黑马程序员_基础加强path3

来源:互联网 发布:apktool mac 编辑:程序博客网 时间:2024/05/17 04:58

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

1 类加载器:

类加载器之间的父子关系和管辖范围图:

类加载器的委托机制:
当java虚拟机加载类时,到底用哪个类加载器?
首先当前线程的类加载器去加载线程中的第一个类。
如果类A引用了类B,那么java虚拟机将使用加载类A的类加载器去加载类B。
还可以直接调用ClassLoader.loaderClass()方法来指定某个类加载器去加载。
类加载器的加载顺序:
每个类加载器加载时,又委托给其上级的类加载器。
当所有祖宗类加载器没有加载到该类,则回到发起者类加载器,还加载不到,则抛出ClassNoFoundException,
不是再找发起者类加载器和儿子,因为没有getChild方法。——从上到下的加载。
自定义类加载器:
工作机制:
父类——>loadClass/findClass()/得到class文件的内容转换成字节码—>difineClass()/将一个 byte 数组转换为Class 类的实例。
实现步骤:
自定义的类加载器必须继承ClassLoader ,覆盖findClass方法,覆盖difineClass()方法。
用自定义加载类实现加密及解密-难!查看视频及源文件 MyClassLoader.class

 练习对一个类进行加密和解密使用:

 需要加密的类:

package jichujiaqiang;
import java.util.Date;
public class ClassLoaderAttachment extends Date {//继承Date是为了方便解密后创建对象使用。
 public String toString(){
  return "hello,itcast";
 }
}
对类进行加密:

import java.io.*;
public class MyClassLoader extends ClassLoader{
 public static void main(String[] args)throws Exception {
  
 String srcPath =  args[0];//输入需要加密类的绝对地址
 String destDir = args[1];//输入加密后类的存放目录

 FileInputStream fis =new FileInputStream(srcPath);
 String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
 String destPath = destDir+"
\\"+destFileName;//  获取加密后类的绝对地址
 FileOutputStream fos =new FileOutputStream(destPath);//F5刷新一下,不然没有
 cypher(fis, fos);//调用对类进行加密的方法

//关闭资源 

fis.close();
 fos.close();
 }
 private static void cypher(InputStream ips,OutputStream ops)throws Exception {//类进行加密的方法
  int b =-1;
  while((b=ips.read())!=-1){
   ops.write(b^0xff);//加密操作
  }
 }
 private String classDir;//加密后类的相对目录

 public MyClassLoader(){}
 public MyClassLoader(String classDir){
  this.classDir=classDir;
 }
 @SuppressWarnings("deprecation")
 @Override//复写findClass方法,对加密类进行解密。
 protected Class<?> findClass(String name) throws ClassNotFoundException {
  String classFileName = classDir+“\\”+name+".class";//获取加密类的相对地址

  try {
   FileInputStream fis =new FileInputStream(classFileName);
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   cypher(fis, bos);//解密
   fis.close();
   byte[] bytes =bos.toByteArray();
   return defineClass(bytes, 0, bytes.length);//byte 数组转换为Class 类的实例。
  } catch (Exception e) {
   e.printStackTrace();
  }
  return null;
 }
}

如何使用加密后的类:

package jichujiaqiang;

import java.util.Date;

public class ClassLoaderTest {
public static void main(String[] args)throws Exception {
 //System.out.println(new ClassLoaderAttachment().toString()); 加密的,读不了
 Class<?> clazz  = new MyClassLoader("itcastlib").loadClass("jichujiaqiang.ClassLoaderAttachment");//对类进行解密
 Date d1 =(Date)clazz.newInstance();//创建解密后类的构造方法
 System.out.println(d1);

}
}

2 代理:

 

 代理构架图:

动态代理技术:

JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。

JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。

 CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以如果要为一个没有实现接口的类生产动态代理类,那么可以使用CGLIB库。

代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标或结果外,还可以在代理方法中如下四个位置加上系统功能代码:

1,在调用目标方法前。

2,在调用目标方法后。

3,在调用目标方法前后。

4,在处理目标方法异常的catch块中。 

例子:

Collection proxy3 =(Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),
    new Class[]{Collection.class},
    new InvocationHandler() {
     ArrayList target =new ArrayList();
     //(Object proxy, Method method, Object[] args):proxy表示调用的对象,method表示对象里的调用方法,args表示调用方法时传递的参数。
     public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {
      long beginTime = System.currentTimeMillis();//添加功能
      Object reVal = method.invoke(target,args);
      long endTime = System.currentTimeMillis();//添加功能
      System.out.println( method.getName()+"running time of "+(endTime-beginTime));/添加功能
      return reVal;//作为proxy3.add("flx");这个方法的返回值。
     }
    });
  
  Object reVal =proxy3.add("flx");
  proxy3.add("lbm");
  System.out.println(proxy3.size());

 

 代理的工作原理:

 

如何让动态生成的类成为目标类的代理:

例子:(由上面代码改编)

private static Object getProxy(final Object target,final Advice advice){//传递2个参数,一个是操作目标,一个是扩展的功能
  Object proxy3 = Proxy.newProxyInstance(target.getClass().getClassLoader(),//创建动态类
   target.getClass().getInterfaces(),
   new InvocationHandler() {   
    public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
     advice.beforeMethod(method);//目标功能前需要扩展的代码
     Object reVal = method.invoke(target,args);
     advice.afterMethod(method);//目标功能后需要扩展的代码
     return reVal;
    }
   });
  return proxy3;
 } 

这样只需要自己写一个advice,就可以实现需要扩展的功能。

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

 

 详细请查看:http://edu.csdn.net/heima/