Java 8 方法引用的介绍与示例参见:https://www.cnblogs.com/xingzc/p/6002873.html
在 Java 的 .class 字节码文件中,方法引用是通过 invoke-dynamic 指令来实现的,可以通过 javap -c xxx.class 对代码进行反汇编查看到。
但是在 Android 的 .dex/.smali 字节码文件中,由于 ART/Davilk 虚拟机并没有实现类似于 invoke-dynamic 的指令(参见:https://source.android.google.cn/devices/tech/dalvik/dalvik-bytecode ),所以 Android 编译器在把 .class 字节码转换成 .smali 字节码的过程中,会把方法引用的 invoke-dynamic 指令转换成等效匿名内部类代码指令来实现。
下面代码中的等效代码是通过反编译使用了方法引用的 Android APK 的代码来反推得到的。
(在 Android Studio 里写代码,编译出 apk,再通过 apktool 反编译 apk 得到 smali 代码,最后通过 smali 代码反推出 java 代码)
class Car {
public static void say(Car car) {
System.out.println("This is " + car);
}
public void run() {
System.out.println(this + " running");
}
public void follow(Car another) {
System.out.println(this + " following " + another);
}
}
public class SupplierTest {
public static Car create(Supplier<Car> supplier) {
return supplier.get();
}
public static Car testCreate() {
Car ret = create(Car::new); // 构造器引用,语法是Class::new,或者更一般的形式:Class<T>::new。注意:这个构造器没有参数。
ret = create(Lambda$0.$instance); // 等效代码 Equivalent code
return ret;
}
public static void main(String[] args) {
final Car car = testCreate();
final List<Car> cars = Arrays.asList(car);
cars.forEach(Car::say); // 静态方法引用,语法是Class::static_method。注意:这个方法接受一个Car类型的参数。
cars.forEach(Lambda$1.$instance); // 等效代码 Equivalent code
cars.forEach(Car::run); // 成员方法的引用,语法是Class::method。注意,这个方法没有定义入参。
cars.forEach(Lambda$2.$instance); // 等效代码 Equivalent code
final Car police = testCreate();
System.out.println(police + " is a police car");
cars.forEach(police::follow); // 某个实例对象的成员方法的引用,语法是instance::method。注意:这个方法接受一个Car类型的参数。
cars.forEach(Lambda$3.get$Lambda(police)); // 等效代码 Equivalent code
}
// for Car::new
static final class Lambda$0 implements Supplier<Car> {
static final Supplier<Car> $instance = new Lambda$0();
@Override
public Car get() {
return new Car();
}
}
// for Car::say (static method)
static final class Lambda$1 implements Consumer<Car> {
static final Consumer<Car> $instance = new Lambda$1();
@Override
public void accept(Car car) {
Car.say(car);
}
}
// for Car::run (non-static method)
static final class Lambda$2 implements Consumer<Car> {
static final Consumer<Car> $instance = new Lambda$2();
@Override
public void accept(Car car) {
car.run();
}
}
// for police::follow
static final class Lambda$3 implements Consumer<Car> {
private final Car arg$1;
private Lambda$3(Car police) {
arg$1 = police;
}
static Consumer<Car> get$Lambda(Car police) {
return new Lambda$3(police);
}
@Override
public void accept(Car car) {
arg$1.follow(car);
}
}
}