我们尝试编写Person类如下
image.png

image.png

各类方法调用情况

无参方法

image.png

有参方法

image.png

静态方法

image.png

赋值

image.png

==所以说Java的类在初始化的时候就会调用静态代码块==

获取类

image.png
所以class关键字只对Java类进行加载,并不会进行初始化

==类在实例化的时候会调用构造代码块==

动态加载类

Class.forName()

image.png
我们跟进去看看
image.png
这里没有,我们可以看看它重载的另一种方法
image.png
它是否初始化的值是在这里确定的
image.png
也就是说它默认是初始化了的
我们尝试使用这个重载方法进行观察
代码如下

1
2
ClassLoader cl = ClassLoader.getSystemClassLoader();  
Class.forName("Person",false,cl);

这样就被认为是没有初始化后的
输出如下
image.png

在这里我们用了一个类加载器,那么如果我们使用这个类加载器去加载类,也就是用它的loadClass方法,它是否会对类进行初始化呢
image.png
我们发现输出为空,那么很明显loadClass方法不会对类进行初始化

我们来瞅瞅类加载的具体实现

我们直接打断点调到loadClass方法里
image.png
但如果我们打印cl变量就知道,这个加载器是一个app类加载器,我们去这个位置找找它的loadClass方法

image.png

image.png
但是这个方法是两个参数的,并不符合我们的调用
于是它就去了它的父类,也就走到了我们刚才强制步入的那个loadClass里
但是它又调用了两个参数的loadClass,所以下一步肯定又是回来
image.png
然后走到这里,它又调用了它父类的loadClass
image.png
然后check它是否被加载过
image.png
然后看它的父类是否存在,如果有的话就调用它父类的,如果没有就会去BootstrapClass
我们可以看到在这里的时候它的parent不是nullimage.png
但是当我们继续往下走然后步入
它又回到了这里
image.png
这时如果我们再走到parent这里image.png就会发现parent成null了
image.png
那是因为ExtClassLoader里就没有loadClass方法,所以它开始找BootstrapClass,然后还是没有找到
image.png
我们在这里继续跟进去
image.png
莫名其妙到了URLClassLoader,但我们去查的时候会发现无论是appClassLoader还是ExtClassLoader,它们都没有findClass这个方法
所以就去找了他俩的父类
然后我们走到了这里
image.png
我们发现它是在
image.png
这个时候完成的类加载
我们跟进去发现它又调用了另一个defineClass
image.png
image.png
它又跑到SecureClassLoader里了
image.png
显而易见的又是父类
然后它又调用了另一个重载的defineClass
最后发现它又回到了ClassLoader里
image.png
我们重点关注这个
image.png
image.png
发现它是一个native方法,也就是在这里完成了类加载
image.png
从这里的返回值c也就能很好的看出来了
然后层层返回,就结束了
image.png

继承关系如下:
ClassLoader->SecureClassLoader->URLClassLoader->AppClassLoader
调用关系
loadClass->findClass->defineClass(从字节码加载)

URLClassLoader任意类加载

我直接用我最开始学Java语法时候生成的.class文件了

1
2
3
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///D:\\codefile\\java\\")});  
Class<?> gongyueshu = urlClassLoader.loadClass("gongyueshu");
gongyueshu.newInstance();

我们这里的协议还可以换成http用来加载远程类,如果我们平时做题能控制到这里,那么就很有趣了

defineClass加载

代码如下

1
2
3
4
5
Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass",String.class,byte[].class,int.class,int.class);  
defineClassMethod.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\codefile\\java\\gongyueshu.class"));
Class c = (Class) defineClassMethod.invoke(cl,"gongyueshu",code,0,code.length);
c.newInstance();

急了,写ClassLoader的时候选错包了,运行好几次才发现跑util下去了,应该选java.lang的那个

unsafe.defineClass字节码加载(spring中可以直接生成

image.png
它里面也有一个defineClass方法
image.png
最终代码如下

1
2
3
4
5
6
Class c = Unsafe.class;  
Field unsafeMethod = c.getDeclaredField("theUnsafe");
unsafeMethod.setAccessible(true);
Unsafe unsafe =(Unsafe) unsafeMethod.get(null);
byte[] code = Files.readAllBytes(Paths.get("D:\\codefile\\java\\gongyueshu.class"));
unsafe.defineClass("gongyueshu",code,0,code.length,cl,null);