前言
学习了类加载过程jar找不到或无法加载主类,可以更加方便我们理解反射的机制和原理。
一、类加载过程
1、加载(load)
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类地java.lang.Class对象。
2、链接(link)
将类的二进制数据合并到 JRE 中。
3、初始化(Initialize):JVM虚拟机负责对类进行初始化
public class test01 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.num);
}
}
class A{
static {
System.out.println("静态代码块初始化!");
num = 500;
}
static Integer num = 100;
public A(){
System.out.println("无参构造初始化!");
}
}
执行结果如下:
结论:
①先执行静态代码块,这时候给num赋值为500
②然后执行无参构造函数,其实就是我们new的操作。
③执行num = 100;
④可以简单的得出类的加载先后顺序!
二、类初始化
前置代码:
public class test01 {
static {
System.out.println("我是main类的静态代码块。main类被加载啦~");
}
public static void main(String[] args) {
}
}
class A{
static int b = 2;
static {
System.out.println("父类A被加载~");
}
}
class B extends A{
static {
System.out.println("子类B被加载~");
b = 500;
}
static int m = 100;
static final int M = 1;
}
可以分两种情况来讨论这个问题:
1、类的主动引用(一定会发生类的初始化)
public static void main(String[] args) {
//主动引用
B b = new B();
}
结果:
public static void main(String[] args) {
//反射也会产生主动引用
Class.forName("com.dbright.Test.B");
}
2、类的被动引用(不会发生类的初始化)
public static void main(String[] args) {
//调用父类静态变量
System.out.println(B.b);
}
public static void main(String[] args) {
//定义自身数组
B[] array = new B[5];
}
public static void main(String[] args) {
//调用自身静态变量
System.out.println(B.M);
}
三、类加载器
**类加载器的作用 :**将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中数据的访问入口。 类加载器主要分为三层:
类缓存:标准的JavaSE类加载器可以按要求查找类jar找不到或无法加载主类,但一旦某个类被加载到类加载器中,他将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些Class对象。
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类的加载器
ClassLoader loader = ClassLoader.getSystemClassLoader();
System.out.println(loader); //sun.misc.Launcher$AppClassLoader@18b4aac2
//获取系统类加载的父类加载器-->扩展类加载器
ClassLoader parent = loader.getParent();
System.out.println(parent); //sun.misc.Launcher$ExtClassLoader@74a14482
//获取扩展类加载器的父类加载器-->根加载器(C/C++)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1); //null
//测试当前类是哪个加载器加载的
ClassLoader classLoader = Class.forName("com.dbright.Test.Test02").getClassLoader();
System.out.println(classLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2
//测试JDK内部类是谁加载的
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader); //null
// 如何获取系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
/*
D:\Software\Java\jdk1.8\jre\lib\charsets.jar;
D:\Software\Java\jdk1.8\jre\lib\deploy.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\access-bridge-64.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\cldrdata.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\dnsns.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\jaccess.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\jfxrt.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\localedata.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\nashorn.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\sunec.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\sunjce_provider.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\sunmscapi.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\sunpkcs11.jar;
D:\Software\Java\jdk1.8\jre\lib\ext\zipfs.jar;
D:\Software\Java\jdk1.8\jre\lib\javaws.jar;
D:\Software\Java\jdk1.8\jre\lib\jce.jar;
D:\Software\Java\jdk1.8\jre\lib\jfr.jar;
D:\Software\Java\jdk1.8\jre\lib\jfxswt.jar;
D:\Software\Java\jdk1.8\jre\lib\jsse.jar;
D:\Software\Java\jdk1.8\jre\lib\management-agent.jar;
D:\Software\Java\jdk1.8\jre\lib\plugin.jar;
D:\Software\Java\jdk1.8\jre\lib\resources.jar;
D:\Software\Java\jdk1.8\jre\lib\rt.jar;
D:\NEU\learn\java\project\out\production\project;
D:\NEU\learn\java\project\src\com\lib\commons-io-2.8.0.jar;
D:\Software\IntelliJ IDEA 2020.1.4\lib\idea_rt.jar
*/
//双亲委派机制:如果上层加载器存在不会使用下层定义类
}
}
双亲委派机制:如果上层加载器存在不会使用下层定义类
2021最新完整面试题及答案(都整理成文档),有很多干货,包含mysql,netty,spring,线程,spring cloud、JVM、源码、算法等详细讲解,详细的学习规划图等学习资料,私信我:Java 获取!
写作不易!请点赞、关注、评论给作者一个鼓励吧~
版权声明
本文仅代表作者观点。
本文系作者授权发表,未经许可,不得转载。
发表评论