从一个小例子来看动态卸载class

本文通过一个实例演示了在Java中如何使用URLClassLoader每隔3秒重复加载同一个类,并观察在此过程中修改类文件所带来的变化。实验表明,虽然无法动态添加或删除类成员,但可以修改成员变量值和成员方法内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[size=medium]先看一个实例

使用URLClassLoader每隔3秒钟重复加载A类的class
假如在这3秒钟内我们把class修改了
将会得到什么样的结果:[/size]
-------------------------------------
package jvm;

import java.net.URL;
import java.net.URLClassLoader;

public class Test {

public static void main(String[] args) {

while (true) {
try {
ClassLoader parentLoader = Test.class.getClassLoader();
URLClassLoader loader1 = new URLClassLoader(new URL[] { null }, parentLoader);
Class<?> cls1 = loader1.loadClass("jvm.A");
A excel = (A) cls1.newInstance();
excel.print();
Thread.sleep(1000 * 3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}

package jvm;

public class A {
private String className = "class A";//修改成员变量 class A
static {
System.out.println(" static block initialization ");//修改静态成员变量的打印内容 static block initialization change
}

// private String addField = "field 1";//运行时添加一个成员变量
public void print() {
System.out.println("hello ");//修改方法内的打印内容hello change
System.out.println("------------------" + className);
System.out.println("the end");
}
//运行时添加一个成员方法
// public void print2() {
// System.out.println("hello ");//修改方法内的打印内容hello change
// System.out.println("------------------" + className);
// System.out.println("the end");
// }
}

[size=medium]
以debug的方式运行、按照下面的修改后运行得到的结果
--------------------------------
1、修改成员变量的值------------动态打印修改后的值
2、修改成员方法的打印内容-------动态打印修改后的值
3、添加成员变量-----------提示警告
4、添加成员方法-----------提示警告
5、删除成员变量-----------提示警告
6、删除成员方法-----------提示警告

根据以上运行结果
[b]class类加载到虚拟机之后无法添加或者删除成员变量及成员方法
但是可以修改成员变量的值或者修改成员方法中的内容[/b]

[/size]

[size=large] 从另一个角度分析 [/size]
[size=medium]
从JVM结构的角度分析,class的结构信息存放在java的方法区内(method Area).包括常量池、字段描述、方法描述等等
常量池:用于存放编译期已可知的常量,这部分内容将在类加载后进入方法区(永久代)存放。但是Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池,运行期间也可将新内容放入常量池。
字段信息和方法描述:在编译时期就已经载入到方法区中。运行时无法对该部分的内容进行修改
方法区可以选择不实现垃圾收集、开源的JVM默认是不实现垃圾收集。
方法区是否需要实现垃圾收集其实是一个很难取舍的问题:
假如对方法区的内存进行垃圾收集、可以想象下次再实例化对象需要重新加载class信息无疑是加重了实例化对象的负担
假如不对方法区的内存进行垃圾收集、则无法动态修改一个class的结构;只能修改一些成员变量、成员方法的内容
相对一些热部署的应用将无法实现[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值