Java的反射机制
一.Java Reflection
Reflection(反射)是被视为动态语言的关键, 反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息, 并能直接操作任意对象的内部属性及方法
1.Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理(前边讲interface时有静态代理)
2.反射相关的主要API:
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法
3.初识反射
通过反射在运行时构造一个类的对象, 调用方法和成员变量
One More Thing 👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class TestReflection { public static void main(String[] args) throws Exception{ Class<Person> clazz = Person.class; Person p = clazz.newInstance(); System.out.println(p); Field f1 = clazz.getField("name"); f1.set(p, "LiuDehua"); Field f2 = clazz.getDeclaredField("age"); f2.setAccessible(true); f2.set(p, 21); System.out.println(p); Method m1 = clazz.getMethod("show"); m1.invoke(p); Method m2 = clazz.getMethod("display", String.class); m2.invoke(p, "CHINA"); } } class Person{ public String name; private int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = age; } public void show() { System.out.println("我是一个人"); } public void display(String nation) { System.out.println("我的国籍是:"+nation); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
|
二.反射的源头Class类
- 源文件经过编译(javac.exe)以后, 得到一个或多个.class文件, .class文件经过运行(java.exe)这步, 就需要进行类的加载(通过JVM的类加载器), 加载到内存的缓存中. 每一个放入缓存中的.class文件就是一个Class的实例!
- Class的一个对象, 对应着一个运行时类(每一个运行时类只加载一次). 相当于一个运行时类本身充当了Class的一个实例.
- 每一个对象, 都能通过它的getClass()方法, 得到它对应的运行时类
- 通过Class的实例得到一个运行时类中的完整结构(属性, 方法, 构造器, 内部类, 父类, 所在包, 异常, 注解, … )
1.创建Class类的对象
- 通过运行时类本身的.class属性获取
- 通过运行时类对象的getClass()方法获取
- 通过Class类的静态方法Class.forName(String path)方法
- (了解)通过类加载器(ClassLoader)的对象的loadClass(String path)方法
ClassLoader的应用:
One More Thing 👇
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static void main(String[] args){ ClassLoader loader = this.getClass().getClassLoader(); InputStream is = loader.getResourceAsStream("com\\crd\\reflection\\jdbc.properties");
Properties pros = new Properties(); pros.load(is); String name = pros.getProperty("user"); System.out.println(name); String password = pros.getProperty("password"); System.out.println(password); }
|
有了Class的实例后, 可以做什么?
- 创建对应的运行时类的对象(重点)
- 获取对应运行时类完整的类的结构: 属性、方法、构造器、包、父类、接口、泛型、注解、异常、内部类…
- 调用对应的运行时类中指定的结构(某个指定的属性、方法、构造器)(重点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Method[] m1 = clazz.getMethods();
Method[] m2 = clazz.getDeclaredMethods();
@Test public void test1(){ Class clazz = Person.class; Type type = clazz.getGenericSuperclass(); ParameterizedType param = (ParameterizedType)type; Type[] arr = param.getActualTypeArguments(); for(int i = 0;i < arr.length;i ++){ System.out.println((Class)arr[i]); } }
|
注意: 调用getDeclaredXxx()方法后, 建议要调用一下, setAccessible(true);
2.创建运行时类的对象
- 使用Class实例的newInstance()方法创建, 该方法默认调用运行时类的空参构造器(该构造器需要足够的权限)
- 故, 创建类时建议创建一个空参的构造器
- 也能用指定的构造器创建运行时类的对象
1 2 3 4 5 6 7 8
| @Test public void test() throws Exception{ Class clazz = Person.class; Constructor cons = clazz.getDeclaredConstructor(String.class,int.class); cons.setAccessible(true); Person p = (Person)cons.newInstance("Tom",10); System.out.println(p); }
|
三.动态代理
- 代理设计模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上
- 之前提到过静态代理, 特征是代理类和被代理类都是在编译期间确定下来, 不利于程序的扩展. 同时, 每一个代理类只能为一个接口服务, 这样一来程序开发中必然产生过多的代理.
- 最好可以通过一个代理类完成全部的代理功能
静态代理: 要求被代理类和代理类同时实现相应的一套接口; 通过代理类的对象调用重写接口的方法时, 实际上执行的是被代理类的同样的方法的调用.
One More Thing 👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| interface ClothFactory{ void productCloth(); }
class NikeClothFactory implements ClothFactory{ public void productCloth(){ System.out.println("Nike工厂生产衣服"); } }
class ProxyFactory implements ClothFactory{ ClothFactory cf; public ProxyFactory(ClothFactory cf){ this.cf = cf; } public void productCloth(){ System.out.println("代理类开始代理"); cf.productCloth(); } } public class TestFactory{ public static void main(String [] args){ NikeClothFactory nike = new NikeClothFactory(); ProxyFactory proxy = new ProxyFactory(nike); proxy.productCloth(); } }
|
动态代理: 在程序运行时, 根据被代理类及其实现的接口, 动态的创建一个代理类. 当调用代理类的实现的抽象方法时, 就发起对被代理类同样方法的调用.
One More Thing 👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| interface Subject { void action(); }
class RealSubject implements Subject { public void action() { System.out.println("我是被代理类, 记得要执行我哦!么么~~"); } } class MyInvocationHandler implements InvocationHandler { Object obj; public Object blind(Object obj) { this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object returnVal = method.invoke(obj, args); return returnVal; } } public class TestProxy { public static void main(String[] args) { RealSubject real = new RealSubject(); MyInvocationHandler handler = new MyInvocationHandler(); Object obj = handler.blind(real); Subject sub = (Subject)obj; sub.action(); NikeClothFactory nike = new NikeClothFactory(); ClothFactory proxyCloth = (ClothFactory)handler.blind(nike); proxyCloth.productCloth(); } }
|
1.动态代理与AOP
One More Thing 👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| interface Human { void info(); void fly(); }
class SuperMan implements Human { public void info() { System.out.println("我是超人!我怕谁!"); } public void fly() { System.out.println("I believe I can fly!"); } } class HumanUtil { public void method1() { System.out.println("=======方法一======="); } public void method2() { System.out.println("=======方法二======="); } } 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 h = new HumanUtil(); h.method1(); Object returnVal = method.invoke(obj, args); h.method2(); return returnVal; } } 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 TestAOP { public static void main(String[] args) { SuperMan man = new SuperMan(); Object obj = MyProxy.getProxyInstance(man); Human hu = (Human)obj; hu.info(); System.out.println(); hu.fly(); NikeClothFactory nike = new NikeClothFactory(); Object obj1 = MyProxy.getProxyInstance(nike); ClothFactory cloth = (ClothFactory)obj1; cloth.productCloth(); } }
|