当前位置: 首页 > 面试题库 >

明确使用LambdaMetafactory

年良骏
2023-03-14
问题内容

我试图显式地使用LambdaMetafactory.metafactory,我不明白为什么它只能与Runnable功能接口一起使用。例如,以下代码完成了预期的工作(打印“
hello world”):

public class MetafactoryTest {

    public static void main(String[] args) throws Throwable {

        MethodHandles.Lookup caller = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(void.class);
        MethodType invokedType = MethodType.methodType(Runnable.class);
        CallSite site = LambdaMetafactory.metafactory(caller, 
                                                      "run", 
                                                      invokedType, 
                                                      methodType, 
                                                      caller.findStatic(MetafactoryTest.class, "print", methodType), 
                                                      methodType);
        MethodHandle factory = site.getTarget();
        Runnable r = (Runnable) factory.invoke();
        r.run();
    }

    private static void print() {
        System.out.println("hello world"); 
    }    
}

当我尝试使用其他功能接口(例如供应商)时,就会出现问题。以下代码不起作用:

public class MetafactoryTest {

    public static void main(String[] args) throws Throwable {

        MethodHandles.Lookup caller = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(String.class);
        MethodType invokedType = MethodType.methodType(Supplier.class);
        CallSite site = LambdaMetafactory.metafactory(caller, 
                                                      "get", 
                                                      invokedType, 
                                                      methodType, 
                                                      caller.findStatic(MetafactoryTest.class, "print", methodType), 
                                                      methodType);
        MethodHandle factory = site.getTarget();
        Supplier<String> r = (Supplier<String>) factory.invoke();
        System.out.println(r.get());        
    }
    private static String print() {
        return "hello world";
    }    
}


Exception in thread "main" java.lang.AbstractMethodError: metafactorytest.MetafactoryTest$$Lambda$1/258952499.get()Ljava/lang/Object;
    at metafactorytest.MetafactoryTest.main(MetafactoryTest.java:29)

这两个代码段不应该以相似的方式工作吗,这是第二个代码段中的问题?

此外,以下应等效的代码也可以正常工作:

public class MetafactoryTest {

    public static void main(String[] args) throws Throwable {
        Supplier<String> r = (Supplier<String>) () -> print();
        System.out.println(r.get());        
    }

    private static String print() {
        return "hello world";
    }    
}

编辑

避免更改方法返回类型的另一种解决方案是定义一个新的功能接口:

public class MetafactoryTest {

    @FunctionalInterface
    public interface Test {
        String getString();
    }

    public static void main(String[] args) throws Throwable {

        MethodHandles.Lookup caller = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(String.class);
        MethodType invokedType = MethodType.methodType(Test.class);
        CallSite site = LambdaMetafactory.metafactory(caller, 
                                                      "getString", 
                                                      invokedType, 
                                                      methodType, 
                                                      caller.findStatic(MetafactoryTest.class, "print", methodType), 
                                                      methodType);
        MethodHandle factory = site.getTarget();
        Test r = (Test) factory.invoke();
        System.out.println(r.getString());        
    }

    private static String print() {
        return "hello world";
    }

问题答案:

Runnable和Supplier之间的区别在于Supplier使用通用类型。

在运行时,供应商没有String get()方法,而有Object get()。但是您实现的方法返回一个String。您需要区分这两种类型。像这样:

public class MetafactoryTest {

    public static void main(String[] args) throws Throwable {

        MethodHandles.Lookup caller = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(Object.class);
        MethodType actualMethodType = MethodType.methodType(String.class);
        MethodType invokedType = MethodType.methodType(Supplier.class);
        CallSite site = LambdaMetafactory.metafactory(caller, 
                                                      "get", 
                                                      invokedType, 
                                                      methodType, 
                                                      caller.findStatic(MetafactoryTest.class, "print", actualMethodType), 
                                                      methodType);
        MethodHandle factory = site.getTarget();
        Supplier<String> r = (Supplier<String>) factory.invoke();
        System.out.println(r.get());
    }

    private static String print() {
        return "hello world";
    }    
}


 类似资料:
  • 问题内容: 我有以下代码: 在最后一行,我收到此错误: 下标使用不明确 我该如何解决? 这段代码已经工作了一段时间,但是随着xcode 7.1的升级,它中断了并停止了工作。 问题答案: 您必须告诉编译器该行中的中间对象是什么 语句之后,编译器不知道他正在处理哪种对象。您必须告诉它是或其他: 当然,您还应该确保可以进行所有强制转换,并且json内的对象确实属于预期类型。 通过直接转换为以下数组,仅使

  • 据我所知,当我执行时,Java编译器会在内部用替换表达式。然而,我们的Java老师告诉我们,总是显式地使用是一个很好的实践。。。 我的假设正确吗?我只需要在串联内部循环时显式使用StringBuilder,如堆栈溢出问题的答案“String builder vs String concatenation”中所示?在其他情况下,是否应该明确使用而不是或?

  • 问题内容: 我有一个由sqlite数据库提供的listview。我在几个不同的点调用fillData()来更新listview。 那行得通…问题是,当我打开/关闭/跳转活动时,logcat中出现错误。它不会使程序崩溃。错误是: 请确保您在游标上显式调用close(), 并且 从未在数据库上显式调用close() 因此,在})下;如果我将mDbHelper.close()放进去,则崩溃,提示数据库未

  • 昨天,我从一个分支创建了一个分支,将它推到Origine,并将它合并回Master。您可以在这里看到: 我把不相关的东西包括在这个列表中,这样我就不会意外地删掉一些相关的东西;正如你所看到的,所有这些历史都是连续的。以下是我历史上提到1601年的一切: null 为什么我会得到这个警告,我如何摆脱它,我如何在未来预防它?

  • 我已经看了所有其他模糊的重命名问题,但似乎没有一个有用。为什么我会得到这个警告?

  • 这是一个中等复杂的CTE,它根据JSON参数的内容更新许多表。执行此函数时,Postgres抛出一个错误。错误所指的行实际上有一个表名来限定列引用。 我很确定我是对的,因为如果我删除下面标记的行,错误就会消失。 我一直在想这个问题,但我不知道。 为什么此代码存在?