目录
1 执行Main方法的过程
2 类加载过程
java类加载属于懒加载,用到才加载
证明:
public class TestDynamicLoad {
static {
System.out.println("*************load TestDynamicLoad************");
}
public static void main(String[] args) {
new A();
System.out.println("*************load test************");
B b = null; //B不会加载,除非这里执行 new B()
}
}
class A {
static {
System.out.println("*************load A************");
}
public A() {
System.out.println("*************initial A************");
}
}
class B {
static {
System.out.println("*************load B************");
}
public B() {
System.out.println("*************initial B************");
}
}
执行结果:
步骤:
1 执行main方法,需要加载TestDynamicLoad类(执行静态代码块)
2 new A()时,加载A类,先执行类中的静态代码块 -> 构造方法
3 B没使用,不会加载
3 类加载器和双亲委派机制
引导类加载器:jre/lib;支撑JVM运行的核心类库
扩展类加载器:jre/lib/ext;扩展jar包
应用程序类加载器:java.class.path;自己写的类
自定义加载器:用户自定义路径下的类包
示例:
System.out.println(String.class.getClassLoader());
System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName());
System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName());
结果:
示例:
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
ClassLoader extClassloader = appClassLoader.getParent();
ClassLoader bootstrapLoader = extClassloader.getParent();
System.out.println("the bootstrapLoader : " + bootstrapLoader);
System.out.println("the extClassloader : " + extClassloader);
System.out.println("the appClassLoader : " + appClassLoader);
结果:
层级:app < ext < bootstrap
3.1 双亲委派核心源码
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
//若之前被加载,则直接获取
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//当前parent=extClassLoader
c = parent.loadClass(name, false);
} else {
//extClassLoader.parent=null(bootStrapClassLoader)
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
long t1 = System.nanoTime();
//都会调用URLClassLoader的findClass方法在加载器的类路径里查找并加载该类 -> 执行defineClass方法实现类加载过程
c = findClass(name);
...
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
为什么要有双亲委派?
沙箱安全机制:防止核心类被加载
避免重复加载:如果类被加载过一次,则不需要重复加载(findLoadedClass)
3.2 自定义类加载器
public class Liuxin {
static class LiuxinClassLoader extends ClassLoader {
private String classPath;
public LiuxinClassLoader(String classPath) {
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = new byte[0];
try {
data = loadByte(name);
} catch (Exception e) {
e.printStackTrace();
}
return defineClass(name, data, 0, data.length);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
if (c == null) {
if (!name.startsWith("User")) {
c = this.getParent().loadClass(name);
} else
c = findClass(name);
sun.misc.PerfCounter.getFindClasses().increment();
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
private byte[] loadByte(String name) throws Exception {
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
public static void main(String args[]) throws Exception {
//初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
LiuxinClassLoader classLoader = new LiuxinClassLoader("D:\\DeskTop");
//D盘创建 test/com/tuling/jvm 几级目录,将User类的复制类User1.class丢入该目录
Class clazz = classLoader.loadClass("User");
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("sout", null);
method.invoke(obj, null);
System.out.println(clazz.getClassLoader().getClass().getName());
LiuxinClassLoader classLoader1 = new LiuxinClassLoader("D:\\DeskTop\\liuxin");
Class clazz1 = classLoader.loadClass("User");
Object obj1 = clazz.newInstance();
Method method1 = clazz.getDeclaredMethod("sout", null);
method.invoke(obj, null);
System.out.println(clazz.getClassLoader().getClass().getName());
}
}
}
使用:
public static void main(String args[]) throws Exception {
//初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
LiuxinClassLoader classLoader = new LiuxinClassLoader("D:/test");
//D盘创建 com/liuxin/User1 几级目录,将User类的复制类User1.class丢入该目录
Class clazz = classLoader.loadClass("com.liuxin.User1");
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("sout", null);
method.invoke(obj, null);
System.out.println(clazz.getClassLoader().getClass().getName());
}
自定义类加载器的父加载器为:appClassLoader