Java中反射的作用

反射的主要作用就是获取JVM中的Class对象,获取了对象之后可以实现很多功能,比方说IOC容器通过反射创建对象、或者是动态代理(这个实际应用讲完反射原理后稍微再讲一下)。

一、获取Class对象的三种方式:

如何获取Class对象呢?有三种情况:

  1. Java代码仅经过编译生成了字节码文件,还未加载到内存中
  2. Java代码加载到了内存中,但是还未创建对象实例
  3. 已经创建了对象实例

针对这三种情况分别有以下三种方式获取Class对象:

1、Class.forName(“全类名”):只有字节码文件,还未被加载进内存。多用于配置文件,将类名定义在配置文件中

2、类名.class:已经加载进内存但是还没有对象。多用于参数的传递

3、对象名.getClass():有对象希望获取字节码。

同一个字节码文件在一次程序的运行过程中只会被加载一次。不论哪一种方式获取的class类对象都是同一个,即这三种方式只会创建一个Class对象

二、Class对象的功能(即Class类中有哪些常用的方法)

以下代码均假设已经获取到了Person类的Class对象:personClass

1、获取类名

  • String getName()
// 获取到的是全类名
String className = personClass.getName();

2、获取构造函数

反射获取Class对象后最重要的一个功能就是创建对象,创建对象自然是要通过构造函数。
方法

  • Constructor<?>[] getConstructors:获取所有public修饰的构造函数

  • Constructor<T> getConstructor(类<?>...parameterTypes)获取指定的public修饰的构造函数

    参数类<?>...parameterTypes表示要传构造函数参数的类型,因为同一个类中区分构造函数只能通过参数
    如要获取构造函数Person(String name, int get),则personClass.getConstructor(String.class, int.class)

  • Constructor<?>[] getDeclaredConstructors():获取所有的构造函数

  • Constructor<T> getDeclaredConstructor(类<?>...parameterTypes):获取任一指定的构造函数

作用

1、获取构造函数当然是为了创建对象

  • T newInstance(parameters...)
  • Class.newInstance():调用空参的构造方法可以这样简化,但是这个方法好像JDK9之后被废除了。
Person p = new Person;
// 空参构造函数简化调用:personClass.newInstance();
// 假设获取的构造方法有两个参数:Stirng类型的名字和int类型的年龄
Constructor constructor = personClass.getConstructor(String.class, int.class);
constructor.newInstance("martin", 23);

私有构造函数可以通过getDeclaredConstructor()获取Constructor对象,但是不能constructor.newInstance()调用,会报IllegalAccessException(非法访问异常),可以通过执行constructor.setAccessible(true)忽略访问权限修饰符的安全检查

3、获取成员变量

方法

  • Field[] getFields():获取所有public修饰的成员变量
  • Field getField(String name):获取所有指定的public修饰的成员变量
  • Field[] getDeclaredFields():获取所有的成员变量
  • Field getDeclaredField(String name):获取任一指定的成员变量

作用

1、取值get()、赋值set()

Field field = personClass.getField("name");
Person p = new Person;
Object value = field.get(p); // 获取对象p的name属性
name.set(field, "martin"); // 设置对象p的name属性

同理可以通过field .setAccessible(true)暴力反射

4、获取成员方法

如何:

  • Method[] getMethods():获取所有public修饰的成员函数,包括从父类如Object等类中继承的
  • Method getMethod(String name, 类<?>...parameterTypes)
    获取所有public修饰的指定的成员函数。第一个参数为函数方法名,后面的参数是函数的参数类型。
  • Method[] getDeclaredMethods():获取本类中所有方法,不会获取父类中的
  • Method[] getDeclaredMethod(String name, 类<?>...parameterTypes):获取本类中任一指定的方法

同理,私有方法可以通过setAccessible(true)暴力反射

作用:

1、获取方法名

Method.getName()

2、执行方法

Method.invoke()

Person p = new Person;
// 获取eat()的方法对象
Method method_eat = personClass.getMethod("eat");
method_eat.invoke(p);

// 获取eat(String foodName)的方法对象
Method method_eat = personClass.getMethod("eat", String.class);
method_eat.invoke(p, "rice");

三、案例

1、jdbc连接数据库中通过Class.forName()加载数据库驱动

2、代理模式对方法增强(aop的原理也是动态代理),这里稍微看一下动态代理中的JDK代理,先上关键部分的代码

public class StarProxy implements InvocationHandler {
	// target接受的是接口,JDK动态代理面向接口代理
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 加强操作
        System.out.println("收代理费");
        // 调用原方法
        Object result = method.invoke(target, args);
        //加强操作
        System.out.println("互换名片");
        return result;
    }

    // 这个方法返回的是代理对象实例,newProxyInstance()深入进去就是根据反射调用了构造函数生成实例
	//PS:生成代理类的方法不一定写在这里,可以写在一个工厂方法中
    public Object CreateProxyObject() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

文章是看了视频总结,视频讲的很好,附上视频链接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章