一、简要描述
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);}
}