本篇文章给大家带来的内容是关于Java动态类加载和重新加载的详细介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

Java中可以在运行时加载和重新加载类,虽然并不像我们想像中那么简单。本文将解释何时、怎样在Java中加载、重新加载类。

你可以争论动态加载类是Java反射的一部分还是Java核心的一部分。不管怎样,我把它放在了Java反射中,因为没有更好的地方放置它。

类加载器

Java程序的所有类都是使用 java.lang.ClassLoader的一些子类加载的。因此,动态加载类也必须使用 java.lang.ClassLoader的子类。

当一个类加载,它所引用的类也会被加载。类加载模式是递归加载的,直到所有需要的类加载完毕。这可能并不是应用程序的所有类。未被引用的类在引用前不会被加载。

类加载层级结构

类加载在Java中被组织成层级。当你创建一个独立的ClassLoader,你必须提供一个父级ClassLoader。如果ClassLoader被请求加载一个类,它会请求它的父级ClassLoader去加载它。如果父级类加载器找不到这个类,子类加载器会尝试自加载。

类加载

类加载器加载类的步骤如下:检查该类是否已被加载

如类未加载,请求父类加载器加载它

如父类加载器不能加载该类,尝试使用当前类加载器加载它

当你实现一个能够重载类的类加载器时,你需要从这个序列中偏离一点。不应请求父类加载程序加载要重装的类。稍后再谈。

动态类加载

