其中BootStrapClassLoader加载jre/lib/rt.jar resources.jar charsets.jar
ExtClassLoader加载jre/ext/
AppClassLoader加载其他的类
找到sum.misc.Launcher
包
在AppClassLoader.loadClass处打断点,随便执行个自己定义的类中的main方法
跟到核心类ClassLoader.loadClass
,我先贴个图
我们先是从AppClassLoader进入
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
//AppClassLoader的父类是ExtClassLoader,依次往上
if (parent != null) {
//父类的loadClass方法也是调用的ClassLoader.loadClass
c = parent.loadClass(name, false);
} else {
//跟到了BootStrapClassLoader没有父类了,调用c++代码找class
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
//首先是ExtClassLoader中的c == null然后执行,返回
//接着是AppClassLoader中的c == null
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
//最终AppClassLoader中执行findClass找到了我们自定义的类
//看下文
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
跳转到URLClassLoader给出的findClass
这一整个findClass的逻辑就是从路径中找Class文件,然后交给defineClass去转化字节码为类
protected Class<?> findClass(final String name)
throws ClassNotFoundException
{
final Class<?> result;
try {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
String path = name.replace('.', '/').concat(".class");
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
//最终执行defineClass方法
return defineClass(name, res);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
} else {
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
如果想打破双亲委派就需要自己写ClassLoader类覆盖掉loadClass方法
自己写ClassLoader打破双亲委派试一下
package com.example.learn.learnjvm;
//import sum.misc.Launcher.AppClassLoader;
import java.io.IOException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException{
try{
String filename = name.substring(name.lastIndexOf(".") + 1) + ".class";
InputStream ls = getClass().getResourceAsStream(filename);
if(ls == null){
throw new ClassNotFoundException(name);
}
byte[] b = new byte[ls.available()];
ls.read(b);
return defineClass(name, b, 0, b.length);
} catch (IOException e) {
throw new ClassNotFoundException(name);
}
}
}
其中defineClass是jvm把二进制数据转换成类的方法。
测试类这样执行
public class Test {
public Test() throws ClassNotFoundException {
MyClassLoader mcl = new MyClassLoader();
Class clazz = mcl.loadClass("com.example.learn.learnjvm.Test");
System.out.println(clazz.getClassLoader());
}
public static void main(String[] args) throws ClassNotFoundException {
new Test();
}
}
报错,看来找不到java.lang.Object,也就是说最基本的类都没有初始化
loadClass替换成findClass就好了
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> findClass(String name) throws ClassNotFoundException{
try{
String filename = name.substring(name.lastIndexOf(".") + 1) + ".class";
InputStream ls = getClass().getResourceAsStream(filename);
if(ls == null){
throw new ClassNotFoundException(name);
}
byte[] b = new byte[ls.available()];
ls.read(b);
return defineClass(name, b, 0, b.length);
} catch (IOException e) {
throw new ClassNotFoundException(name);
}
}
}
测试类
public class Test {
public Test() throws ClassNotFoundException {
MyClassLoader mcl = new MyClassLoader();
Class clazz = mcl.findClass("com.example.learn.learnjvm.Test");
System.out.println(clazz.getClassLoader());
}
public static void main(String[] args) throws ClassNotFoundException {
new Test();
}
}
ok
总结
loadClass() 主要进行类加载的方法,默认的双亲委派机制就实现在这个方法中
findClass() 根据名称或位置加载.class字节码
definClass() 把字节码转化成java.lang.Class