lambda是java8的新特性,基本使用比較容易了解,但有一個環節遇到了坎兒,那就是方法引用,尤其是類的執行個體方法引用,燒腦之後總結一下。
在需要函數參數的方法中,我們可以把另一個同類型的方法直接傳入,這稱為方法引用的綁定。類似于C語言中的函數指針。
lambda表達式可以替代方法引用;或者說方法引用是lambda的一種特例,方法引用不可以控制傳遞參數。
需要有無參的構造器。
so easy,隻要靜态方法的參數清單和FI需要的參數一緻就可以。
so easy,隻要成員方法的參數清單和FI需要的參數一緻就可以。
��,前方高能,請關掉耳機的音樂,認真思考,小心行事。
傳統的java開發中,是不允許使用類名去調用成員方法的,這是一個基本原則,那麼這裡的這種寫法就有點不太容易了解了。還是用執行個體說明:
用到的内部類:
測試代碼:
小結一下:
前面的例子,FI的兩個參數是同一個類型,如果類型不同呢?省略了哪個參數呢?
是按照位置省略了第一個,亦或者是省略了最後一個?
還是按照類型自動去對應,而不關心第幾個呢?
這個時候,我們能想到的辦法可能是去看源碼,但是一般看代碼沒有個把禮拜甚至更長,毛都看不出來。我們還是用一個例子來分析一下吧。
定義一個FI接口:
編寫兩個用于參數的類:
TestBean1.java
TestBean2.java
二者差別不大。
編寫測試類:
測試方法中,除了标記OK的行正确,其他都報錯。
分析:
首先我們要明确FI需要的參數清單是:(TestBean1,TestBean2)
我們先看①行,我們傳入的”::”前導的類是TestBean1,而expect1方法比對的是TestBean1類型的入參bean1,也就是說省略了TestBean2類型的參數bean2,FI中的最後一個參數。即便我們使用類TestBean1去new一個對象,也找不到TestBean2,是以這個錯誤。
我們先看②行,我們傳入的”::”前導的類是TestBean1,而expect2方法比對的是TestBean2類型的入參bean2,也就是說省略了TestBean1類型的參數bean1,那麼lambda就可以使用”::”前導的TestBean1建構一個對象,作為第一個參數,進而比對FI的接口方法。ok。
我們先看③行,我們傳入的”::”前導的類是TestBean2,而expect1方法比對的是TestBean1類型的入參bean1,也就是說省略了TestBean2類型的參數bean2,FI的最後一個參數。按照第二步的分析,我們用”::”前導的類TestBean2去new一個對象,應該可以湊足兩個參數。實際測試會發現這不靈。這就證明了隻能省略第一個參數,而且,用”::”前導的類也必須是第一個參數的類型。
同第一步類似,第④行代碼,找不到TestBean1的參數,有錯誤可以了解。
至于⑤~⑧,隻是替換了外層的test1的主體,沒有任何差別。這證明了,lambda的比對與外層是什麼鬼沒有任何關系,它隻關心外層需要的FI的參數清單。
請不要看下一步,在這裡停下來冷靜的思考一下,如果我們把TestInterface中FI方法的參數位置換一下,即<code>public void anyStringAsName(TestBean2 cat,TestBean1 dog);</code>,結果應該是哪兩行正确呢?認真思考一下,實在想不明白跑一下測試用例,也許對了解更有幫助。
如果想明白了用這個思路驗證一下:參照參數清單<code>(TestBean2,TestBean1)</code>,可以确定隻可以省略第一個參數即TestBean2,那麼”::”簽到必須是TestBean2,用于自動建立對象;而未省略的參數是TestBean1,那麼方法名為expect1,結果為<code>xxx(TestBean2::expect1)</code>,即③和⑦,你答對了嗎?