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

image.png

image.png

image.png

各类方法调用情况

无参方法

image.png

image.png

有参方法

image.png

image.png

静态方法

image.png

image.png

赋值

image.png

image.png

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

获取类

image.png

image.png

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

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

动态加载类

Class.forName()

image.png

image.png

我们跟进去看看
image.png
image.png

这里没有,我们可以看看它重载的另一种方法
image.png
image.png

它是否初始化的值是在这里确定的
image.png
image.png

也就是说它默认是初始化了的
我们尝试使用这个重载方法进行观察
代码如下

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

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

image.png

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

image.png

我们发现输出为空,那么很明显loadClass方法不会对类进行初始化

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

我们直接打断点调到loadClass方法里
image.png

image.png

但如果我们打印cl变量就知道,这个加载器是一个app类加载器,我们去这个位置找找它的loadClass方法

image.png

image.png

image.png

image.png

但是这个方法是两个参数的,并不符合我们的调用
于是它就去了它的父类,也就走到了我们刚才强制步入的那个loadClass里
但是它又调用了两个参数的loadClass,所以下一步肯定又是回来
image.png
image.png

然后走到这里,它又调用了它父类的loadClass
image.png
image.png

然后check它是否被加载过
image.png
image.png

然后看它的父类是否存在,如果有的话就调用它父类的,如果没有就会去BootstrapClass
我们可以看到在这里的时候它的parent不是nullimage.png
image.png

但是当我们继续往下走然后步入
它又回到了这里
image.png
image.png

这时如果我们再走到parent这里image.png
image.png
就会发现parent成null了
image.png
image.png

那是因为ExtClassLoader里就没有loadClass方法,所以它开始找BootstrapClass,然后还是没有找到
image.png
image.png

我们在这里继续跟进去
image.png
image.png

莫名其妙到了URLClassLoader,但我们去查的时候会发现无论是appClassLoader还是ExtClassLoader,它们都没有findClass这个方法
所以就去找了他俩的父类
然后我们走到了这里
image.png
image.png

我们发现它是在
image.png
image.png

这个时候完成的类加载
我们跟进去发现它又调用了另一个defineClass
image.png
image.png

image.png
image.png

它又跑到SecureClassLoader里了
image.png
image.png

显而易见的又是父类
然后它又调用了另一个重载的defineClass
最后发现它又回到了ClassLoader里
image.png
image.png

我们重点关注这个
image.png
image.png

image.png
image.png

发现它是一个native方法,也就是在这里完成了类加载
image.png
image.png

从这里的返回值c也就能很好的看出来了
然后层层返回,就结束了
image.png
image.png

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

URLClassLoader任意类加载

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

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

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

defineClass加载

代码如下

java
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

image.png

它里面也有一个defineClass方法
image.png
image.png

最终代码如下

java
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);