java可以运行时增加class吗 java类可以重复加载吗_类加载器


我爱学习,这一更大概路会和上一更在同一时间更新。所以就先期待一下!


java可以运行时增加class吗 java类可以重复加载吗_Java_02


正文分割线


一、类的加载机制:

1、类的加载机制总览:首先上一张整图


java可以运行时增加class吗 java类可以重复加载吗_类加载器_03


我们都知道Java程序的实现是通过Java代码-字节码-编译程序。我们主要讲解的还是class后缀文件加载到jvm虚拟机中的操作。具体的加载步骤如下图,我们也将按顺序讲解下图中的步骤。


java可以运行时增加class吗 java类可以重复加载吗_Java_04


2、类加载的步骤:

1)、第一步加载:将class文件中的内容,使用io流读取到jvm所在的内存。加载时,需要使用3个类加载器,他们分别是根类加载器,扩展类加载器,系统类加载器。他们之间存在父子关系。扩展类加载器的父类是根类加载器,子类是系统类加载器。

根类加载器:主要是加载Java的核心代码;java.*

扩展类加载器:加载Java的扩展代码,类似于Javax.*

系统类加载器:加载我们所写的代码。

类加载的具体流程:

1、Java.exe程序搜索jre目录,寻找jvm,并启动jvm。

2、jvm运行根类加载器,该根类加载器加载Java核心api。

3、根类加载器运行后,它会自动加载扩展类加载器和系统加载器,并将扩展类加载器的父类设置为根类加载器,将应用加载器的父亲设置为扩展类加载器。

4、扩张类加载器加载搜索JAVA_HOME/jre/lib/ext目录,并加载扩展api。

5、应用加载器搜索classpath目录,加载我们要运行的类。

6、类的class文件读入内存后,就会创建一个Java.lang.Class对象。也就是说,当Java程序中使用任何类时,系统都会为之创建一个Java.lang.Class对象。一旦某个类被载入jvm中,同一个类就不会再次被载入。

注意:一旦某个类被载入jvm中,同一个类就不会再次被载入。

类的加载机制-双亲委派


java可以运行时增加class吗 java类可以重复加载吗_加载_05


为什么要进行双亲委派呢?主要是为了防止程序员修改系统代码

2)、第二步连接:当类被加载后,系统就为之创建一个对应的class对象,接着就会进入连接阶段。连接阶段会负责把类的二进制数据合并到jre中。连接如下图所示也分为3个步骤。


java可以运行时增加class吗 java类可以重复加载吗_加载_06


验证:判断class中的内容,能否运行在当前jvm版本上,你不要做jdk1.8的代码,放在jdk1.7去运行。

准备:给static修饰的类变量赋初值,基本数据类型赋值为0,引用数据类型赋值为null。

解析:将类的二进制数据中的符号引用替换成直接引用。

3)、第三步初始化:

类初始化,第一个事情,就是针对静态变量赋初值,例如pi=3.14。

第二个事情,执行类中static修饰的静态初始化代码块代码。

初始化的步骤:

1)假如这个类还没有被加载和连接,程序先加载并连接该类。

2)假如该类的直接父类还没有被初始化,则先初始化其直接父类。

3)假如该类中有初始化语句,则系统依次执行这些初始化语句。

3、类的初始化的6种情况

1、创建类的实例子。

2、调用某个类的静态方法。

3、访问某个类或者接口的静态属性,或者为静态属性赋值。

4、使用反射方式强制创建某个类或接口对应的java.lang.Class对象。

5、初始化某个类的子类。

6、直接使用java.exe命令运行某个主类。

二、GC垃圾回收

1、总览:GC垃圾回收就是系统监视每一个类对象,如果该类没有被引用,就把该类销毁释放内存空间。

2、堆的空间分配:我们之前知道类一般是存放在堆中,所以垃圾回收的主战场还是在堆中。


java可以运行时增加class吗 java类可以重复加载吗_Java_07


堆空间中有新生代,老年代,持久代。后来我们把持久代单独归为元空间分割出来。而新生代中又分为Eden和Survive,Survive又分为from和to。

eden、from和to的内存比例为8:1:1

新生代和老年代的内存比例为1:2

3、垃圾回收的算法:

标记算法:标记对象的引用次数 当次数>0 表示对象正在被使用,当==0时,表示对象可以被清理。

清理算法:就是将对象从内存中干掉,一般来讲清理之后,会有内存的碎片,需要整理。

复制算法:就是将对象在转移时,copy复制一份,同样要记录复制次数。

4、回收的步骤:

第一次回收:当eden空间满了,gc线程将会检查每个对象的使用次数标记,当标记为0时,表示该对象已经没有被引用,可以被gc回收。当前标记不为0的,表示该对象依旧有引用,将使用复制算法将对象复制到form区间,并记录它的复制次数为1.

第二次回收:当eden空间再次满了,gc线程同事检查eden和from区间,判断每个对象的使用次数标记。为0则被回收,不为0使用复制算法将对象复制到to区间,并记录它的复制次数为2,将to改名为from.

第三次回收:当eden空间再次满了,gc线程同事检查eden和from区间,判断每个对象的使用次数标记。为0则被回收,不为0使用复制算法将对象复制到to区间,并记录它的复制次数为2,from改名为to,将to改名为from。

第N次:一直重复,不过当一个对象的复制次数>15次,依旧再次引用。此时对象将被复制到老年代,老年代如果满了,就会触发:full gc(全量垃圾回收)

5、如何优化JVM

总体思想:尽量的减少 Full GC()的次数,方法:调整新生代 和老年代的内存比例,调整新生代中Eden 和 Survive的内存比例,以及尽量不要存在那种长时间持有对象引用的类

6、Java的优势

Java语言牛逼就牛逼在,我们不需要进行垃圾回收,其他的都需要。因为JVM有一个称为垃圾回收器的低级线程,这个线程在后台不断地运行,自动寻找在Java程序中不再被使用的对象,并释放这些对象的内存。这种内存回收的过程被称为垃圾回收(Garbage Collection)。通过调用对象身上的finalize()方法,进行销毁对象。

代码举例


//试图重写String的方法
package java.lang;
public class String {
    public int length() {
        return 0;
    }
}
package com.woniuxy.java23.loader;
public class MainEnter {
    public static void main(String[] args) {
        TeacherBean teacher = new TeacherBean();
        //返回加载TeacherBean的加载类
        System.out.println(teacher.getClass().getClassLoader());
        //返回系统类加载器的父类
         System.out.println(teacher.getClass().getClassLoader().getParent());
        //返回扩展类加载器的父类
         System.out.println(teacher.getClass().getClassLoader().getParent().getParent());
        //防止 我们乱改它的核心代码,或者扩展代码
        String str = "1231231";
        System.out.println(str.length());
    }
}
代码的执行结果:length() == 7 不是0