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 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 ClassLoader
you 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:
- 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 MyObject
type 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
} 转自:http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html#classloader
Java_动态加载类(英文)的更多相关文章
- 关于实现Extjs动态加载类的方式实现
Extjs4以前的版本没有动态加载类的方式,这样开发程序的时候加载很多的js会导致加载变慢,由于本人一直使用extjs3的版本进行开发,于是简单实现了一个动态加载类的管理器,使用方式与extjs4的方 ...
- tomcat 5.5 动态加载类
转载于:http://www.itxuexiwang.com/a/javadianzishu/tomcat/2016/0225/161.html?1456480735 开发使用的是tomcat5.5. ...
- [javaSE] 反射-动态加载类
Class.forName(“类的全称”) ①不仅表示了类的类类型,还代表了动态加载类 ②请大家区分编译,运行 ③编译时刻加载类是静态加载类,运行时刻加载类是动态加载类 Ⅰ所有的new对象都是静态加载 ...
- java动态加载类和静态加载类笔记
JAVA中的静态加载类是编译时刻加载类 动态加载类指的是运行时刻加载类 二者有什么区别呢 举一个例子 现在我创建了一个类 实现的功能假设为通过传入的参数调用具体的类和方法 class offic ...
- Java动态加载类在功能模块开发中的作用
Java中我们一般会使用new关键字实例化对象然后调用该对象所属类提供的方法来实现相应的功能,比如我们现在有个主类叫Web类这个类中能实现各种方法,比如用户注册.发送邮件等功能,代码如下: /* * ...
- java reflect 初始学习 动态加载类
首先要理解Class类: 在java 的反射中,Class.forName("com.lilin.Office") 使用类的全名,这样获取,不仅仅表示了类的类类型,同时还代表着类的 ...
- Java运行时动态加载类之ClassLoader
https://blog.csdn.net/fjssharpsword/article/details/64922083 *************************************** ...
- java反射动态加载类Class.forName();
1,所有的new出来的对象都是静态加载的,在程序编译的时候就会进行加载.而使用反射机制Class.forName是动态加载的,在运行时刻进行加载. 例子:直接上两个例子 public class Ca ...
- 反射01 Class类的使用、动态加载类、类类型说明、获取类的信息
0 Java反射机制 反射(Reflection)是 Java 的高级特性之一,是框架实现的基础. 0.1 定义 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对 ...
随机推荐
- poj 1611:The Suspects(并查集,经典题)
The Suspects Time Limit: 1000MS Memory Limit: 20000K Total Submissions: 21472 Accepted: 10393 De ...
- 使用RMAN DUPLICATE...FROM ACTIVE DATABASE创建物理standby database
Applies to: Oracle Server - Enterprise Edition - Version 11.1.0.6 to 11.2.0.4 [Release 11.1 to 11.2] ...
- Codeforces Round #364 As Fast As Possible
二分思想,对所要花费的时间进行二分,再以模拟的形式进行验证是否可行. 使用二分法,可以将一个求最优解的问题转化为一个判定问题,优雅的暴力. #include<cstdio> #includ ...
- WCF消息拦截,利用消息拦截做身份验证服务
本文参考 http://blog.csdn.net/tcjiaan/article/details/8274493 博客而写 添加对信息处理的类 /// <summary> /// 消 ...
- Base64编码保存到文件服务器
byte[] buffer = Convert.FromBase64String(param.Base64Code); System.Net.WebClient webClient = new Sys ...
- MySQL主主复制3
一.创建并授权用户 在每一台(主)服务器上创建一个用户,并为之授权,使它们可以互相访问彼此的数据库 在Server-1上: 创建一个充许Server-2来访问的用户server2,密码为:server ...
- Uva10328 dp(递推+高精度)
题目链接:http://vjudge.net/contest/136499#problem/F 题意:给你一个硬币,抛掷n次,问出现连续至少k个正面向上的情况有多少种. 一个比较好理解的题解:原题中问 ...
- Python与Hack之守护进程
1.什么是守护进程: 在linux或者unix操作系统中,守护进程(Daemon)是一种运行在后台的特殊进程,它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件.由于在linux中,每个 ...
- JQuery学习之操作CSS
样式表: .important{ font-weight:bold; font-size:xx-large; } .blue{ color:blue; } 1.addClass():向被选元素添加一个 ...
- 关于本地存储构成数组以及jquery的inArray方法的使用
for (var i=0, j = _self.sessionStorage.length; i < j; i++){ var key = _self.sessionStorage.key(i) ...