本篇文章给大家带来的内容是关于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动态类加载和重新加载的详细介绍的详细内容。更多信息请关注PHP中文网其他相关文章!

解决Java反射异常(ReflectiveOperationException)的方法在Java开发中,反射(Reflection)是一种强大的机制,它允许程序在运行时动态地获取和操作类、对象、方法和属性等。通过反射,我们可以实现一些灵活的功能,比如动态创建对象、调用私有方法、获取类的注解等。然而,使用反射也会带来一些潜在的风险和问题,其中之一就是反射异常(

Golang函数的反射和类型断言的应用和底层实现在Golang编程中,函数的反射和类型断言是两个非常重要的概念。函数的反射可以让我们在运行时动态的调用函数,而类型断言则可以帮助我们在处理接口类型时进行类型转换操作。本文将深入讨论这两个概念的应用以及他们的底层实现原理。一、函数的反射函数的反射是指在程序运行时获取函数的具体信息,比如函数名、参数个数、参数类型等

如何在Java中使用反射调用方法反射是Java语言的一个重要特性,它可以在运行时动态地获取类的信息并操作类的成员,包括字段、方法和构造函数等。使用反射可以在编译时不知道具体类的情况下操作类的成员,这使得我们能够编写更加灵活和通用的代码。本文将介绍如何在Java中使用反射调用方法,并给出具体的代码示例。一、获取类的Class对象在Java中,要使用反射来调用方

Python是一种灵活的编程语言,为开发人员提供了广泛的功能和工具。其强大的功能包括元编程——一种先进的技术,使开发人员能够在运行时动态地操作和生成代码。在本文中,我们将踏上高级Python元编程领域的旅程,特别关注动态代码生成和反射。通过采用这些技术,开发人员可以创建能够适应、修改甚至自省的代码,从而为创建灵活高效的应用程序开启了新的可能性世界。通过探索Python中动态代码生成和反射的概念和实际应用,我们将揭示元编程如何彻底改变开发过程,使开发人员能够生成健壮且高度适应性的代码。了解元编程元

Go语言作为一门静态类型语言,在代码编写时需要明确每个变量的类型。但是,在某些情况下,我们需要对程序中的类型进行动态的分析和操作,这时就需要用到反射机制。反射机制可以在程序运行时动态地获取程序对象的类型信息,并能够对其进行分析和操作,非常有用。但是,Go语言中反射机制也存在一些局限性,下面我们来详细了解一下。反射机制对性能的影响使用反射机制可以大大增强代

Java是一种面向对象的编程语言,代码在编译后不直接变成机器语言,而是转化为字节码。字节码是Java虚拟机(JVM)可以理解的一种二进制形式。因此,在JVM上运行的程序可以在任何平台上运行,这就是Java的跨平台性。Java字节码的特征Java字节码是一种中间代码。编译器将Java源代码转换为字节码并存储在.class文件中。字节码指令可以轻松地转换为指示任

Java底层技术解读:如何实现反射与动态代理引言:Java是一种面向对象的编程语言,在开发过程中,我们经常需要使用到一些底层技术,比如反射和动态代理。本文将介绍反射和动态代理的原理,并给出具体的代码示例,帮助读者更好地理解和运用这两个底层技术。一、反射(Reflection)的原理反射是Java中一种强大而灵活的特性,它使得我们可以在运行时动态地获取和操作一

反射通常被定义为程序在执行时检查自身并修改其逻辑的能力。用不太专业的术语来说,反射是要求一个对象告诉您它的属性和方法,并更改这些成员(甚至是私有成员)。在本课程中,我们将深入探讨如何实现这一点,以及它何时可能有用。一点历史在编程时代的初期,出现了汇编语言。用汇编语言编写的程序驻留在计算机内部的物理寄存器中。通过读取寄存器可以随时检查其组成、方法和值。更重要的是,您可以在程序运行时通过简单地修改这些寄存器来更改程序。它需要对正在运行的程序有一些深入的了解,但它本质上是反思性的。与任何很酷的玩具一样


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

Dreamweaver CS6
视觉化网页开发工具

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),