Java的动态性很重要的原因是他提供了一种自定义的类的加载机制。 为了深入学习, 自己编写了一个自定义的类加载器类:主要的问题:
疑问:1。 为什么我自定了加载类还没加载 系统的加载器就可以发现类的存在。
2。 可是在第二个输出信息中为什么又变成了 我自定义的加载器
3。 更奇怪的是当我再次new 又会由系统加载器再次进行加载。
package classLaoder;
import java.io.*;
public class UserClassLoader extends ClassLoader {
public synchronized Class loadClass(String className, Boolean flag ) throws ClassNotFoundException {
//check the class weather had been loaded
Class class1=null; //= Class.forName(className);
if(class1!= null)
System.out.println(class1.toString());
//return class1;
// check the class has not been loaded by the System ClassLoader
try{
class1 = super.findSystemClass(className);
if(class1!=null)
System.out.println(class1.toString());
}catch(ClassNotFoundException _ex){
System.out.println(">> Not a system class.");
}
byte abyte0[] = getClassBytes(className);
if(abyte0 == null){
throw new ClassNotFoundException();
}
class1 = defineClass(null, abyte0, 0, abyte0.length);
if(class1 == null){
throw new ClassFormatError();
}
if(flag){
resolveClass(class1);
}
System.out.println(">> Returning newly loaded class.");
return class1;
}
private byte[] getClassBytes(String className){
String path="D://Program//NASA Program//ClassLoaderTest//classLaoder//";
className=path+"UserClass.class";
File f=new File( className );
byte[] b = new byte[(int)f.length()];
try{
InputStream input= new FileInputStream( f );
input.read(b);
System.out.println(b);
}catch(IOException e){
e.printStackTrace();
}
return b;
}
} 接着编写了一个测试程序:
package classLaoder;public class ClassLoaderTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
UserClassLoader loader= new UserClassLoader();
Object ob;
try{
ob=loader.loadClass("classLaoder.UserClass", true).newInstance();
System.out.println("the class UserClass is loader by "+ob.getClass().getClassLoader() );
}catch(Exception e){
e.printStackTrace();
}
UserClass user=new UserClass();
System.out.println("now the class UserClass is loader by "+user.getClass().getClassLoader() );
}
}
(其中的 UserClass 用于测试的一个非常简单的自定义的类)测试的结果:
class classLaoder.UserClass
[B@addbf1
>> Returning newly loaded class.
the class UserClass is loader by classLaoder.UserClassLoader@42e816
now the class UserClass is loader by sun.misc.Launcher$AppClassLoader@11b86e7疑问:1。 为什么我自定了加载类还没加载 系统的加载器就可以发现类的存在。
2。 可是在第二个输出信息中为什么又变成了 我自定义的加载器
3。 更奇怪的是当我再次new 又会由系统加载器再次进行加载。
疑问:1。 为什么我自定了加载类还没加载 系统的加载器就可以发现类的存在。
2。 可是在第二个输出信息中为什么又变成了 我自定义的加载器
3。 更奇怪的是当我再次new 又会由系统加载器再次进行加载。
package classLaoder;
import java.io.*;
public class UserClassLoader extends ClassLoader {
public synchronized Class loadClass(String className, Boolean flag ) throws ClassNotFoundException {
//check the class weather had been loaded
Class class1=null; //= Class.forName(className);
if(class1!= null)
System.out.println(class1.toString());
//return class1;
// check the class has not been loaded by the System ClassLoader
try{
class1 = super.findSystemClass(className);
if(class1!=null)
System.out.println(class1.toString());
}catch(ClassNotFoundException _ex){
System.out.println(">> Not a system class.");
}
byte abyte0[] = getClassBytes(className);
if(abyte0 == null){
throw new ClassNotFoundException();
}
class1 = defineClass(null, abyte0, 0, abyte0.length);
if(class1 == null){
throw new ClassFormatError();
}
if(flag){
resolveClass(class1);
}
System.out.println(">> Returning newly loaded class.");
return class1;
}
private byte[] getClassBytes(String className){
String path="D://Program//NASA Program//ClassLoaderTest//classLaoder//";
className=path+"UserClass.class";
File f=new File( className );
byte[] b = new byte[(int)f.length()];
try{
InputStream input= new FileInputStream( f );
input.read(b);
System.out.println(b);
}catch(IOException e){
e.printStackTrace();
}
return b;
}
} 接着编写了一个测试程序:
package classLaoder;public class ClassLoaderTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
UserClassLoader loader= new UserClassLoader();
Object ob;
try{
ob=loader.loadClass("classLaoder.UserClass", true).newInstance();
System.out.println("the class UserClass is loader by "+ob.getClass().getClassLoader() );
}catch(Exception e){
e.printStackTrace();
}
UserClass user=new UserClass();
System.out.println("now the class UserClass is loader by "+user.getClass().getClassLoader() );
}
}
(其中的 UserClass 用于测试的一个非常简单的自定义的类)测试的结果:
class classLaoder.UserClass
[B@addbf1
>> Returning newly loaded class.
the class UserClass is loader by classLaoder.UserClassLoader@42e816
now the class UserClass is loader by sun.misc.Launcher$AppClassLoader@11b86e7疑问:1。 为什么我自定了加载类还没加载 系统的加载器就可以发现类的存在。
2。 可是在第二个输出信息中为什么又变成了 我自定义的加载器
3。 更奇怪的是当我再次new 又会由系统加载器再次进行加载。
JVM并没有要求一个类只加载一次,你在自定义ClassLoader加载了UserClass并不会影响其它的ClassLoader,所以后面还是看到了系统的ClassLoader
一般来说,如果要用到自己的ClassLoader,最好是在你调用代码中全部使用Interface或者Abstract Class,真正的实现类依赖自己的ClassLoader加载,但是在后续代码中并不直接看到实现类,而是看到接口,这样就可以方便控制怎样加载自己的类,又不会再现系统自动加载你类的问题
另外还有, 如果一个类可以被多次加载, 那么不是很不安全, 如果在两次加载中间有个线程改了类的一些属性, 那么JVM中就有了两个版本的类 这时候如何生成新的对象?
当然你也可以Thread.currentThread().setContextClassLoader(cl)方式指定当前线程的ClassLoader