技术经验分享:Java_动态加载类(英文)

简介: 技术经验分享:Java_动态加载类(英文)

It is possible to load and reload classes at runtime in Java, though it is not as straightforward as one might have hoped. This text will explain when and how you can load and reload classes in Java.


You can argue whether Java's dynamic class loading features are really part of Java Reflection, or a part of the core Java platform. Anyways, the article has been put in the Java Reflection trail in lack of a better place to put it.


The ClassLoader


All classes in a Java application are loaded using some subclass of //代码效果参考:http://www.jhylw.com.cn/133428655.html

java.lang.ClassLoader. Loading classes dynamically must therefore also be done using a java.lang.ClassLoader subclass.

When a class is loaded, all classes it references are loaded too. This class loading pattern happens recursively, until all classes needed are loaded. This may not be all classes in the application. Unreferenced classes are not loaded until the time they are referenced.


The ClassLoader Hierarchy


Class loaders in Java are organized into a hierarchy. When you create a new standard Java ClassLoaderyou must provide it with a parent ClassLoader. If a ClassLoader is asked to load a class, it will ask its parent class loader to load it. If the parent class loader can't find the class, the child class loader then tries to load it itself.


Class Loading


The steps a given class loader uses when loading classes are://代码效果参考:http://www.jhylw.com.cn/563439321.html


Check if the class was already loaded.


If not loaded, ask parent class loader to load the class.


If parent class loader cannot load class, attempt to load it in this class loader.


When you implement a class loader that is capable of reloading classes you will need to deviate a bit from this sequence. The classes to reload should not be requested loaded by the parent class loader. More on that later.


Dynamic Class Loading


Loading a class dynamically is easy. All you need to do is to obtain a ClassLoader and call its loadClass()method. Here is an example:


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();


}


}


Dynamic Class Reloading


Dynamic class reloading is a bit more challenging. Java's builtin Class loaders always checks if a class is already loaded before loading it. Reloading the class is therefore not possible using Java's builtin class loaders. To reload a class you will have to implement your own ClassLoader subclass.


Even with a custom subclass of ClassLoader you have a challenge. Every loaded class needs to be linked. This is done using the ClassLoader.resolve() method. This method is final, and thus cannot be overridden in your ClassLoader subclass. The resolve() method will not allow any given ClassLoader instance to link the same class twice. Therefore, everytime you want to reload a class you must use a new instance of yourClassLoader subclass. This is not impossible, but necessary to know when designing for class reloading.


Designing your Code for Class Reloading


As stated earlier you cannot reload a class using a ClassLoader that has already loaded that class once. Therefore you will have to reload the class using a different ClassLoader instance. But this poses som new challenges.


Every class loaded in a Java application is identified by its fully qualified name (package name + class name), and the ClassLoader instance that loaded it. That means, that a class MyObject loaded by class loader A, is not the same class as the MyObject class loaded with class loader B. Look at this code:


MyObject object = (MyObject)


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


Notice how the MyObject class is referenced in the code, as the type of the object variable. This causes theMyObject class to be loaded by the same class loader that loaded the class this code is residing in.


If the myClassReloadingFactory object factory reloads the MyObject class using a different class loader than the class the above code resides in, you cannot cast the instance of the reloaded MyObject class to the MyObjecttype of the object variable. Since the two MyObject classes were loaded with different class loaders, the are regarded as different classes, even if they have the same fully qualified class name. Trying to cast an object of the one class to a reference of the other will result in a ClassCastException.


It is possible to work around this limitation but you will have to change your code in either of two ways:


Use an interface as the variable type, and just reload the implementing class.


Use a superclass as the variable type, and just reload a subclass.


Here are two coresponding code examples:


MyObjectInterface object = (MyObjectInterface)


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


MyObjectSuperclass object = (MyObjectSuperclass)


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


Either of these two methods will work if the type of the variable, the interface or superclass, is not reloaded when the implementing class or subclass is reloaded.


To make this work you will of course need to implement your class loader to let the interface or superclass be loaded by its parent. When your class loader is asked to load the MyObject class, it will also be asked to load the MyObjectInterface class, or the MyObjectSuperclass class, since these are referenced from within theMyObject class. Your class loader must delegate the loading of those classes to the same class loader that loaded the class containing the interface or superclass typed variables.


ClassLoader Load / Reload Example


The text above has contained a lot of talk. Let's look at a simple example. Below is an example of a simpleClassLoader subclass. Notice how it delegates class loading to its parent except for the one class it is intended to be able to reload. If the loading of this class is delegated to the parent class loader, it cannot be reloaded later. Remember, a class can only be loaded once by the same ClassLoader instance.


As said earlier, this is just an example that serves to show you the basics of a ClassLoader's behaviour. It is not a production ready template for your own class loaders. Your own class loaders should probably not be limited to a single class, but a collection of classes that you know you will need to reload. In addition, you should probably not hardcode the class paths either.


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;


}


}


Below is an example use of the 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();


}


Here is the reflection.MyObject class that is loaded using the class loader. Notice how it both extends a superclass and implements an interface. This is just for the sake of the example. In your own code you would only have to one of the two - extend or implement.


public class MyObject extends MyObjectSuperClass implements AnInterface2{


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


// or implement interface methods


}


转自:

相关文章
|
10天前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
|
27天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
47 17
|
19天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
23天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
76 4
|
24天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
45 2
|
24天前
|
JSON 前端开发 JavaScript
java-ajax技术详解!!!
本文介绍了Ajax技术及其工作原理,包括其核心XMLHttpRequest对象的属性和方法。Ajax通过异步通信技术,实现在不重新加载整个页面的情况下更新部分网页内容。文章还详细描述了使用原生JavaScript实现Ajax的基本步骤,以及利用jQuery简化Ajax操作的方法。最后,介绍了JSON作为轻量级数据交换格式在Ajax应用中的使用,包括Java中JSON与对象的相互转换。
38 1
|
28天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
4月前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
61 7
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
20 3
|
2月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
31 2