反射是框架设计的灵魂,也就是说要想看懂框架的源代码,必须得掌握反射机制。
作为初学者的我,觉得至少应该掌握它日常得几种用法。下面,继续接地气,说说反射机制的应用。
一、什么是Java Reflection?
运行过程中借助Reflection API来取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
注意:一定是运行过程中,不过这也很容易理解,“反射”凭感觉就可以认为这是一个动态的机制。关于反射机制,在Java中涉及到一个类——Class类。程序从源代码编写到执行的过程,如下图(图片来源于网络):
反射机制的使用前提:必须先得到字节码,前面所提的Class类就是用于表示.class文件(字节码)。
二、反射机制的作用
1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法
4.在运行时调用任意一个对象的成员变量和方法
比较难)
Reflection API:(主要的API)
反射的目的,就是要在程序运行时把类中的各种成分(如属性,构造方法,方法等等)分解成一个个的对象。那么,首先应该获取到‘类’,方法主要有三种,严格来讲有四种,而java.lang.Class这个类主要就是用来分解类中的对象。
接下来分析,获取运行时类的三种重要方式。
记住,得到的运行时类就是Class类型的实际对象,Class这个类是没有公共的构造方法的。
方法一:Class类中的静态方法forName("类名") ,已知Person是一个定义好的类,下同。
Class cs = Class.forName("Person");
方法二:Object超类中的getClass()方法
Person p=new Person(18,"90");
Class cs1 =p.getClass();
方法三:任何数据类型(包含基本数据类型)都有一个静态属性class
Person p=new Person(18,"90");
Class cs2 =Person.class;
Class自己本身是一个类,由于它没有公开的构造方法,因此它的对象只能由系统建立,并且任何一个类在JVM中只有一个实例。实际上一个Class对象对应
的是一个加载到JVM中的一个.class文件;每个类的实例都会记得自己是由哪个 Class 实例所生成;通过Class对象可以得到其对应类完整的结构。
Class有许多方法,使用时需要参照API文档。
这里省略Method、Constructor、Field等类的介绍,参照API,那是权威。哈哈!
三、反射的应用
主要应用于动态代理,代理是一种设计模式,还有静态代理,静态代理比较常见。
首先创建一个接口(JDK代理都是面向接口的),然后创建具体实现类来实现这个接口,在创建一个代理
类同样实现这个接口,不同之处在于,具体实现类的方法中需要将接口中定义的方法的业务逻辑功能实现,而代理类中的方法只要调用具体类中的对应方法即
可,这样我们在需要使用接口中的某个方法的功能时直接调用代理类的方法即可,将具体的实现类隐藏在底层。
1 package com.rdst.staticDL;
2 //静态代理模式
3 //接口
4 interface ClothFactory{
5 void productCloth();
6 }
7 //被代理类
8 class NikeClothFactory implements ClothFactory{
10 @Override
11 public void productCloth() {
12 System.out.println("Nike工厂生产一批衣服");
13 }
14 }
15 //代理类
16 class ProxyFactory implements ClothFactory{
17 ClothFactory cf;
18 //创建代理类的对象时,实际传入一个被代理类的对象
19 public ProxyFactory(ClothFactory cf){
20 this.cf = cf;
21 }
22
23 @Override
24 public void productCloth() {
25 System.out.println("代理类开始执行,收代理费$1000");
26 cf.productCloth();
27 }
28
29 }
30
31 public class TestClothProduct {
32 public static void main(String[] args) {
33 NikeClothFactory nike = new NikeClothFactory();//创建被代理类的对象
34 ProxyFactory proxy = new ProxyFactory(nike);//创建代理类的对象
35 proxy.productCloth();
36 }
37 }
看见没,静态代理是在编译前就将接口、实现类、代理类一股脑儿全部手动完成。
动态代理的思维模式与之前的静态代理是一样的,也是面向接口进行编码,创建代理类将具体类隐藏解耦,不同之处在于代理类的
创建时机不同,动态代理需要在运行时因需实时创建。
1 import java.lang.reflect.InvocationHandler;
2 import java.lang.reflect.Method;
3 import java.lang.reflect.Proxy;
4 //动态代理的使用,体会反射是动态语言的关键
5 interface Subject {
6 void action();
7 }
8 // 被代理类
9 class RealSubject implements Subject {
10 public void action() {
11 System.out.println("我是被代理类!");
12 }
13 }
14 class MyInvocationHandler implements InvocationHandler {
15 Object obj;// 实现了接口的被代理类的对象的声明
16
17 // ①给被代理的对象实例化②返回一个代理类的对象
18 public Object blind(Object obj) {
19 this.obj = obj;
20 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
21 .getClass().getInterfaces(), this);
22 }
23 //当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用
24 @Override
25 public Object invoke(Object proxy, Method method, Object[] args)
26 throws Throwable {
27 //method方法的返回值时returnVal
28 Object returnVal = method.invoke(obj, args);
29 return returnVal;
30 }
31 }
32 public class TestProxy {
33 public static void main(String[] args) {
34 //1.被代理类的对象
35 RealSubject real = new RealSubject();
36 //2.创建一个实现了InvacationHandler接口的类的对象
37 MyInvocationHandler handler = new MyInvocationHandler();
38 //3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象。
39 Object obj = handler.blind(real);
40 Subject sub = (Subject)obj;//此时sub就是代理类的对象
41 sub.action();//转到对InvacationHandler接口的实现类的invoke()方法的调用
42 //再举一例
43 NikeClothFactory nike = new NikeClothFactory();
44 ClothFactory proxyCloth = (ClothFactory)handler.blind(nike);//proxyCloth即为代理类的对象
45 proxyCloth.productCloth();
46 }
47 }
面向对象编程的多态,代理的核心知识还是向上转型。