Java中的反射机制
2017-06-08 20:56
190 查看
Java中的反射是一种强大的工具,可以创建灵活的代码,这些代码可以在运行时装配,无须在组件中进行链接。反射允许在编写与执行时,使程序代码能接触到装载到JVM中类的内部信息。Java中的类的反射Reflectio是Java程序对自身进行检查或者‘自审’,并且能直接操作程序内部的属性,实际上它的应用不多,但在框架开发中会经常用到,其他的程序设计中也根本本不存在这样的反射机制。下面是一些常用的代码片段:
Java中反射机制主要是应用在动态代理上,这里面分为静态代理和动态代理区别在于,
静态代理:代理类和目标对象的类都是在编译期间确定下来的,而且每个代理只能为一个接口服务,这样在开发过程中必然产生过多的代理,不利于程序的扩展,于是产生了动态代理。
下面来看动态代理的实现:
这里在举一个动态代理的AOP的典例:
package com.java24hours.reflection; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.junit.Test; import com.java24hours.Person; public class TestReflection { //在反射以前,创建对象并调用其方法属性 @Test public void test1() throws Exception { Person p = new Person(); p.setName("test"); p.setAge(27); System.out.println(p); p.show(); p.display("HK"); } //有了反射之后,做同样的事情这么来做 @Test public void test2() throws Exception { Class<Person> clazz = Person.class; //1.创建clazz对应的运行时类Person,用的是clazz.newInstance() //这里的clazz.newInstance()实际上是调用的是Person类的无参构造器 Person p = clazz.newInstance(); System.out.println(p); //2.然后在调用,调用的时候先用clazz.getField(“属性名”)的方法来获取public作用域的属性,然后再往对象里面设值 Field f1 = clazz.getField("name"); f1.set(p, "test2"); System.out.println(p); //获取private作用域的属性值方法比一样,用上面的方法获取不到 //首先应该获取声明的属性 Field f2 = clazz.getDeclaredField("age"); //将访问权限改为true f2.setAccessible(true); f2.set(p, 20); System.out.println(p); //3.通过反射调用运行类的方法,首先获取方法 Method m1 = clazz.getMethod("show"); //然后调用方法,没有形参的直接m1.invoke(p); m1.invoke(p); //调用有形参的方法,clazz.getMethod时需要指明参数的类型 Method m2 = clazz.getMethod("display", String.class); //有形参的话m2.invoke(p,形参);传入形参 m2.invoke(p, "HK"); } /* * java.lang.Class是反射的源头 * 创建的类通过编译(javac.exe),生成对应点.class文件,之后我们使用的java.exe加载(JVM的类加载器) * .class文件,此。class文件加载到内存以后,就是一个运行时类,放在缓存中,那么这个运行时类本身就是一个Class类 * 1.每个运行时类只加载一次 * 2.有了class实例以后才能进行如下操作 * 1)创建对应的运行时类的对象 * 2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类..) * 3)调用对应的运行时类的指定的结构(属性、方法、构造器) * 4)反射的应用:动态代理 */ @Test public void test3() { Person p = new Person(); //得到运行时类 Class myclass = p.getClass(); System.out.println(myclass); } //如何获取Class的实例 @Test public void test4() throws Exception { //方法1 Class clazz = Person.class; System.out.println(clazz.getName()); System.out.println(String.class.getName()); //方法2.通过运行时类的对象获取 Person p = new Person(); Class clazz2 = p.getClass(); System.out.prin 4000 tln(clazz2.getName()); //方法3.通过Class的静态方法 String classNme = "com.java24hours.Person"; Class clazz3 = Class.forName(classNme); System.out.println(clazz3.getName()); //方法4.用类加载器 ClassLoader cl = this.getClass().getClassLoader(); Class clazz4 = cl.loadClass(classNme); //利用类加载器来加载配置文件 // InputStream is = cl.getResourceAsStream("xx"); // Properties pro = new Properties(); // pro.load(is); // String 属性名 = pro.getProperty("xx配置文件的属性名"); System.out.println(clazz4.getName()); } //获取对应的运行时类的属性 @Test public void testField() { Class clazz = Person.class; //getFields获取该类及其父类中权限为public的属性 Field[] fields = clazz.getFields(); System.out.println(fields[0]); //2.获取该类本身类中的属性用如下的方法getDeclaredFields(), Field[] fields2 = clazz.getDeclaredFields(); for(int i=0;i<fields2.length;i++) { System.out.println(fields2[i].getName()); } } //权限修饰符 变量类型 变量名 @Test public void test5() { Class clazz = Person.class; Field[] fields = clazz.getDeclaredFields(); for(Field f: fields) { //1.获取每个属性的权限修饰符 int i = f.getModifiers(); //将权限的索引转变成对应的权限名字 String m = Modifier.toString(i); //2.获取每个属性的变量类型 String type = f.getType().getName(); //3.获取每个属性 的变量名 String name = f.getName(); System.out.println(m + "-" + type + "-" + name); } } //获取方法的一些属性 @Test public void test06() { Class clazz = Person.class; //获取运行时类及其父类中public权限的方法 Method[] methods = clazz.getMethods(); for(Method m : methods) { System.out.println(m.getName() + ": " + Modifier.toString(m.getModifiers()) ); } System.out.println("==============="); //getDeclaredMethods是获取该类的中所有方法 Method[] methods2 = clazz.getDeclaredMethods(); for(Method m : methods2) { //获取注解 Annotation[] ann = m.getAnnotations(); for(Annotation a : ann) { System.out.println(a); } //获取形参列表 Class rt = m.getReturnType(); //获取异常类型 System.out.println("方法名:" + m.getName() + "-权限修饰符:" + Modifier.toString(m.getModifiers()) + "-注解:" + ann + "-返回值类型:" + rt); } System.out.println("==================="); } }
Java中反射机制主要是应用在动态代理上,这里面分为静态代理和动态代理区别在于,
静态代理:代理类和目标对象的类都是在编译期间确定下来的,而且每个代理只能为一个接口服务,这样在开发过程中必然产生过多的代理,不利于程序的扩展,于是产生了动态代理。
这里注意一下,正常情况下,被代理对象是一个实现一个抽象接口的类,代理对象是一个实现该抽象接口的代理类,而动态代理是一个实现了InvocationHandler接口的类。
下面是一段静态代理的一个实例:/** * 静态代理模式 * @author Weiguo Liu * */ //接口 interface ClothFactory { void productCloth(); } //被代理类 class NikeClothFactory implements ClothFactory { @Override public void productCloth() { System.out.println("Nike生产衣服"); } } //代理类,这里实现了接口,很明显他只能服务于ClothFactory这个接口 class ProxyFactory implements ClothFactory { //声明的时候声明成ClothFactory ClothFactory cf; //创建代理类,传入的是一个被代理类的对象 public ProxyFactory(ClothFactory cf) { this.cf = cf; } @Override public void productCloth() { System.out.println("代理类执行"); cf.productCloth(); } } public class TestSaticProxy { public static void main(String[] args) { //创建被代理的对象 NikeClothFactory nike = new NikeClothFactory(); //创建代理对象,因为是静态代理,所以这个代理只能为NikeClothFactory这一个对象做代理, //当创建新的对象时,将又要创建代理对象,如果被代理的对象很多的话,就要创建很多的代理对象,很不方便 ProxyFactory pf = new ProxyFactory(nike); pf.productCloth(); } }
下面来看动态代理的实现:
package com.java24hours.reflection; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理 * @author Weiguo Liu * */ //被代理类 interface Subject { void action(); } //代理类 class RealSubject implements Subject { @Override public void action() { System.out.println("代理类执行"); } } //创建动态代理类,注意动态代理都要实现一个InvocationHandler的接口 class MyInnvocationHandler implements InvocationHandler { //实现了接口的被代理类的对象声明,这里由于是因为不能确定被代理类的对象的类,所以同一用Object类,在调用的时候 //根据被代理类的类型做适当的强转即可 Object obj; //给被代理对象实例化,返回一个代理类的对象 public Object blind(Object obj) { this.obj = obj; //三个参数意义(被代理类的类加载器, 被代理类实现的接口, 实现InvocationHandler的类,即动态代理的类) return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); } //当通过代理类的对象发起对被重写的方法调用时,都会转换为如下的invoke方法的调用,即调用具体接口中的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //调用被代理对象的方法,获取返回对象 Object rv = method.invoke(obj, args); return rv; } } public class TestDynamicProxy { public static void main(String[] args) { //被代理对象 RealSubject rs = new RealSubject(); //创建实现InnvocationHandler接口的动态代理类对象 MyInnvocationHandler mi = new MyInnvocationHandler(); //调用blind()方法,将被代理对象绑定到代理对象上,即设置代理对象 Object obj = mi.blind(rs); //根据具体的被代理对象做强转,都是强转成对象的服务接口,这里的sub就是转成Subject接口对象 Subject sub = (Subject)obj; //调用接口方法 sub.action(); NikeClothFactory nike = new NikeClothFactory(); obj = mi.blind(nike); ClothFactory pf = (ClothFactory)obj; pf.productCloth(); } }
这里在举一个动态代理的AOP的典例:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理与AOP面向切面编程 * @author Weiguo Liu * */ //创建接口 interface Human { void info(); void fly(); } //创建实现接口的被代理类 class SuperMan implements Human { @Override public void info() { System.out.println("我是超人"); } @Override public void fly() { System.out.println("我可以飞"); } } class HumanUtil { public void method1(){ System.out.println("====method1===="); } public void method2() { System.out.println("====method2====="); } } //创建实现Invocatio f8ec nHandler接口的动态代理类 class MyInvocationHandler implements InvocationHandler { Object obj; public void setObject(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { HumanUtil hu = new HumanUtil(); hu.method1(); Object rv = method.invoke(obj, args); hu.method2(); return rv; } } //代理类 class MyProxy { public static Object getProxyInstance(Object obj) { MyInvocationHandler handler = new MyInvocationHandler(); handler.setObject(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); } } public class TestAOProxy { public static void main(String[] args) { SuperMan man = new SuperMan(); Object obj = MyProxy.getProxyInstance(man); Human hu = (Human)obj; hu.info(); System.out.println("888888888888888888"); hu.fly(); System.out.println("===================="); NikeClothFactory nf = new NikeClothFactory(); ClothFactory cf = (ClothFactory)MyProxy.getProxyInstance(nf); cf.productCloth(); } }
相关文章推荐