您好,登錄后才能下訂單哦!
JDK 8 見證了一個特殊特性的出現:構造函數引用和方法引用。在本文中, Adrian D. Finlay 探討了開發人員如何釋放構造函數引用的真正潛力。
方法引用的一些背景
如果你還不知道 Java 構造函數本身就是特殊的方法,那么閱讀方法引用的基本示例將對讀者有所幫助,通過了解這些內容,可以了解構造函數引用是什么。
「方法引用為已經有名稱的方法提供易讀的 lambda 表達式。」
「它們提供了一種無需執行就可以引用方法的簡單方式。」
以上引自《Java 8 編程參考官方教程(第 9 版)》,作者:Herbert Schildt
方法引用可以引用靜態方法和實例方法,兩者是通用的。方法引用是函數式接口的實例。雖然 Lambda 表達式允許你動態創建方法實現,但通常情況下,一個方法最終會調用 Lambda 表達式中的另一個方法來完成我們想要完成的工作。更直接的方法是使用方法引用。當你已經有一個方法來實現這個函數式接口時,這是非常有用的。
讓我們看一個使用靜態方法及實例方法的示例。
//step #1 - Create a funnctional interface. interface FuncInt { //contains one and only abstract method String answer(String x, boolean y); } //step #2 - Class providing method(s)that match FuncInt.answer()'s definition. class Answer { static String ans_math_static(String x, Boolean y) { return "\"" + x + "\"" + "\t = \t" + y.toString().toUpperCase(); } String ans_math_inst(String x, Boolean y) { return "\"" + x + "\"" + "\t = \t" + y.toString().toUpperCase(); } }
譯注:以上代碼的測試用例如下,因靜態方法與實例方法結果相同,僅以靜態方法為例。
Answer.ans_math_static("9 > 11 ?", false); Answer.ans_math_static("987.6 < 1.1 ?", false); Answer.ans_math_static("1 > 0.9 ?", true); Answer.ans_math_static("T/F: Is Chengdu in Sichuan?", true); Answer.ans_math_static("-1 % 0.2=0 ?", false); Answer.ans_math_static("T/F: Does Dwyne Wade play for the Knicks?", false);
得到與原文舉例相同的輸出結果:
"9 > 11 ?" = FALSE "987.6 < 1.1 ?" = FALSE "1 > 0.9 ?" = TRUE "T/F: Is Chengdu in Sichuan?" = TRUE "-1 % 0.2=0 ?" = FALSE "T/F: Does Dwyne Wade play for the Knicks?" = FALSE
使用方法引用的主要步驟有:
1.定義一個函數式接口
2.定義一個滿足函數式接口抽象方法要求的方法
3.使用對步驟2中定義的 (x :: y ) 方法引用實例化函數式接口的實例。
譯注:靜態方法的方法引用格式為 類名 :: 方法名 ;實例方法的方法引用格式為 對象實例名 :: 方法名 。
4.使用函數式接口實例調用方法: Instance.AbstractMethod();
這提供了一種創建方法實現的可插拔方式。Lambda 表達式和方法引用為 Java 編程帶來了一個功能方面的提升。
構造函數的方法引用
讓我們開始詳細討論吧。
構造函數和其他方法一樣是方法。對嗎?錯。它們有點特殊,它們是對象初始化方法。盡管如此,它們仍然是一個方法,沒有什么能阻止我們像其他方法引用一樣創建構造函數的方法引用。
//step #1 - Create a funnctional interface. interface FuncInt { //contains one and only abstract method Automobile auto(String make, String model, short year); } //step #2 - Class providing method(s)that match FuncInt.answer()'s definition. class Automobile { //Trunk Member Variables private String make; private String model; private short year; //Automobile Constructor public Automobile(String make, String model, short year) { this.make = make; this.model = model; this.year = year; } protected void what() { System.out.println("This Automobile is a" + year + " " + make + " " + model + "."); } } //Step #3 - Class making use of method reference public class ConstrRef { static void createInstance() { } public static void main(String[] args) { System.out.println(); //Remember, a Method Reference is an instance of a Functional Interface. Therefore.... FuncInt auto = Automobile::new;//We really don't gain much from this example //Example #1 Automobile honda = auto.auto("honda", "Accord", (short) 2006); honda.what(); //Example #1 Automobile bmw = auto.auto("BMW", "530i", (short) 2006); bmw.what(); System.out.println(); } }
輸出結果
This Automobile is a2006 honda Accord. This Automobile is a2006 BMW 530i.
說明
用戶應該清楚的第一件事是這個基本示例沒有那么實用。這是一種相當迂回的創建對象實例的方式。實際上,幾乎可以肯定,你不會經歷所有這些麻煩來創建一個 Automobile 實例,但是為了概念的完整性,還是要提及。
使用構造函數的方法引用的主要步驟有:
1.定義一個只有抽象方法的函數式接口,該方法的返回類型與你打算使用該對象進行構造函數引用的對象相同。
2.創建一個類,該類的構造函數與函數式接口的抽象方法匹配。
3.使用對步驟 #2 中定義的構造函數的方法引用,實例化函數式接口的實例。
譯注:構造函數的方法引用格式為 類名 :: new
4.在步驟 #2 中使用構造函數引用實例化類的實例,例如 MyClass x = ConstructorReference.AbstractMethod (x, y, z…)
構造函數引用與泛型一起使用的時候變得更有用。通過使用泛型工廠方法,可以創建各種類型的對象。
讓我們看一看。
//step #1 - Create a funnctional interface. interface FuncInt<Ob, X, Y, Z> { //contains one and only abstract method Ob func(X make, Y model, Z year); } //step #2 - Create a Generic class providing a constructor compatible with FunInt.func()'s definition class Automobile<X, Y, Z> { //Automobile Member Variables private X make; private Y model; private Z year; //Automobile Constructor public Automobile(X make, Y model, Z year) { this.make = make; this.model = model; this.year = year; } protected void what() { System.out.println("This Automobile is a " + year + " " + make + " " + model + "."); } } //step #3 - Create a Non-Generic class providing a constructor compatible with FunInt.func()'s definition class Plane { //Automobile Member Variables private String make; private String model; private int year; //Plane Constructor public Plane(String make, String model, int year) { this.make = make; this.model = model; this.year = year;//Automatic unboxing } protected void what() { System.out.println("This Plane is a " + year + " " + make + " " + model + "."); } } //Step #3 - Class making use of method reference with generics public class ConstrRefGen { //Here is where the magic happens static <Ob, X, Y, Z> Ob factory(FuncInt<Ob, X, Y, Z> obj, X p1, Y p2, Z p3) { return obj.func(p1, p2, p3); } public static void main(String[] args) { System.out.println(); //Example #1 FuncInt<Automobile<String, String, Integer>, String, String, Integer> auto_cons = Automobile<String, String, Integer>::new; Automobile<String, String, Integer> honda = factory(auto_cons, "Honda", "Accord", 2006); honda.what(); //Example #2 FuncInt<Plane, String, String, Integer> plane_cons = Plane::new; Plane cessna = factory(plane_cons, "Cessna", "Skyhawk", 172); cessna.what(); System.out.println(); } }
輸出結果
This Automobile is a 2006 Honda Accord. This Plane is a 172 Cessna Skyhawk.
說明
這里有很多東西需要消化。事實上,如果你以前從未深入研究過泛型,那么這些代碼看上去可能相當晦澀。讓我們分解一下。
我們做的第一件事是創建一個通用的函數式接口。注意細節。我們有四個泛型類型參數:Ob、X、Y、Z。
如果我們替換泛型方法占位符,抽象方法可能是這樣的: SomeClass func (String make, String model, int year)。注意,由于我們使接口具有了泛型,所以可以指定任何返回類型或我們希望返回的類實例。這釋放了構造函數引用的真正潛力。
接下來的兩個部分相對簡單,我們創建了相同的類,一個泛型類和一個非泛型類,以演示它們與在公共類中定義的工廠方法的互操作性。注意,這些類的構造函數與 FuncInt.func() 的方法簽名是兼容的。
進入公共類的文件。這個方法就是奇跡發生的地方。
//Here is where the magic happens static <Ob, X, Y, Z> Ob factory(FuncInt<Ob, X, Y, Z> obj, X p1, Y p2, Z p3) { return obj.func(p1, p2, p3); }
我們將該方法標記為靜態的,所以我們可以不使用 ConstRefGen 實例,畢竟它是一個工廠方法。注意,factory 方法具有與函數式接口相同的泛型類型參數。注意,方法的返回類型是 Ob,它可以是由我們決定的任何類。當然,X、Y、Z是 Ob 中方法的方法參數。請注意,該函數以 FuncInt 的一個實例作為參數(類類型和方法參數作為類型參數),同時也接受 Ob 類型的類作為方法的參數。
在方法體中,它調用方法引用并將在 factory() 中傳遞的參數提供給它。
我們的第一個任務是創建一個符合 FuncInt<> 的方法引用。
這里我們分別引用 Automobile 類和 Plane 類的構造函數。
我們的下一個任務是創建一個帶有方法引用的對象。
為此,我們調用 factory() 并將它需要的構造函數引用以及 factory() 定義的有關構造函數的參數提供給它。factory() 可以靈活地創建對各種方法的構造函數引用,因為它是通用的。因為 Plane 類和 Automobile 類的構造函數匹配 FuncInt.func() 的方法簽名,所以它們可作為 FuncInt.func() 的方法引用使用。factory() 通過調用 obj.func(x,y,z) 返回類的一個實例,這是一個構造函數方法引用,當求值時,它將為你提供指定為其參數的類的一個實例。
斟酌這個問題一段時間,會發現它是Java的一個非常有用的補充 ;)
英文鏈接: jaxenter
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。