黑马程序员_【总结】_ 高新_5_类加载器

类加载器


---------- android培训 java培训 、期待与您交流! ---------- 

---------------------------------------------------------------------------------------------------------------------------------------------
类加载器、自定义类加载器
1、类加载器就是加载类的工具

2、类加载器:BootStrap<<<ExtClassLoader<<<AppClassLoader

3、类加载器本身也是Java类    顶级类加载器BootStrap 不是java类 getName() 显示为null

4、类名.class.getClassLoader().getClass().getname();获取类加载器名称。

5、ClassLoader.loaderClass(); 方法指定类加载器加载某个类

6、委托机制就是先让父类找,没找到自己找,不会让儿子找

7、自定义类加载器必须 继承ClassLoader并覆盖findClass()   这也是【 模版设计模式】

8、最简单的加密   ops.write(ben ^ 0xff);  加密,解密都是该方法

9、被加载加密的类,一定要用完成的路径,但完整的路径不是硬编码,而是运算出来的。

10、defineClass 方法将一个 byte 数组转换为 Class 类的实例  
----------------------------------------
类加载器:就是加载类的工具。


JAVA虚拟机中可以安装多个类加载器, 系统默认三个主要的类加载器,每个类负责加载特定位置的类。
 BootStrap-------ExtClassLoader------AppClassLoader       classpath指定的类加载器
    父级                                       子集                                        子子集     
类加载器也是JAVA类,JAVA类的类加载器本身也要被类加载其加载。
显然必须有第一个类加载器不是jAVA类,这正是BootStrap;
所以类加载器是用BootStrap加载的。
Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时
,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。 




类名.class.getClassLoader().getClass().getname();获取类加载器名称。


类加载器是类的加载工具,主要有三种类加载器 
一种是BootStrap  一种是ExtClassLoader  一种是 AppClassLoader 
自定义类加载器:
首先,类加载器必须要继承ClassLoader。 覆盖findClass
//1类加载器的树状结构 :   BootStrap<<ExtClassLoader<<AppClassLoader
	public static void Test1(){		
		//1获取ClassLoaderTest类的类加载器
		ClassLoader loader = ClassLoaderTest.class.getClassLoader();
		while(loader!=null){
			//2 获取 该类加载器的字节码,然后获取其名称
			System.out.println(loader.getClass().getName());
			//3 获取 该类加载器的父类
			loader = loader.getParent();
		}
		System.out.println(loader);
	}
BootStrap: 显示为  null

类加载器的委托机制
一、类加载器加载一个类到底用那个类加载器?
1、类加载器先加载线程中第一个类
2、如果A应用了B,Jav虚拟机会用加载A的类加载器来加载B
3、ClassLoader.loaderClass(); 方法指定类加载器加载某个类
二、每个类加载器加载类时,会先委托给上级类加载器,当所有的祖宗级类加载器没有加载类
则回到发着者类加载器,如果还加载不了,则抛出异常:ClassNotFoundException
是不会再去找发起者的儿子类。
----------------------------------

【自定义类加载器】
创建ABC 三个类   A为 自定义类加载器  B为 被加载的类  C 为测试类
一     A部分 为类加密


  【当A- 6  完成时候,运行MyClassLod_A  给该类主函数传递2个参数】
  E:\Yunyao\heiMa\javaenhance\bin\com\itheima\day5\MAttachment_B.class cypherlib
  被加密类的绝对路径                                                                                     新的文件夹
  1、用加密后的Class文件替换掉原文件则报错,Java的类加载器无法解密加载



  二  A 的B部分 为 继承ClassLoader 覆盖findClass 达到自定义类加载器的目的
 
覆盖findClass  接收2个参数:
  new MyClassLod_A("cypherlib").loadClass("MAttachment_B");
  //把自定义类加载器挂到系统类加载器作为子类       //然后放入需要加载的类
 
  1、父类首先去找类,找到了,但是无法解密加载,所以报错
  2、 删掉当前文件夹的MAttachment_B.class 文件,让父类类加载器找不到,
  3、这个时,就用调用子类,也就是自定义的类加载器,并加载加密后的MAttachment_B.class    
  4、解密成功,类加载成功,打印结果。

注意: 根据AB 两部分的路径来看,一定要用完成的路径,但完整的路径不是硬编码,而是运算出来的。

注意:覆盖findClass()  能达到自定义类加载器,    模版设计模式。

分三个类
【自定义A】
/A-0 创建MyClassLod_A
public class MyClassLod_A extends ClassLoader{

	 * 运行该类时, 有两个参数,
	 * 1 要加密的类的绝对路径,
	 * 2 相对文件夹名 这里是cyhperlib
	 * ---
	 * A- 自定义类加载器加载并加密类:MyCLAttachmentB
	 * 1、建立MyCLoderTestA
	 * 2、建立MyCLAttachmentB 附件类
	 * 		1、继承Date
	 * 		2、覆盖toString()方法即可
	 * 3、创建  测试类CL_testC
	 * B- 解密并打印 自定义类加载并加密的Class文件

