Đối số thứ ba với phương pháp bootstrap, mà bạn tên lambdaType
, là gọi loại của liên invokedynamic
lệnh (thường được điền bởi JVM). Đó là ngữ nghĩa được định nghĩa bởi phương thức bootstrap và trong trường hợp của LambdaMetaFactory
, nó chỉ định giao diện chức năng như kiểu trả về (kiểu đối tượng để xây dựng) và các giá trị để nắm bắt như kiểu tham số (kiểu giá trị cần dùng khi xây dựng một cá thể lambda).
Vì vậy, để nắm bắt this
, bạn phải thêm các loại this
để loại gọi của bạn và vượt qua this
như một cuộc tranh cãi với invokeExact
gọi:
public class Test {
public static void main(String... arg) throws Throwable {
System.out.println(new Test().foo().getAsInt());
}
public IntSupplier foo() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(int.class),
invokedType = MethodType.methodType(IntSupplier.class, Test.class);
MethodHandle methodHandle = lookup.findVirtual(getClass(), "fortyTwo", methodType);
CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt",
invokedType, methodType, methodHandle, methodType);
return (IntSupplier) callSite.getTarget().invokeExact(this);
}
public int fortyTwo() {
return 42;
}
}
Nếu bạn muốn chụp nhiều giá trị, bạn phải thêm chúng vào chữ ký theo đúng thứ tự. Ví dụ: để chụp khác int
giá trị:
public class Test {
public static void main(String... arg) throws Throwable {
System.out.println(new Test().foo(100).getAsInt());
}
public IntSupplier foo(int capture) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(int.class, int.class),
functionType = MethodType.methodType(int.class),
invokedType = MethodType.methodType(IntSupplier.class, Test.class, int.class);
MethodHandle methodHandle=lookup.findVirtual(getClass(),"addFortyTwo",methodType);
CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt",
invokedType, functionType, methodHandle, functionType);
return (IntSupplier) callSite.getTarget().invokeExact(this, capture);
}
public int addFortyTwo(int valueToAdd) {
return 42+valueToAdd;
}
}
Phương pháp mục tiêu sẽ có một chữ ký bao gồm các loại this
, nếu không muốn nói static
, tiếp theo là tất cả các loại tham số. Giá trị chụp sẽ ánh xạ theo loại chữ ký này từ trái sang phải và các loại thông số còn lại, nếu có, đóng góp vào chữ ký chức năng, do đó phải khớp với các loại tham số của phương thức interface
.
Điều này ngụ ý rằng khi không có giá trị bị bắt và phương pháp đích không phải là static
, loại bộ tiếp nhận phương thức có thể trở thành kết hợp với loại chữ ký đầu tiên, như trong ToIntFunction<String> f=String::length;
.
Tôi sẽ giả định điều này là nhằm mục đích tìm hiểu cách lambdas làm việc nội bộ, bởi vì nếu không bạn sẽ 'trả về IntSupplier mới() {...};' không có phép thuật. – immibis
Điều tôi không hiểu, là nhận xét “Sẽ không bình thường ảo”. – Holger