还是本着先学习的态度看看这个特性长什么样。然后看看到底代表了什么。一般用在什么地方。
第一种 static方法的引用
就是你如果有个类有个静态方法。你可以直接写
ContainingClass::staticMethodName
但是我有个疑问。这么写了之后。这个整体表示的是啥。如果照以前ContainingClass.staticMethodName也是可以调用啊。其实这就引出了一个问题。方法引用的目的是啥。现在看起来好像主要是当成方法调用的一个参数。至少我现在看到的基本是作为参数在使用。那既然能当成是参数。这说明代表是一个实例。既然是实例。就肯定背后是个类。但是能这么多层隐身表达的。只有我们提到的函数式接口才有这个能力。 也就是这么写。虽然是一个方法。但是背后一定有一个函数式接口来对应。我们来看例子
例子一。静态方法是没有参数的。没有返回值。
其实这种代表的函数接口比较好找到。 runnable就是
例子2,静态方法没有参数,但是有返回值。也好找Callable
例子3,静态方法有一个入参,没有返回值。能想到的就是Consumer。这里有几个分支。就是静态方法的参数是具体类型。还是泛型。跟调用方法的Consumer是否指定类型。看例子。
这里的test3 跟 test33 一个是指定了具体类型。一个是用的泛型。那对应得方法引用的例子就有三种。可以指定Consumer类型。比如IntConsumer。也可以直接用Consumer。但是对应的能调用的静态方法的写法是不同的。这里就不一一举例了。反正用不对。编译器会提示你如何修改。
看完这三个例子。基本对方法引用是用来干什么的有个初步印象了。说白了就是不同类之间方法调用方法。因为有了函数式接口。函数本身可以作为参数传递。弄双冒号可以省略写很多参数。在某些代码的语义上重点突出了函数含义本身。因为有时候不是太关心参数。
第二种 ClassName::new
这种就是类名 直接加双冒号new 。那这个整体代表的也应该是一个实例。是ClassName的实例么。应该不是。应该还是跟之前的那种。背后一定是某个函数式接口的实例。到底是哪个函数式接口呢.可以是任何构造器方法的函数式接口。看例子
FunctionRefenceTest这个类是默认构造器的。所以test55的入参用Sumpplier就符合了 。如果FunctionRefenceTest的构造器是一个带参数的呢。也就是有入参。有返回结果的那种。我想到的是Function。一个入参。一个返回结果。看代码
同样是FunctionRefenceTest::new 看出背后的含义是不一样的。
第三种 containingObject::instanceMethodName
这种双冒号前面是一个类的实例。后面的方法名是这个类的普通方法。通过列举过程我们还发现了。这些方法都把参数给省略了。真神奇。
这个形式跟第一种的静态类行很像。区别就是如果传入的方法是非静态的。非static。那如果还想用怎么办。双冒号的左边就不能用类的名字了。必须是一个类的实例。
这个例子举的不好。都是同一个类。正常来说调用的类A跟 入参方法的所在的类B 通常是不一样的。这里举例是为了证明语法ok
方便。
最后一种 最复杂的一种 ContainingType::methodName
这个双冒号前面是类名A。后面是普通方法B。这种复杂了。但是根据经验整体代表的依然是某个函数式接口的实例。当然这个函数式接口的方法第一个参数一定是这个类名A或者A的子类。然后其他的参数一定跟这个普通方法B一模一样。但是关键还是在于函数式接口。还是看例子
这里就没用具体的函数调用来说明了。只是用了一个MyInter m定义。这里很明显左边还是类名Test1。右边是普通的方法a。这是没有参数也没有返回值的情况。注意看函数式接口的里头的第一个参数。恰巧是入参类Test1.也就是说要要能写成普通类名双冒号普通方法这种简单写法。这个函数式接口的的第一个参数必须是被调用方法类或者他的子类。
再看个有参数的
还是符合刚才的假定。所以一切的一切都是在于函数式接口如何定义。