Java基础(反射)

概念

反射机制是动态语言的关键。反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能操作任意对象的内部属性和方法。包括

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时调用任意一个对象的成员变量和方法
  5. 生成动态代理

反射相关主要API

  1. java.lang.Class //类
  2. java.lang.reflect.Method //类方法
  3. java.lang.reflect.Field //类成员变量
  4. java.lang.reflect.Constructor //类构造方法

简单示例

先定义一个Unit类

public class Unit {
    public int a;
    private String b;

    public void show(){
        System.out.println("A = "+a+" ,B = "+b);
    }
}
public class reflectionTest {
    @Test
    public void test1() throws Exception {
        Class<Unit> clazz = Unit.class;
        //Unit u = (Unit)clazz.newInstance(); Java9之后已被废弃
        Unit u = clazz.getDeclaredConstructor().newInstance();
        Field f1 = clazz.getField("a");
        //private使用getDeclaredField
        Field f2 = clazz.getDeclaredField("b");
        f1.set(u,1);
        //修改范围外属性需要设置可达性
        f2.setAccessible(true);
        f2.set(u,"one");
        Method m1 = clazz.getMethod("show");
        //Method m1 = clazz.getDeclaredMethod("m1",String.class,Integer.class)
        //m1.setAccessible(true);
        //m1.invoke(obj,args);
        m1.invoke(u);
    }
}

反射与Class类的联系

java.lang.Class是反射的源头。

我们创建的类通过编译(javac.exe),生成对应的.class文件,之后使用jvm的类加载器加载。此.class文件加载到内存后,就是一个运行时类,储存在缓存区。这个运行时类本身就是Class的实例。

每一个运行时类只加载一次。

有了Class的实例后,我们可以进行:

  1. 创建对应的运行时类的对象
  2. 获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在包、异常、注解。。。)
  3. 调用对应的运行时类的指定结构(属性、方法、构造器)

获取Class实例的方式

调用运行时类本身的.class属性

Class clazz = Unit.class;

通过运行时类的对象获取

Unit u = new Unit();
Class clazz = u.getClass();

通过Class的静态方式获取

Class clazz = Class.forName("Unit");

通过类的加载器

ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz = classLoader.loadClass("Unit");

Class对象的作用

getDeclaredConstructor(Class…parameterTypes)能够获取到本类的指定形参类型构造器。

向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。

使用Constructor类中的newInstance()方法。

通过反射获取类的结构

Field

Class clazz = Unit.class;
//获取属性
//getFields()只能获取运行时类中声明为public的属性
Field[] fields = clazz.getDeclaredFields();

for(Field f:fields)

//获取属性的权限修饰符
Modifier.toString(f.getModifiers());

//获取属性的类型
f.getType().getName();

Method

Class clazz = Unit.class
//获取运行时类的方法
//getMethods()获取运行时类及其父类中所有声明为public的方法
//getDeclaredMethods()本身声明的所有方法
Method[] ms = clazz.getDeclaredMethods();

for(Method m:ms)

//获取注解
Annotation[] anns = m.getAnnotations();

//获取返回值类型
Class returnType = m.getReturnType();

//获取方法名
m.getName();

//形参列表
Class[] params = m.getParameterTypes();

//异常类型
m.getExceptionTypes();

Constructor

Class clazz = Unit.class
//获取构造器
Constructor[] cons = clazz.getDeclaredConstructors();

其他

Class clazz = Unit.class
//获取运行时类的父类
Class superClass = clazz.getSuperclass();

//获取带泛型的父类
Type type = clazz.getGenericSuperclass();

//获取父类的泛型
ParameterizedType param = (ParameterizedType)type;
Type[] types = param.getActuallyTypeArguments(); 
types[i].getName();

//获取实现的接口
Class[] interfaces = clazz.getInterfaces();

//获取所在的包
Package package = clazz.getPackage();

动态代理

静态代理的特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发过程中必然存在过多的代理。

动态代理可以通过一个代理类完成全部的代理功能。是指客户通过代理类来调用其他对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。

代理设计模式的原理

使用一个代理将对象包装起来,然后用该代理对象取代原对象。任何原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。

静态代理模式示例

/**
 * 静态代理模式
 */
interface ClothFactory{
    void productCloth();
}
//被代理类
class NikeClothFactory implements ClothFactory{
    @Override
    public void productCloth() {
        System.out.println("Nike");
    }
}
//代理类
class ProxyFactory implements ClothFactory{
    ClothFactory cf;
    //创建代理类的对象时,实际传入一个被代理类的对象
    public ProxyFactory(ClothFactory cf){
        this.cf = cf;
    }
    @Override
    public void productCloth() {
        System.out.println("代理类开始执行");
        cf.productCloth();
    }
}
public class ClothProduct {
    public static void main(String[] args) {
        NikeClothFactory nike = new NikeClothFactory();
        ProxyFactory proxy = new ProxyFactory(nike);
        proxy.productCloth();
    }
}

动态代理模式示例

/**
 * 动态代理模式
 */
interface ClothFactory{
    void productCloth();
}
//被代理类
class NikeClothFactory implements ClothFactory{
    @Override
    public void productCloth() {
        System.out.println("Nike");
    }
}
//代理类
class MyInvocationHandler implements InvocationHandler {
    //实现了接口的被代理类的声明
    Object obj;
    /* 1.给被代理类的对象实例化
     * 2.返回一个代理类的对象
     */
    public Object bind(Object obj){
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),this);
    }
    //当通过代理类的对象发起对被重写的方法的调用时,都会转化为对如下的invoke方法的调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //returnVal就是method方法的返回值
        Object returnVal = method.invoke(obj,args);
        return returnVal;
    }
}
public class ClothProduct {
    public static void main(String[] args) {
        //1.创建被代理类的对象
        NikeClothFactory nike = new NikeClothFactory();
        //2.创建一个实现了InvotationHandler接口的类的对象
        MyInvocationHandler handler = new MyInvocationHandler();
        //3.调用bind方法,动态返回一个同样实现了nike所在类实现的接口ClothFactory的代理类的对象
        Object obj = handler.bind(nike);
        //此时的clothFactory就是代理类的对象
        ClothFactory clothFactory = (ClothFactory)obj;
        //转到对InvacationHandler接口的实现类的invoke()方法的调用
        clothFactory.productCloth();
    }
}