运行:
看下结果: com.sun.tools.javac.api.JavacTool class com.text.TankTimeProxy Tank moving.... 2004
Ok,我们要求的功能全部实现了。
5.如果现在我们实现不是一个特定的接口(意思就是不是实现Moveable接口,而是实现的其他接口),那我们怎么办喃?
那我们把接口也当参数传进来
修改代码: //把接口也当做一个参数传进来 public static Object newProxyInstance( Class infc) throws Exception{//把接口也传进去 String methodsString= "";//定义一个变量 Method methods[]=infc.getMethods();//获取方法(反射) for(Method m: methods){ methodsString=methodsString+"@Override"+ " public void "+m.getName()+"() {"+ " long start=System.currentTimeMillis();"+ " t."+m.getName()+"();"+ " long end=System.currentTimeMillis();"+ " System.out.println((end-start));"+ " }"; /*把这个类当成一个string的字符串(源码) 现在我们假设,我们能把这字符串编译,生成类,放在内存,来产生对象 动态代理就是你看不到代理类,你只需要调用一个方法( Proxy的newProxyInstance()方法), 会自动给你返回一个代理类对象,这个对象的产生是由内部动态的生成一段代码,编译完成的*/ //现在我们就来动态的编译这段代码(JDK6,complier API,CGlib,ASM(直接生成二进制的class文件)) String src= "package com.text;"+
"public class TankTimeProxy implements "+infc.getName()+"{"+ "public TankTimeProxy(Moveable h) {"+ " this.h = h;" + " }"+ //" Moveable t;"+ "Moveable h ; " + methodsString + "}"; //获取当前 系统目录(就是项目根目录) String fileName=System. getProperty("user.dir")+ "/src/com/text/TankTimeProxy.java" ; //System.out.println(fileName); File f= new File(fileName); FileWriter writer= new FileWriter(f); writer.write(src); writer.flush(); writer.close(); //看是否生成代码,右键项目,刷新就OK了 /*****************编译********************/ //这句话的作用就是获取系统当前默认的编译器(其实就 javac) JavaCompiler compiler=ToolProvider. getSystemJavaCompiler(); //拿到java的编译器 System. out.println(compiler.getClass().getName()); StandardJavaFileManager filemag=compiler.getStandardFileManager( null, null, null);//文件的管理器 Iterable untis= filemag.getJavaFileObjects(fileName);//找到文件,把文件放在 Iterable中 CompilationTask t=compiler.getTask( null, filemag, null, null , null, untis );//编译文件任务 t.call(); //编译文件 filemag.close(); //编译之后,我们打开window show View 选择Navigator(这个可以看到类详细的变化,就是看得到class文件的产生) /********************load 到内存,和创建对象*************************/ //如果要使用class.loader,就必须保证这个class在 classpath的路径下 //因此我们要用一个特殊的loader URL [] urls= new URL[]{ new URL("file:/"+System. getProperty( "user.dir")+"/src" )}; URLClassLoader ul= new URLClassLoader(urls);//这里需要一个数组地址 Class c=ul.loadClass("com.text.TankTimeProxy" );//把类加到内存 System. out.println(c); //反射来创建对象 Constructor ctr= c.getConstructor(Moveable. class ) ;//获取构造方法 Object m=ctr.newInstance( h); return m; }
}
即使这样,我们还是遇到一个问题,那就是每个接口的方法不是一样的,有的多,有的少,这样有怎么办喃?
这样就能保证,即使方法不统一,我也可以让每个方法都执行计时功能哦
6.现在我们来解决下一个问题,我们每个接口都是来实现计时功能的?显然不是,那肯定还有其他功能三
那我们怎么样来做,才可以是我们想实现什么功能,就实现什么功能喃?动态代理?
我们按照一贯的做法,继续把功能也传经来。。
看代码:
public class Proxy { //这个类的作用就是用来产生新的代理类 public static Object newProxyInstance( Class infc,InvocationHandler h) throws Exception{//把接口也传进去 String methodsString= ""; Method methods[]=Moveable. class.getMethods(); for(Method m: methods){ /*methodsString=methodsString+"@Override"+ " publi