天天看點

java.lang.String_自己寫的java.lang.String可以讓jvm加載到嗎?

git

前言

老問題了,到網上也一搜一堆答案,比如,随便來一篇

java.lang.String_自己寫的java.lang.String可以讓jvm加載到嗎?

乍一看好像沒什麼問題,但是在掌握自定義類加載器之後,知道如何打破雙親委派之後再回頭來看這段話發現有兩個問題:

1:憑什麼你認為我現在是ApplicationClassLoader? 畢竟很多架構都會自定義類加載器的

2: 憑什麼你認為我一定要走雙親委派?

懷疑當然要有個證據,那麼我們就寫一段程式:

1:打破雙親委派

2:寫一個java.lang.String類

代碼見git

《2020最新Java基礎精講視訊教程和學習路線!》

一些重要的地方截取出來看看package java.lang;

public class String {

private Integer a;

public Integer getA() {

return a;

}

public void setA(Integer a) {

this.a = a;

}

}package org.wayne;

import org.wayne.util.ClassLoaderUtil;

import java.lang.reflect.Method;

public class RegisterDriverUtil {

public static void register(String name){

Class pluginClass = ClassLoaderUtil.getPluginClass(RegisterDriverUtil.class);

try {

Method method = pluginClass.getDeclaredMethod("register", String.class);

method.setAccessible(true);

method.invoke(pluginClass.newInstance(),name);

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}package org.wayne;

public class RegisterDriverUtil {

public void register(String name) throws ClassNotFoundException {

Class.forName(name);

}

}public static void test8(){

EnvironmentUtil.setEnv(EnvEnum.A);

RegisterDriverUtil.register("java.lang.String");

EnvironmentUtil.clearEnv();

}

打包,在wsl下運作,結果如下

java.lang.String_自己寫的java.lang.String可以讓jvm加載到嗎?

推測:

1:代碼裡是用自定義類加載器直接加載的java.lang.String類,并沒有走雙親委派

2:由報錯來看,是java.lang.ClassLoader阻止了加載

原因

無論何種自定義類加載器,最後都是調用的defineClass方法加載byte[],注釋如下

java.lang.String_自己寫的java.lang.String可以讓jvm加載到嗎?

protected final Class> defineClass(String name, byte[] b, int off, int len,

ProtectionDomain protectionDomain)

throws ClassFormatError

{

protectionDomain = preDefineClass(name, protectionDomain);

String source = defineClassSourceLocation(protectionDomain);

Class> c = defineClass1(name, b, off, len, protectionDomain, source);

postDefineClass(c, protectionDomain);

return c;

}

private ProtectionDomain preDefineClass(String name,

ProtectionDomain pd)

{

if (!checkName(name))

throw new NoClassDefFoundError("IllegalName: " + name);

// Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias

// relies on the fact that spoofing is impossible if a class has a name

// of the form "java.*"

if ((name != null) && name.startsWith("java.")) {

throw new SecurityException

("Prohibited package name: " +

name.substring(0, name.lastIndexOf('.')));

}

if (pd == null) {

pd = defaultDomain;

}

if (name != null) checkCerts(name, pd.getCodeSource());

return pd;

}

結論

1:無論何種自定義類加載器,最終都會調用ClassLoader.defineClass

2:ClassLoader.defineClass中會檢查類名,類名以java.開頭的,不予加載