[英]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.