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源码分析和大数据等多个知识点高级进阶干货的免费直播讲解  能够进来一块儿学习交流哦

相关文章
相关标签/搜索