rec*_*rec 9 java lambda classloader java-8
我想在Java 8中创建一个lambda函数,获取它的类名,然后再从它的类名实例化该函数.
这是我尝试的:
import java.util.function.Consumer;
public class SimpleLambda
{
public static void call(String aLambdaClassName, String aArg) throws Exception
{
Class<Consumer<String>> lClass = (Class<Consumer<String>>) Class.forName(aLambdaClassName);
Consumer<String> newlamba = lClass.newInstance();
newlamba.accept(aArg);
}
public static void main(String[] args) throws Exception
{
{
// Attempt with a static method as lambda
Consumer<String> lambda = Host::action;
String classname = lambda.getClass().getName();
call(classname, "Hello world");
}
{
// Attempt with a locally defined lambda
Consumer<String> lambda = (s) -> { System.out.println(s); };
String classname = lambda.getClass().getName();
call(classname, "Hello world");
}
}
}
class Host {
public static void action(String aMessage) {
System.out.println(aMessage);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,使用此代码(在两种变体中,使用静态方法引用并使用本地声明的lambda),我得到一个异常:
Exception in thread "main" java.lang.ClassNotFoundException: mypackage.SimpleLambda$$Lambda$1/471910020
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at mypackage.SimpleLambda.main(SimpleLambda.java:12)
Run Code Online (Sandbox Code Playgroud)
我本以为我至少可以重新实例化静态方法引用... nope,显然不是.
我一直在使用与Groovy Closures类似的方法,并且运行良好.所以我只是对Java 8 lambdas做错了,还是不可能通过名称实例化lambdas?我在网上发现了lambdas可以(de)序列化的一些提示,所以我希望它也可以通过名称实例化它们.
好吧,Oracle的JRE/OpenJDK的一个特殊属性是使用"匿名类",根本不能通过名称访问它.但即使没有这个,也没有理由认为这应该有效:
Class.forName(String)尝试通过调用者解析类ClassLoader.因此,即使使用普通类实现lambda表达式,如果通过不同的方式加载也无法访问ClassLoaderClass.newInstance()仅在存在public无参数构造函数时才有效.你不能假设有一个no-arg构造函数,也不是publicjava.lang.reflect.Proxy生成interface委托给一个的实现InvocationHandler.尝试通过其类名重新实例化此类代理将失败,因为您需要将实际InvocationHandler实例传递给代理的构造函数.原则上,JRE特定的lambda表达式实现可以使用类似的模式考虑到上述几点,应该清楚的是,你不能说它一般适用于内部类.你必须要满足很多限制.
关于序列化,它适用于可序列化的lambda表达式,因为持久化表单与运行时实现类完全分离,如本答案中所述.因此,生成的类的名称不包含在序列化形式中,反序列化结束可能具有完全不同的运行时实现.
| 归档时间: |
|
| 查看次数: |
1353 次 |
| 最近记录: |