JavaSE学习笔记——反射
2020-03-04 本文已影响0人
funOfFan
- Java Reflection
- 反射是动态语言实现的关键
- 发射机制允许在执行期间借助Reflection API取得任何类的内部信息,
并直接操作任意对象的内部属性及方法
- Java反射机制提供的功能
- 在运行时候判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
- 如何创建Class的实例(重点)
/** * java.lang.Class:是反射的源头 * 我们创建了一个类,通过编译,生成对应的.class文件, * 之后使用java.exe加载此文件(JVM的类加载器完成) * 此文件加载到内存以后,就是一个运行时类,存放在缓存区 * 那么该运行时类本身就是一个大的Class的实例 */ //1.调用运行时类本身的.Class属性 Class c1 = Person.class; //2. 通过运行时类的对象获取 Person p = new Person(); Class c3 = p.getClass(); //3.通过Class的静态方法获取 String class_name = "learning_reflect.Person"; Class c4 = Class.forName(class_name); //4.通过类的加载器 ClassLoader cl = this.getClass().getClassLoader(); Class c5 = cl.loadClass(class_name);
- 有了Class类实例之后,可以做什么?
- 从Class类实例,创建运行时类的对象
//方法一,调用Class类的newInstance方法,直接创建运行时对象 Class clazz = Class.forname("learning_reflect.Person"); Object obj = clazz.newInstance(); Person p = (Person) obj; //方法二,调用指定的构造器,创建运行时对象 Class clazz = Person.Class; Constructor cons = clazz.getDeclaredConstructor(String.Class,int.Class); cons.setAccessible(true); Person p = (Person)cons.newInstance("Tom", 10);
- 获取对应的运行时类的完整类结构:属性、方法、构造器、所在包、父类、接口、
泛型、注解、异常、内部类
//举例如下 //getMethods方法获取运行时类及其父类中所有声明为public的方法 Method[] m1 = clazz.getMethods(); //getDeclaredMethods方法获取运行时类自身声明的所有方法,但不包含父类的 Method[] m2 = clazz.getDeclaredMethods();
- 可以调用运行时类中指定的结构(方法、属性、构造器等)
//调用指定非静态方法 Class clazz = Person.class; Method m1 = clazz.getMethod("show"); Person p = (Person) clazz.newInstance(); Object returnValue = m1.invoke(p);//This is a person //调用指定静态方法 Method m3 = clazz.getMethod("info"); m3.invoke(Person.class); //调用指定构造器 String classname = "learning_reflect.Person"; Class clazz = Class.forName(classname); Constructor cons = clazz.getDeclaredConstructor(String.class, int.class); cons.setAccessible(true); Person p = (Person) cons.newInstance("罗维", 20);
- 动态代理-反射的应用,体会反射的动态性
- 代理设计模式的原理:
- 使用一个代理将对象包装起来,然后用该代理取代原始对象,
任何对原始对象的调用都要通过代理,
代理决定是否以及何时将方法调用转移到原始对象上。 - 静态代理:要求被代理类和代理类同时实现相应的一组接口;
通过代理类的对象调用重写接口的方法时,实际上执行的是被代理类的同样的方法。 - 动态代理:在程序运行时,根据被代理类及其实现的接口,动态的创建一个代理类,
当调用代理类的实现的抽象方法时,就发起对被代理类同样方法的调用。- 提供一个实现了InvocationHandler接口实现类,并重写其invoke方法
- Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),h);
(此处obj为被代理类对象,h为实现了InvocationHandler的一个对象)
- 使用一个代理将对象包装起来,然后用该代理取代原始对象,
- 动态代理与AOP
package learning_reflect; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Human { void info(); void fly(); } class SuperMan implements Human { @Override public void fly() { System.out.println("Here comes Clerk"); } @Override public void info() { System.out.println("I am Super Man"); } } class HumanUtil { public void method1() { System.out.println("===方法一==="); } public void method2() { System.out.println("===方法二==="); } } class SelfInvocationHandler 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 h = new HumanUtil(); h.method1(); Object returnVal = method.invoke(obj, args); h.method2(); return returnVal; } } class MyProxy { //动态地创建一个代理类的对象 public static Object getProxyInstance(Object obj) { SelfInvocationHandler handler = new SelfInvocationHandler(); handler.setObject(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); } } public class TestAOP { public static void main(String[] args) { SuperMan man = new SuperMan(); Object obj = MyProxy.getProxyInstance(man); Human sm = (Human) obj; sm.info(); System.out.println(); sm.fly(); } }