1.概念 ---- 什么是方法引用???
对于每一个java类来说,它们都主要有三种方法,即普通方法、静态方法和构造方法。而方法引用就是利用函数式接口+lambda表达式(这里的lambda表达式并非前面提到的带"->“符号的表达式,而是使用双冒号”::"的一种lambda表达式)的方式对类中的方法进行引用,之所以称为“引用”,是因为这种方式不像以往我们对类中的方法进行操作时,就是直接调用该方法,或者说执行该方法,这中方式会根据指定的函数式接口创建一个该接口的一个实例,方法的真正执行需要通过该实例去触发执行。
2. 代码说话
看完概念部分的介绍,可能很多人还是会有云里雾里的感觉,下面用几个小栗子来具体的说一下:
2.1 入门----静态方法的方法引用
package com.nrsc.lambda.MethodReference;
import java.util.function.Consumer;
//Cat类
class Cat {
private String name = "加菲猫";
/**
* 静态方法
*/
public static void eat(Cat cat) {
System.out.println(cat + "喜欢吃鱼");
}
@Override
public String toString() {
return this.name;
}
}
public class Demo {
public static void main(String[] args) {
//静态方法的方法引用
/**
* 通过分析可以得知静态方法eat需要输入的参数为Cat实例,无返回结果,
* 那么它与JDK所提供的函数式接口Consumer<T>所需要的输入和输出是一致的,
* 因此该静态方法可以使用函数式接口Consumer<T> + 双冒号lambda表达式 的方式进行引用
* 引用方式如下:
*/
Cat cat = new Cat();
Consumer<Cat> eatMethod = Cat::eat;//静态方法的双冒号表达式是类名::方法名
eatMethod.accept(cat);
}
}
从上面的入门栗子里可以看出,其实方法引用很简单,只需要分析清楚方法的输入参数类型和参数格式,以及返回结果类型,然后由此选择合适的函数式接口,再配合双冒号("::")lambda表达式,就可以完成方法引用了。
2.2 静态方法+非静态方法+构造函数的方法引用示例:
方法引用其实并不难,这里弄了一段代码,对各种方法引用都进行了一下测试:
package lambda;
import java.util.function.*;
//Dog类
class Dog {
private String name = "哮天犬";
/**
* 默认10斤狗粮
*/
private int food = 10;
public Dog() {
}
/**
* 带参数的构造函数
*
* @param name
*/
public Dog(String name) {
this.name = name;
}
/**
* 狗叫,静态方法
*
* @param dog
*/
public static void bark(Dog dog) {
System.out.println(dog + "叫了");
}
/**
* 吃狗粮 JDK
*
* 默认会把当前实例传入到非静态方法,参数名为this,位置是第一个;
*
* @param num
* @return 还剩下多少斤
*/
public int eat(int num) {
System.out.println("吃了" + num + "斤狗粮");
this.food -= num;
return this.food;
}
// 和上面的eat方法效果一模一樣
// public int eat(Dog this, int num) {
// System.out.println("吃了" + num + "斤狗粮");
// this.food -= num;
// return this.food;
// }
@Override
public String toString() {
return this.name;
}
}
public class MethodRefrenceDemo {
public static void main(String[] args) {
Dog dog = new Dog();
// 静态方法的方法引用
Consumer<Dog> consumer2 = Dog::bark;
consumer2.accept(dog); // 哮天犬叫了
System.out.println("===================================");
// 非静态方法,使用对象实例的方法引用
// Function<Integer, Integer> function = dog::eat;
// 由于方法的输入参数类型和输出参数类型相同,所以可以使用一元函数接口
// UnaryOperator<Integer> function = dog::eat;
// 当然也可以使用带类型的一元函数接口
IntUnaryOperator function = dog::eat;
System.out.println("剩下" + function.applyAsInt(2) + "斤"); // 吃了2斤狗粮 剩下8斤
System.out.println("++++++++++++++++++++++++++++++++++++");
/**
* 大家应该知道,在非静态方法里,可以使用this关键字, 它的原理其实就是在形参里默认将当前对象传给了方法,参数名就是this
*
* 因此非静态方法eat还可以看成是一个有两个输入一个输出的函数BiFunction<T ,U ,R> 此时可以使用(类名::方法名)的方式进行方法引用
* 栗子如下:
*/
BiFunction<Dog, Integer, Integer> eatFunction = Dog::eat;
System.out.println("还剩下" + eatFunction.apply(dog, 2) + "斤");
System.out.println("******************************************");
// 构造函数的方法引用
Supplier<Dog> supplier = Dog::new;
System.out.println("创建了新对象:" + supplier.get());
// 带参数的构造函数的方法引用
Function<String, Dog> function2 = Dog::new;
System.out.println("创建了新对象:" + function2.apply("旺财"));
}
}