MyLoadClass (自己写类加载器)

MyLoadClass (自己写类加载器)_第1张图片

Api中:

通常情况下,Java 虚拟机以与平台有关的方式,从本地文件系统中加载类。例如,在 UNIX 系统中,虚拟机从 CLASSPATH 环境变量定义的目录中加载类。

然而,有些类可能并非源自一个文件;它们可能源自其他来源(如网络),也可能是由应用程序构造的。defineClass 方法将一个 byte 数组转换为 Class 类的实例。这种新定义的类的实例可以使用 Class.newInstance 来创建。

类加载器所创建对象的方法和构造方法可以引用其他类。为了确定引用的类,Java 虚拟机将调用最初创建该类的类加载器的 loadClass 方法。

例如,应用程序可以创建一个网络类加载器,从服务器中下载类文件。示例代码如下所示:

   ClassLoader loader = new NetworkClassLoader(host, port);
   Object main = loader.loadClass("Main", true).newInstance();
          . . .
 

网络类加载器子类必须定义方法 findClassloadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法 defineClass 来创建类实例。示例实现如下:

     class NetworkClassLoader extends ClassLoader {
         String host;
         int port;

         public Class findClass(String name) {
             byte[] b = loadClassData(name);
             return defineClass(name, b, 0, b.length);
         }

         private byte[] loadClassData(String name) {
             // load the class data from the connection
              . . .
         }
     }


import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;

import org.junit.Test;

/*
 * 用自己做的类加载器加载指定目录的字节码文件,生成Class对象,进行再得出obj
 * 1技术入口: 利用API中的ClassLoader类的defineClass(String name, byte[] b, int off, int len)生成一个Class对象 
   2为了调用defineClass(),要利用IO把字节码数据加载到一个byte[] b, 然后就可调用defineClass()方法了
 * 
 */
public class MyClassLoader extends ClassLoader {

	public Class MyLoadClass(String name) throws Exception {
		// 利用IO把字节码数据加载到一个byte[] b
		FileInputStream fin = new FileInputStream(name);
		byte buf[] = new byte[512];
		int len = 0;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		while ((len=fin.read(buf)) != -1) {
			bos.write(buf, 0, len);
		}
		bos.close();// 把缓存中的数据全部刷到baout中
		byte b[] = bos.toByteArray();
		// 技术入口,调用父类ClassLoader中的defineClass()方法生成c对象
		Class c = this.defineClass(null, b, 0, b.length);
		return c;
	}

	@Test
	public void test1() throws Exception {
		MyClassLoader loader = new MyClassLoader();
		Class c = loader.MyLoadClass("D:\\a\\A.class");
		Object obj = c.newInstance();
		System.out.println(obj);
		
		ClassLoader loader2=obj.getClass().getClassLoader();
		System.out.println("loader2: "+loader2);
	}
	
	@Test //该测试是反模式: 不同的类加载器加载的类是不能相互转换的,可理解成不同的空间
	public void t2() throws Exception{
		MyClassLoader loader = new MyClassLoader();
		Class c = loader.MyLoadClass("D:\\a\\A.class");
		Object obj = c.newInstance();
		//obj的类加载器是MyClassLoader, 而obj2的类加载器是AppClassLoader
		A obj2 =(A) obj; //WA: 不同的类加载器加载的类是不能相互转换的
		System.out.println(obj2);
		
	}
}

你可能感兴趣的:(java进阶)