我的包的路径是com.company.*
新建两个文件,一个Main.java,用作被加载之用。
一个CustomClassLoader.java,用于加载Main.java。
代码如下:
package com.company;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class CustomClassLoader extends ClassLoader {
@Override
public Class findClass(String name) throws ClassNotFoundException {
byte[] b = loadClassFromFile(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassFromFile(String fileName) {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(
fileName.replace('.', File.separatorChar) + ".class");
byte[] buffer;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = 0;
try {
while ( (nextValue = inputStream.read()) != -1 ) {
byteStream.write(nextValue);
}
} catch (IOException e) {
e.printStackTrace();
}
buffer = byteStream.toByteArray();
return buffer;
}
public static void main(String[] args) {
CustomClassLoader customClassLoader = new CustomClassLoader();
try {
Object main = customClassLoader.findClass("com.company.Main").newInstance(); //com.company.CustomClassLoader@511d50c0
System.out.println(main.getClass().getClassLoader());//sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(Main.class.getClassLoader());//false
System.out.println(main instanceof Main);
} catch (Exception e) {
e.printStackTrace();
}
}
}
可以看到指定使用CustomClassLoader和使用JVM默认的方式加载的Main是会被判断为不是同一类的。
因为不同的类加载器有不同的命名空间。
https://www.baeldung.com/java-classloaders
另外经常会有面试题问能够自己定义一个java.lang.System进行加载,答案是否定的
我们可以尝试在src目录下新建java.lang.System类,再用上面的代码尝试加载,会发现抛出异常java.lang.SecurityException: Prohibited package name: java.lang。
在ClassLoader类中也可以看到这样的解释。
* If an attempt is made to add this class to a package that * contains classes that were signed by a different set of * certificates than this class, or if an attempt is made * to define a class in a package with a fully-qualified name * that starts with "{@code java.}".