本篇文章给大家带来的内容是关于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动态类加载和重新加载的详细介绍的详细内容。
