Java中的構造函數引用和方法引用

方法引用的一些背景

若是你還不知道 Java 構造函數自己就是特殊的方法,那麼閱讀方法引用的基本示例將對讀者有所幫助,經過了解這些內容,能夠了解構造函數引用是什麼。java

方法引用能夠引用靜態方法和實例方法,二者是通用的。方法引用是函數式接口的實例。雖然 Lambda 表達式容許你動態建立方法實現,但一般狀況下,一個方法最終會調用 Lambda 表達式中的另外一個方法來完成咱們想要完成的工做。更直接的方法是使用方法引用。當你已經有一個方法來實現這個函數式接口時,這是很是有用的。編程

歡迎學Java和大數據的朋友們加入java架構交流: 855835163
羣內提供免費的架構資料還有:Java工程化、高性能及分佈式、高性能、深刻淺出。高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點高級進階乾貨的免費直播講解  能夠進來一塊兒學習交流哦架構

讓咱們看一個使用靜態方法及實例方法的示例。app

1分佈式

2函數

3源碼分析

4性能

5學習

6測試

7

8

9

10

11

12

13

14

15

16

//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();

    }

}

譯註:以上代碼的測試用例以下,因靜態方法與實例方法結果相同,僅以靜態方法爲例。

1

2

3

4

5

6

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);

獲得與原文舉例相同的輸出結果:

1

2

3

4

5

6

"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 編程帶來了一個功能方面的提高。

構造函數的方法引用

讓咱們開始詳細討論吧。

構造函數和其餘方法同樣是方法。對嗎?錯。它們有點特殊,它們是對象初始化方法。儘管如此,它們仍然是一個方法,沒有什麼能阻止咱們像其餘方法引用同樣建立構造函數的方法引用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

//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();

    }

}

輸出結果

1

2

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…)

構造函數引用與泛型一塊兒使用的時候變得更有用。經過使用泛型工廠方法,能夠建立各類類型的對象。

讓咱們看一看。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

//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();

    }

}

輸出結果

1

2

This Automobile is a 2006 Honda Accord.

This Plane is a 172 Cessna Skyhawk.

說明

這裏有不少東西須要消化。事實上,若是你之前從未深刻研究過泛型,那麼這些代碼看上去可能至關晦澀。讓咱們分解一下。

咱們作的第一件事是建立一個通用的函數式接口。注意細節。咱們有四個泛型類型參數:Ob、X、Y、Z。

  • Ob 表明要引用其構造函數的類。
  • X,Y,Z 表明該類的構造函數的參數。

若是咱們替換泛型方法佔位符,抽象方法多是這樣的: SomeClass func (String make, String model, int year)。注意,因爲咱們使接口具備了泛型,因此能夠指定任何返回類型或咱們但願返回的類實例。這釋放了構造函數引用的真正潛力。

接下來的兩個部分相對簡單,咱們建立了相同的類,一個泛型類和一個非泛型類,以演示它們與在公共類中定義的工廠方法的互操做性。注意,這些類的構造函數與 FuncInt.func() 的方法簽名是兼容的。

進入公共類的文件。這個方法就是奇蹟發生的地方。

1

2

3

4

//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的一個很是有用的補充 ;)

歡迎學Java和大數據的朋友們加入java架構交流: 855835163 羣內提供免費的架構資料還有:Java工程化、高性能及分佈式、高性能、深刻淺出。高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點高級進階乾貨的免費直播講解  能夠進來一塊兒學習交流哦

相關文章
相關標籤/搜索