技术经验分享: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


}


转自:

相关文章
|
12天前
|
前端开发 Java API
Java入门教程:掌握Spring MVC的双向数据绑定技术
以上步骤展示了如何利用 Spring MVC 实现双向数据绑定:从显示表单、提交表单、验证输入、直至返回结果页面都涉及到不同层次间交互过程,在整个过程都无需手动去编写繁琐代码去手动获取或设置每一项值。
96 20
|
18天前
|
安全 Java 数据建模
Java记录类:简化数据载体的新选择
Java记录类:简化数据载体的新选择
169 101
|
18天前
|
安全 Java 开发者
Java记录类:简化数据载体的新方式
Java记录类:简化数据载体的新方式
196 100
|
23天前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
213 1
|
23天前
|
安全 Cloud Native Java
Java 模块化系统(JPMS)技术详解与实践指南
本文档全面介绍 Java 平台模块系统(JPMS)的核心概念、架构设计和实践应用。作为 Java 9 引入的最重要特性之一,JPMS 为 Java 应用程序提供了强大的模块化支持,解决了长期存在的 JAR 地狱问题,并改善了应用的安全性和可维护性。本文将深入探讨模块声明、模块路径、访问控制、服务绑定等核心机制,帮助开发者构建更加健壮和可维护的 Java 应用。
127 0
|
29天前
|
监控 Cloud Native Java
Quarkus 云原生Java框架技术详解与实践指南
本文档全面介绍 Quarkus 框架的核心概念、架构特性和实践应用。作为新一代的云原生 Java 框架,Quarkus 旨在为 OpenJDK HotSpot 和 GraalVM 量身定制,显著提升 Java 在容器化环境中的运行效率。本文将深入探讨其响应式编程模型、原生编译能力、扩展机制以及与微服务架构的深度集成,帮助开发者构建高效、轻量的云原生应用。
142 44
|
2月前
|
Java 测试技术 API
2025 年 Java 开发者必知的最新技术实操指南全览
本指南涵盖Java 21+核心实操,详解虚拟线程、Spring Boot 3.3+GraalVM、Jakarta EE 10+MicroProfile 6微服务开发,并提供现代Java开发最佳实践,助力开发者高效构建高性能应用。
316 4
|
2月前
|
安全 Java 编译器
new出来的对象,不一定在堆上?聊聊Java虚拟机的优化技术:逃逸分析
逃逸分析是一种静态程序分析技术,用于判断对象的可见性与生命周期。它帮助即时编译器优化内存使用、降低同步开销。根据对象是否逃逸出方法或线程,分析结果分为未逃逸、方法逃逸和线程逃逸三种。基于分析结果,编译器可进行同步锁消除、标量替换和栈上分配等优化,从而提升程序性能。尽管逃逸分析计算复杂度较高,但其在热点代码中的应用为Java虚拟机带来了显著的优化效果。
64 4
|
2月前
|
缓存 安全 Java
Java反射机制:动态操作类与对象
Java反射机制是运行时动态操作类与对象的强大工具,支持获取类信息、动态创建实例、调用方法、访问字段等。它在框架开发、依赖注入、动态代理等方面有广泛应用,但也存在性能开销和安全风险。本文详解反射核心API、实战案例及性能优化策略,助你掌握Java动态编程精髓。
|
23天前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案

热门文章

最新文章