	public static void main(String[] args) throws Exception
	{
		//【A】
		//A-2-0 接收 类的绝对路径、新文件夹的名字
		String srcPath = args[0];
			//要加载的类的绝对路径
			//E:\Yunyao\heiMa\javaenhance\bin\com\itheima\day5\MyCLAttachmentB.class
		String dirName = args[1];// 新的路径文件夹名   cypherlib
		//A-2-1通过类的绝对路径--获取到类的类名.Class 
		String dirFileName =srcPath.substring(srcPath.lastIndexOf('\\')+1);//截取加载类的名称
		//A-2-2 组合成为 新的相对路径   (文件夹在本项目所以是相对路径)
		String desPath = dirName+ "\\" + dirFileName;// 获得 文件名\\加载后的类名(原类名)
			//System.out.println(dirPath);
		//A-3  读取源文件--写入新文件。
		FileInputStream fis = new FileInputStream(srcPath);
		FileOutputStream fos = new FileOutputStream(desPath);	
		//A-4 完成加密-copy 
		cypher(fis,fos);
		fis.close();
		fos.close(); 
		
		//A-5启动测试类:CL_testC 进行测试  System.out.println(new MyCLAttachmentB().toString());
	}

	// cyhper  加密,解密方法。 //A-1 加密、解密,接收一个输入流 、输出流
	A-1  cypher 加密\解密  --方法
	private static void cypher(InputStream ips,OutputStream ops) throws Exception
	{
		int ben = -1 ;
		while((ben = ips.read()) != -1){
			ops.write(ben ^ 0xff);
		}
	}
	//【B】
	private String classDir;
	//在项目目录下创建文件夹:cypherlib
	//B-7     覆盖findClass 方法 
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException
	{
		//B-9         获取  文件\\文件名.class
		String classFileName = classDir + "\\" + name+ ".class";
		// 当传递的为包命.name时
		//String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1)+ ".class";
		FileInputStream ips = null;
		ByteArrayOutputStream bos = null;//操作字节数组对象
			try {
				//B-9-1 定义 输入流, 和字节数输出流   为什么是字节数初六defineClass 方法需要
				ips = new FileInputStream(classFileName);
				bos = new ByteArrayOutputStream();
				System.out.println("111");
				//B-9-2读取文件并【解密】
				cypher(ips,bos);
				//B-9-3   转换为字节数组
				byte[] bytes = bos.toByteArray();
				ips.close();
				System.out.println("2222");
				//B-9-4    返回      ---数组转换为Class实例 
				return defineClass(bytes,0,bytes.length);
				//return defineClass(name,bytes,0,bytes.length);
			} 
			catch (Exception e) {}
			//委托给父类。
		return super.findClass(name);
	}
	//B-8 -1构造函数 
	MyClassLod_A(){}
	//B--8-2   构造函数2  并生成 private String classDir; 
	MyClassLod_A(String classDir){
		this.classDir = classDir;
	}
}
//defineClass 方法将一个 byte 数组转换为 Class 类的实例

 第一个类,完成了,对类的加密、类加载器、解密的功能

下面是被加载的类,该类只需要覆盖toString 方法,作为测试
  【自定义B】
 import java.util.Date;
//A-0 创建MAttachment_B 覆盖toString方法
public class MAttachment_B extends Date {
	public String toString(){
		return "测试测试  MyCLAttachmentB 测试测试。";
	}
}
//E:\Yunyao\heiMa\javaenhance\bin\com\itheima\day5\MAttachment_B.class cypherlib
 
  【自定义C】
测试类分   两部分
第一部分是 对加密文件的测试
二部分 则是对  加密的类进行加载的测试
import java.util.Date;

public class cl_Test_C {
	//A- 5  MyCLoderTestA 的测试类
	public static void main(String[] args) throws Exception {
			
		//A-5-1
		//System.out.println(new MAttachment_B().toString());
					//A-6-1【MAttachment_B.class  被替换后报错】 注销该打印语句
		         
		//A- 6 把加密后的MyCLAttachmentB.class 覆盖掉原来的MyCLAttachmentB.class  
		//并运行,发现,原来的加载器是无法加载 自定义类加载器加密的文件,必须用自定义的类加载器才能加载解密。
		System.out.println("------A-   end   -------\nB start:");
		//B-10   
		 			//把自定义类加载器挂到系统类加载器作为子类       //然后自定义加载该类
		Class clazz = new MyClassLod_A("cypherlib").loadClass("MAttachment_B");
		//MyCLAttachmentB是不可以的, JVM会再次对该类进行加载,
		//MyCLAttachmentB mb = (MyCLAttachmentB)clazz.newInstance();
			//加载成功后,用这个字节码创建一个对象 
		System.out.println("----2222--------");
		//B-10-1  date 接收 实例对象 并打印
		Date date = (Date)clazz.newInstance();
		System.out.println("---333-------");
		System.out.println(date);
		// 这时候报异常 ClassFormatError 因为父类的类加载器找当了当前目录下的
		//	MAttachment_B.class  是被替换后的 加密文件 自然是加密不了的,  
		// 现在【把 当前目录下的MAttachment_B 文件给删掉】,父类 类加载器找不到后会调用子类类加载器,
		//也就是我们定力的类加载器 进行加载,自然而然  就搞定。
	}	
}

-----------------------------------------------------







---------------------------------------------------------------------------------------------------------------------------------------------
---------- android培训、 java培训 、期待与您交流!----------


----------------------------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值