动态加载类非常简单。所有你需要做的是获得一个ClassLoader并调用它的loadClass()方法。示例如下:public class MainClass {

public static void main(String[] args){

ClassLoader classLoader = MainClass.class.getClassLoader();

try {

Class aClass = classLoader.loadClass("com.jenkov.MyClass");

System.out.println("aClass.getName() = " + aClass.getName());

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

动态类重新加载

动态类重新加载有一些挑战。Java内建的类加载器在加载类之前总会检查类是否已被加载。因此,使用Java的内置类加载器不可能重新加载类。重新加载一个类你必须实现自己的ClassLoader子类。

即使使用类加载器的自定义子类,也会遇到挑战。所有已被加载的类都需要被链接。这个方法是final的,因此不能被你的ClassLoader子类重载。resolve()方法不允许ClassLoader实例链接一个类2次。因此,每当你需要重新加载类时,你必须重新创建一个ClassLoader类的实例。这不是不可能的,但必须知道何时设计类重新加载。

类重载代码设计

如上文述,不能使用加载指定类的ClassLoader重新加载这个类。因此,必须使用不同的ClassLoader加载这个类。但是,这会带来新的问题。

Java程序中加载的每一个类都以其全限定名(包名+类名)标识,并且由ClassLoader实例加载。这意味着,类MyObject由类加载器A加载,是和由类加载器B加载的同一个类MyObject不相同。模拟代码如下:MyObject object = (MyObject)

myClassReloadingFactory.newInstance("com.jenkov.MyObject");

注意,类MyObject在代码中是如何引用的,是作为object类型的变量。这导致MyObject类被已加载过这个类的驻留代码的类加载器加载。

如果myClassReloadingFactory对象工厂使用与驻留代码不同的类加载器加载MyObject,你不能强制转换重新加载的Object类型的变量MyObject为MyObject类型。因为这两个MyObject由不同的类加载器加载,他们被视为不同的类,尽管他们拥有相同的全限定名。尝试强转一个object的类为另一个类的引用将抛出ClassCastException。

有可能绕过这个限制,但是你必须用两种方式来改变你的代码:使用接口作为变量类型,并且只重新加载实现类

使用超类作为变量类型,并且只重新加载子类

这里是示例代码:MyObjectInterface object = (MyObjectInterface)

myClassReloadingFactory.newInstance("com.jenkov.MyObject");MyObjectSuperclass object = (MyObjectSuperclass)

myClassReloadingFactory.newInstance("com.jenkov.MyObject");

如果变量类型是接口或超类,上面的代码都会正常运行,接口或超类在重新加载实现或子类时不会被重新加载。

为了上面代码的正常运行,你当然需要实现自己的类加载器,让接口或超类由其父类加载。当你的类加载器被请求加载MyObject时,它也会被请求加载MyObjectInterface接口或者MyObjectSuperclass类,因为它们被MyObject类在内部引用。你的类加载器必须把类加载委派给相同的类加载器,即加载了接口或超类的类加载器。

类加载器加载/重新加载示例

上文包含了很多内容。让我们看一下简单的示例。下面是一个简单的ClassLoader子类。注意它如何将类加载委托给它的父类,除了它想要重装的一个类之外。如果类加载被委派给了它的父类,它以后将不能被重新加载。记住,一个类只能被同一个ClassLoader实例加载。

如前所述,这只是一个示例,它显示了类加载器的行为的基本知识。这并不是一个你的类加载器的生产就绪的模板。你的类加载器可能并不仅限于一个类,可能是一个你想要重新加载的类的集合。此外,你也不能硬编码class path。public class MyClassLoader extends ClassLoader{

public MyClassLoader(ClassLoader parent) {

super(parent);

}

public Class loadClass(String name) throws ClassNotFoundException {

if(!"reflection.MyObject".equals(name))

return super.loadClass(name);

try {

String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +

"classes/reflection/MyObject.class";

URL myUrl = new URL(url);

URLConnection connection = myUrl.openConnection();

InputStream input = connection.getInputStream();

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

int data = input.read();

while(data != -1){

buffer.write(data);

data = input.read();

}

input.close();

byte[] classData = buffer.toByteArray();

return defineClass("reflection.MyObject",

classData, 0, classData.length);

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

}

下面是使用MyClassLoader的示例:public static void main(String[] args) throws

ClassNotFoundException,

IllegalAccessException,

InstantiationException {

ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();

MyClassLoader classLoader = new MyClassLoader(parentClassLoader);

Class myObjectClass = classLoader.loadClass("reflection.MyObject");

AnInterface2 object1 =

(AnInterface2) myObjectClass.newInstance();

MyObjectSuperClass object2 =

(MyObjectSuperClass) myObjectClass.newInstance();

//create new class loader so classes can be reloaded.

classLoader = new MyClassLoader(parentClassLoader);

myObjectClass = classLoader.loadClass("reflection.MyObject");

object1 = (AnInterface2) myObjectClass.newInstance();

object2 = (MyObjectSuperClass) myObjectClass.newInstance();

}

reflection.MyObject类是由自定义类加载器加载的。注意,它是如何继承一个超类、实现一个接口的。这只是为了这个例子。在你的代码中,只需要两个中的一个,继承超类或实现接口。public class MyObject extends MyObjectSuperClass implements AnInterface2{

//... body of class ... override superclass methods

// or implement interface methods

}

java 类 重新加载_Java动态类加载和重新加载的详细介绍相关推荐

  1. java类验证和装载顺序_java中类的加载顺序介绍(ClassLoader)

    转自:http://blog.csdn.net/eff666/article/details/52203406 1.ClassNotFoundExcetpion 我们在开发中,经常可以遇见java.l ...

  2. java类验证和装载顺序_Java类的加载机制和双亲委派模型

    Java类的加载机制和双亲委派模型 1类的加载机制 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括了:加载(Loading).验证(Verification).准备(Prepar ...

  3. java类验证和装载顺序_Java类的加载顺序

    1.有继承关系的加载顺序 关于关键字static,大家 都知道它是静态的,相当于一个全局变量,也就是这个属性或者方法是可以通过类来访问,当class文件被加载进内存,开始初始化的时候,被static修 ...

  4. java类验证和装载顺序_java类加载机制,你会了吗?

    什么是类加载机制呢? java虚拟机将编译后的class文件加载到内存中,进行校验.转换.解析和初始化,到最终的使用.这就是java类加载机制: 下面就开始今天的内容: 1.类加载的生命周期:加载(L ...

  5. 【Android 逆向】启动 DEX 字节码中的 Activity 组件 ( 使用 DexClassLoader 获取组件类失败 | 失败原因分析 | 自定义类加载器没有加载组件类的权限 )

    文章目录 一.使用 DexClassLoader 获取组件类失败报错 二.失败原因分析 一.使用 DexClassLoader 获取组件类失败报错 在上一篇博客 [Android 逆向]启动 DEX ...

  6. java类的成员组成_Java类的组成:类的三个组成部分

    Java类的组成:类的三个组成部分 (2011-11-17 21:51:53) 标签: j2me 一.数据成员:数据成员是类的属性,声明该类的对象所具备的属性.声明数据成员往往需要声明以下几项:(1) ...

  7. java类和对象程序_Java类与对象程序设计基础

    Java类与对象程序设计基础 一.实验目的: 通过编制一个独立应用程序,使得学生掌握Java的系统所提供类的引用方法:通过编制一个完整的应用程序,使得学生对Java的应用程序的基本构成和基本算法熟练掌 ...

  8. Java类Demo中存在_Java中的数据类型转换

    先来看一个题: Java类Demo中存在方法func0.func1.func2.func3和func4,请问该方法中,哪些是不合法的定义?( ) public class Demo{ float fu ...

  9. java类的运行顺序_Java语言类的基本运行顺序

    本文主要向大家介绍了Java语言类的基本运行顺序,通过具体的代码向大家展示,希望对大家学习Java语言有所帮助.我们以下面的类来说明一个基本的 Java 类的运行顺序:1. public class  ...

最新文章

  1. php 之 在win10-64 上搭建开发环境
  2. NavigationDrawer和NavigationView-Android M新控件
  3. 用ISAPI方式实现Web页面的自动更新
  4. P1196 ssl1225-银河英雄传说【图论,并查集】
  5. windows API 菜鸟学习之路(三)
  6. PBR理论基础2:光照、材质与微面元理论
  7. react native基础-(一)react和react native基础
  8. 2020年带你学会全网营销
  9. 贝宝php支付接口,php做贝宝(paypal)支付接口
  10. 中国三四线城市有哪些创业机会?
  11. 阳光下可读显示技术的工作原理
  12. 乐鑫ESP32模组如何查看内部flash芯片支持的工作模式(QIO、QOUT、DIO、DOUT)?
  13. 跟小丸子学基础口语21-25
  14. java整合消息推送_SpringMVC整合websocket实现消息推送及触发功能
  15. Numpy给数组增加维度的操作
  16. Extjs 3.0.0 问题总结
  17. 未来5年,6大风口行业
  18. Maxwell简介、部署、原理和使用介绍
  19. C#零基础入门07:打老鼠之面向对象重构
  20. PMAC应用五-运动学

热门文章

  1. python缺失值填充方法
  2. 计算机主板上电时序图,主板上电时序图ppt课件.ppt
  3. 爆料称字节跳动实习生删库
  4. linux生成initrd,Linux initrd详解
  5. 2-2 实变函数之集合论(点集)
  6. 蓝桥杯 蚂蚁感冒 不要模拟!
  7. C++中虚析构函数和纯虚析构函数
  8. 做好这四件小事,让移动支付安全无忧!
  9. 电脑硬盘怎样合并分区?这样比重装系统快多了!
  10. 爱因斯坦在63岁时说