函数式接口的实现既可以使用Lambda表达式也可以使用方法引用的方式,那么它们之间有何区别呢?
也就是说: 函数式接口的实例既可以是Lambda表达式也可以是方法引用
//方式1: Lambda
Function<String, String> lambda = (a) -> a.toUpperCase();
//方式2: 方法引用
Function<String, String> lambda = String::toUpperCase;
废话少说,咱来通过实验一步一步来解开其中的奥秘!
测试源代码TestClassInstanceMethodRefrence:
package wjw.test.java8.invokedynamic;
import java.util.Arrays;
public class TestClassInstanceMethodRefrence {
static {
//加上这个参数后,运行时会将生成的函数式接口代理类的class代码码输出到一个文件中
System.setProperty("jdk.internal.lambda.dumpProxyClasses", "./lambda_dumpProxyClasses");
}
public static void main(String[] args) {
(new TestClassInstanceMethodRefrence()).testA();
(new TestClassInstanceMethodRefrence()).testB();
}
public TestClassInstanceMethodRefrence() {
}
public void testA() {
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, (T1, T2) -> T1.compareToIgnoreCase(T2));
}
public void testB() {
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
}
}
Arrays.sort()方法里需要一个函数式接口参数Comparator, 方法testA是使用Lambda表达式方式,方法testB是使用方法引用方式.
来看看编译后的代码:
测试类: TestClassInstanceMethodRefrence
package wjw.test.java8.invokedynamic;
import java.util.*;
public class TestClassInstanceMethodRefrence
{
static {
System.setProperty("jdk.internal.lambda.dumpProxyClasses", "./lambda_dumpProxyClasses");
}
public static void main(final String[] args) {
new TestClassInstanceMethodRefrence().testA();
new TestClassInstanceMethodRefrence().testB();
}
public TestClassInstanceMethodRefrence() {
super();
}
public void testA() {
final String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, (T1, T2) -> T1.compareToIgnoreCase(T2));
}
public void testB() {
final String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
}
private static /* synthetic */ int lambda$0(final String T1, final String T2) {
return T1.compareToIgnoreCase(T2);
}
}
可以看到里面多出来一个
lambda$0方法,这个方法就是编译器自动添加的让lambda表达式来调用
lambda方式对应的源码: TestClassInstanceMethodRefrence$$Lambda$1.class
package wjw.test.java8.invokedynamic;
import java.util.*;
import java.lang.invoke.*;
final synthetic class TestClassInstanceMethodRefrence$$Lambda$1 implements Comparator
{
private TestClassInstanceMethodRefrence$$Lambda$1() {
super();
}
@LambdaForm.Hidden
@Override
public int compare(final Object o, final Object o2) {
return TestClassInstanceMethodRefrence.lambda$0((String)o, (String)o2);
}
}
含有Lambda的类在程序运行的时的流程:
- 在含有Lambda的类中新增一个
private static的方法,这个方法的方法体就是Lambda表达式中的代码- 还会生成一个匿名内部类,实现Lambda表达式代表的函数式接口,重写抽象方法
- 在重写方法中会调用含有Lambda的类中新生成的
private static的那个方法.
方法引用方式对应的源码: TestClassInstanceMethodRefrence$$Lambda$2.class
package wjw.test.java8.invokedynamic;
import java.util.*;
import java.lang.invoke.*;
final synthetic class TestClassInstanceMethodRefrence$$Lambda$2 implements Comparator
{
private TestClassInstanceMethodRefrence$$Lambda$2() {
super();
}
@LambdaForm.Hidden
@Override
public int compare(final Object o, final Object o2) {
return ((String)o).compareToIgnoreCase((String)o2);
}
}
含有方法引用的类在程序运行的时的流程:
- 生成一个匿名内部类,实现方法引用代表的函数式接口,重写抽象方法
- 在重写方法中会调用方法引用指向的的那个方法.
可以看出方法引用实际上是Lambda表达式的更简洁高效的写法.不会像Lambda表达式那让在包含Lambda表达式的类里生成一个静态私有方法.

<<<<<< [完] >>>>>>