天天看点

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.开头的,不予加载