1.Loading
将class文件加载到内存(生成两块内容):
1.二进制放到内存的一块区域
2.生成一个class类的对象,指向了上面的内容
2.Linking
>1.Verification(验证):验证文件是否符合JVM规定
>2.Preparation(准备):给静态成员变量赋默认值
>3.Resolution(解析):将类,方法,属性等符号引用解析为直接引用(转换成为内存的具体地址和指针)
3.Initializing
1.调用类初始化代码,给静态成员变量赋初始值
(成员变量赋值过程)
public class Hello {
//new Hello()的时候两个过程
// 1.申请出对象的内存,成员变量count赋默认值0
// 2.调用构造方法,成员变量count赋初始值6
private int count = 6;
public Hello(){
}
}
类加载器
类加载过程
问:为什么类加载要使用双亲委派机制?
答:为了安全 。假如直接写一个类java.lang.String,使用自定义类加载器将其load到内存,想想后果。。。
如果使用双亲委派的机制,当加载这个类的时候,首先会一层一层向上(父加载器)去查是否加载过此类,当查到最顶层Bootstrap类加载器时,发现加载过了,然后直接返回,就不会出现安全问题。
父加载器不是“类加载器的加载器”,也不是“类加载器的父类加载器”。通俗的理解他是类加载器里的一个成员变量parent对象。
双亲委派是指一个孩子向父亲的方向,然后父亲向孩子的方向的双亲委派过程。(图:类加载器)
手动加载一个类的class对象
Class clazz = Test4.class.getClassLoader().loadClass("com.example.springboot.demo.test.Test");
自定义类加载器只要重写ClassLoader的findClass方法。----------模板方法设计模式
findClass方法内部无逻辑,直接抛出ClassNotFoundException。
public class MyClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
File f = new File("d:/test/", name.replace(".", "/").concat(".class"));
try {
FileInputStream fis = new FileInputStream(f);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = 0;
while ((b=fis.read()) !=0) {
baos.write(b);
}
byte[] bytes = baos.toByteArray();
baos.close();
fis.close();//可以写的更加严谨
return defineClass(name, bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name); //throws ClassNotFoundException
}
public static void main(String[] args) throws Exception {
ClassLoader myClassLoader = new MyClassLoader();
Class clazz = myClassLoader.loadClass("com.example.springboot.demo.test.Hello");
Class clazz1 = myClassLoader.loadClass("com.example.springboot.demo.test.Hello");
System.out.println(clazz == clazz1);
Hello hello = (Hello)clazz.newInstance();
System.out.println(hello.hello());
System.out.println(myClassLoader.getClass().getClassLoader());
System.out.println(myClassLoader.getParent());
System.out.println(getSystemClassLoader());
}
}