[英]Why can't lambda class load?
为什么运行以下代码时会出现异常? 去看源码发现这个class是ASM生成的。 这样生成的class不是在方法区吗?
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class<? extends Runnable> runClass = test().getClass();
ClassLoader classLoader = runClass.getClassLoader();
System.out.println(classLoader.loadClass(Main.class.getName()));
System.out.println(classLoader.loadClass(runClass.getName()));
}
public static Runnable test() {
return () -> {};
}
}
结果
class link.yxw.Main
Exception in thread "main" java.lang.ClassNotFoundException: link.yxw.Main$$Lambda$1/1324119927
at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at link.yxw.Main.main(Main.java:10)
简短的回答是:因为 lambda class 是隐藏的(JDK15 中的JEP 371 对其进行了标准化并暴露了 API,但由于 JDK 已被其他类访问且无法访问) 您可以在类似这样的博文和文章中找到更多信息。
如果我们定义:
public static Runnable lambdaTest() {
return () -> {
};
}
public static Runnable anonymTest() {
return new Runnable() {
@Override
public void run() {
}
};
}
并运行:
System.out.println(Main.class.isHidden());
System.out.println(anonymTest().getClass().isHidden());
System.out.println(lambdaTest().getClass().isHidden());
我们会得到:
false
false
true
如果我们打印 lambda class 的名称,我们将在不同的 JDK 上得到不同的结果,但都归结为相同的概念:
JDK 8-10: java.lang.ClassNotFoundException: Main$$Lambda$1/791452441
JDK 11+: java.lang.ClassNotFoundException: Main$$Lambda$1/0x0000000800060840
如果 class 或接口被隐藏,则结果为以下形式的字符串: N + '/' + <suffix> 其中 N 是传递给 Lookup::defineHiddenClass 的 class 文件指示的二进制名称,并且是非限定名称.
如果您想查看实现: 可以在此处找到JDK 9 的本机 JDK 代码(这里是镜像类的简短描述), 这里是 JDK 18 代码(自 15 年以来一直存在)。 如果您想阅读更多内容,我推荐这个 SO answer 。
最后让我们看看查找 class 进行加载的ClassLoader
代码:
protected final Class<?> findLoadedClass(String name) {
if (!checkName(name))
return null;
return findLoadedClass0(name);
}
// true if the name is null or has the potential to be a valid binary name
private static boolean checkName(String name) {
if ((name == null) || (name.isEmpty()))
return true;
if ((name.indexOf('/') != -1) || (name.charAt(0) == '['))
return false;
return true;
}
如果 class 名称包含/
字符,则将其解析为无效的二进制名称并且无法加载。 如果您想知道[
字符 - 它标记了一个数组 class。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.