一、简要描述
Lambda的方法引用也叫引用方法
- 方法引用初体验
- 方法引用的底层实现
- 方法引用的语法格式
- 方法引用举例
- 静态方法引用
- 构造方法引用
- 普通方法引用
- super和this方法引用
- 数组的方法引用
二、方法引用初体验
为什么出现方法引用?
- 引用已存在方法,避免重复逻辑
- 代码更加简洁
Lambda函数体以存在,是否还有存在的必要? 答案是:没有存在的必要,直接方法引用调用。
三、方法引用的底层实现
1、使用cfr工具包解码Lambda字节码
使用java命令,cfr工具解析字节码
java -jar cfr-0.145.jar MethodReferenceFirstGo.class --decodelambdas false
2、使用Java命令打开dumps调试模式
Java命令:
java -Djdk.internal.lambda.dumpProxyClasses ClassName
打开调试模式
2.1、生成Lambda编译的class文件
生成后编译后的文件:
- MethodReferenceFirstGo$$Lambda$1.class
- MethodReferenceFirstGo$$Lambda$2.class
2.2、两个文件进行对比
四、方法引用语法格式
- 方法引用运算符
双冒号 ::
- 那些方法可以引用?
- 类方法 / 构造方法 / 实例方法
- 被引用方法与函数式接口抽象方法:
- 参数列表相同
- 返回值类型相同
- 方法引用语法格式
格式:类名 :: 静态方法
范例:Integer :: parseIn
格式:类名 :: new
范例:Student :: new
格式:对象 :: 成员方法
范例:hello :: toUpperCase
格式:this :: 方法名 / super :: 方法名
五、方法引用示例
1、静态方法引用
1.1、定义Calcable接口类
package tech.flygo.lambda.demo6;
/**
* @description: 计算数值接口
* @author: flygo
* @time: 2023/8/12 11:16
*/
@FunctionalInterface
public interface Calcable {
/**
* description: 定义一个抽象方法,传递一个整数,对整数进行绝对值计算并返回 <br>
* date: 2023/8/12 11:17 <br>
* author: flygo <br>
*
* @return int
* @param: number
*/
int calcAbs(int number);
}
1.2、定义StaticMethodReference主函数测试类
package tech.flygo.lambda.demo6;
/**
* @description: 通过类名引用静态成员方法 <br>
* 类已经存在,静态成员方法也已经存在 <br>
* 就可以通过类名直接引用静态成员方法 <br>
* @author: flygo
* @time: 2023/8/12 11:18
*/
public class StaticMethodReference {
/**
* description: 定义一个方法,方法的参数传递要计算绝对值的整数,和函数式接口Calcable <br>
* date: 2023/8/12 11:19 <br>
* author: flygo <br>
*
* @return int
* @param: number
* @param: c
*/
public static int method(int number, Calcable c) {
return c.calcAbs(number);
}
public static void main(String[] args) {
// 调用method方法,传递计算绝对值的整数和Lambda表达式
int number = method(-10, (n) -> {
// 对参数进行绝对值计算并返回结果
return Math.abs(n);
});
System.out.println(number);
// 使用方法引用优化Lambda表达式
/**
* Math类是存在的
* abs计算绝对值的静态方法也是存在的
* 所有我们可以直接通过类名引用静态方法
*/
int result = method(-20, Math::abs);
System.out.println(result);
}
}
1.3、代码示例
2、构造方法引用
2.1、定义Person类
package tech.flygo.lambda.demo7;
/**
* @description: 人类
* @author: flygo
* @time: 2023/8/12 11:45
*/
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.2、定义一个创建Person对象的函数式接口
package tech.flygo.lambda.demo7;
/**
* @description: 定义一个创建Person对象的函数式接口
* @author: flygo
* @time: 2023/8/12 11:47
*/
@FunctionalInterface
public interface PersonBuilder {
/**
* description: 定义一个方法,根据传递的姓名,创建Person对象返回 <br>
* date: 2023/8/12 11:48 <br>
* author: flygo <br>
*
* @return tech.flygo.lambda.demo7.Person
* @param: name
*/
Person buildPerson(String name);
}
2.3、定义ConstructorMethodReference主函数测试类
package tech.flygo.lambda.demo7;
/**
* @description: 类的构造器(构造方法)引用
* @author: flygo
* @time: 2023/8/12 11:49
*/
public class ConstructorMethodReference {
/**
* description: 定义一个方法,参数传递姓名和PersonBuilder接口,方法中通过姓名创建Person对象 <br>
* date: 2023/8/12 11:50 <br>
* author: flygo <br>
*
* @return void
* @param: name
* @param: builder
*/
public static void printName(String name, PersonBuilder builder) {
Person person = builder.buildPerson(name);
System.out.println(person.getName());
}
public static void main(String[] args) {
// 调用printName方法,方法的参数PersonBuilder接口是一个函数式接口,可以传递Lambda表达式
printName("刘德华", name -> new Person(name));
// 使用方法引用优化Lambda表达式
/**
构造方法 new Person(String name)已知
创建对象已知 new
就可以使用Person引用new创建对象
*/
// 使用Person类带参数的构造方法,通过传递的姓名创建对象
printName("周欣欣", Person::new);
}
}
2.4、代码示例和运行结果
3、普通方法引用
3.1、定义一个打印的函数式接口Printable
package tech.flygo.lambda.demo8;
/**
* @description: 定义一个打印的函数式接口
* @author: flygo
* @time: 2023/8/12 12:14
*/
@FunctionalInterface
public interface Printable {
/**
* description: 定义打印字符串的抽象方法 <br>
* date: 2023/8/12 12:15 <br>
* author: flygo <br>
*
* @return void
* @param: s
*/
void print(String s);
}
3.2、打印字符串的对象类MethodRerObject
package tech.flygo.lambda.demo8;
/**
* @description: 打印字符串的对象类
* @author: flygo
* @time: 2023/8/12 12:15
*/
public class MethodRerObject {
/**
* description: 定义一个成员方法,传递字符串,把字符串转换成大写输出 <br>
* date: 2023/8/12 12:16 <br>
* author: flygo <br>
*
* @return void
* @param: str
*/
public void printUpperCaseString(String str) {
System.out.println(str.toUpperCase());
}
}
3.3、通过对象名引用成员方法测试类
package tech.flygo.lambda.demo8;
/**
* @description: 通过对象名引用成员方法
* 使用前提是对象名是已经存在的,成员方法也是已经存在的
* 就可以使用对象名来引用成员方法
* @author: flygo
* @time: 2023/8/12 12:17
*/
public class ObjectMethodReference {
/**
* description: 定义一个方法,方法的参数传递Printable接口 <br>
* date: 2023/8/12 12:20 <br>
* author: flygo <br>
*
* @return void
* @param: printable
*/
public static void printString(Printable printable) {
printable.print("Hello");
}
public static void main(String[] args) {
// 调用printString方法,方法的参数Printable是一个函数式接口,所以可以传递Lambda表达式
printString(s -> {
// 创建MethodRerObject对象
MethodRerObject object = new MethodRerObject();
// 调用MethodRerObject对象中的成员方法printUpperCaseString,把字符串按照大写输出
object.printUpperCaseString(s);
});
// 创建MethodObject对象
MethodRerObject object = new MethodRerObject();
/*
使用方法引用优化Lambda
对象是已经存在的MethodRerObject
成员方法是已经存在的printUpperCaseString
所以可以使用对象名引用尘缘方法
*/
printString(object::printUpperCaseString);
}
}