Java基础:反射

131 阅读4分钟

在学习Spring框架的AOP(面向切面编程)过程中,发现其实现原理就是动态代理模式反射

反射:

将类的各个组成部分封装成其他对象。(成员变量、构造方法、成员方法)

  • 好处
    1. 在程序运行过程中,可以操作这些对象完成一些操作。
    2. 可以对程序进行解耦,提高程序的可扩展性。

反射的使用:

获取Class对象:

获取Class对象的原因: 当你要使用反射机制去操作这些封装对象的时候,首先是要获取到字节码Class对象

获取Class对象的方式:

  • Class.forName("全类名"):将字节码文件加载进内存,返回Class对象(一般用在配置文件,将类名定义在配置文件里面。读取文件)
  • 类名.class:通过类名的属性class获取
  • 对象.getClass():getClass()方法在object类中定义(一般用于已经有一个对象,想获取它的字节码)

Class对象功能:

获取成员变量:

      1. Field[] getFields() //获取所有public修饰的成员变量
      2. Field getField(String name) //获取指定名称的public修饰的成员变量
      3. Field[] getDeclaredFields() //获取所有的成员变量,不考虑修饰符
      4. Field getDeclaredFields(String name) //获取指定名称的成员变量,不考虑修饰符
         
         Field:成员变量
            操作:
              1.设置值:
                void set(Object obj,Object value)
              2.获取值
                get(Object obj)
              3.忽略访问权限修饰符的安全检查
                setAccessible(true):暴力反射

获取构造方法:

   1. Constructor<?>[] getConstrucors() //获取public修饰无参构造方法
   2. Constructor<T>[] getConstrucors(类<?>...parameterTypes)//获取指定参数的public修饰有参构造方法
   3. Constructor<T>[] getDeclaredConstrucors(类<?>...parameterTypes)//获取所有的指定参数类型的有参构造方法
   4. Constructor<?>[] getDeclaredConstrucors()//获取所有有参构造方法
   
        Constructor:构造方法
            T newInstance(Object... initargs)

获取成员方法:

    1. Method[] getMethods()
    2. Method getMethod(String name,类<?>...parameterTypes)
    3. Method getDeclaredMethods()
    4. Method getDeclaredMethod(String name,类<?>...parameterTypes)

        Method:方法对象
            执行方法:
            Object invoke(Object obj,Object...args)
            获取方法名称:
            String getName:获取方法名

例子:

基本方法:

首先随便创建一个类

package com.yuan.bean;

public class Person {
    private String name;
    public Integer age;
    
    public Person() {
 }
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
 }
    public String getName() {
        return name;
 }
    public void setName(String name) {
        this.name = name;
 }
    public Integer getAge() {
        return age;
 }
    public void setAge(Integer age) {
        this.age = age;
 }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
 }
    public void eat(){
       System.out.println("干饭");
 }
}

接下来通过上面介绍的方法,综合起来运用一下:

public class test01 {
    public static void main(String[] args) throws Exception { //方法中可能出现多处异常,先抛个大的异常
//获取Class类对象
 Class cls = Class.forName("com.yuan.bean.Person");
 
 /*
 其他两种方法
 Class<Person> personClass = Person.class;
 Person p = new Person(); Class cls = p.getClass();
 */
 
 //获取类成员变量
 Field[] fields = cls.getFields();
 for(Field filed:fields){
      System.out.println(filed.getType()+"   "+filed.getName()); //class java.lang.Integer   age
 }
 
//获取类构造方法
 Constructor constructor = cls.getConstructor();
 Person o = (Person) constructor.newInstance();//通过构造器的newInstance()创建Person类对象
 
 //获取类成员方法
 Method method = cls.getMethod("eat");
 method.invoke(o);//通过method的invoke()方法调用成员方法 /*干饭*/
 }
}

写一个“框架”,可以帮我们创建任意类的对象,并且执行其中任意方法:(可以练个手)

1. 首先在src目录下创建一个properties配置文件:

(里面放我们要创建对象的类路径,以及要调用的类方法)

className=com.yuan.bean.Person
methodName=eat

2.编写测试方法

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        
//加载配置文件
        Properties pro = new Properties();//创建Properties对象
        ClassLoader classLoader = ReflectTest.class.getClassLoader();//通过类对象 获取类加载器getClassLoader()
        InputStream is = classLoader.getResourceAsStream("pro.properties");//通过类加载器获取配置文件的字节输入流对象
        pro.load(is);//加载文件
        
 //获取配置文件中加载的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        
 //加载该类进内存,获取Class类对象
        Class cls = Class.forName(className);
        
 //获取构造方法
        Constructor constructor = cls.getConstructor();
        
 //通过构造方法创建对象
        Object o = constructor.newInstance();
        
 //获取成员方法
        Method method = cls.getMethod(methodName);
        
 //调用成员方法
        method.invoke(o);
 }
    
}

后续:

这些也只是基本总结了反射的基本概念和方法,通过反射,我们可以不通过new的方式去创建一个新的对象,可以通过反射获取一个类的成员变量、构造方法、成员方法。可以通过操作一个类,去通过获取到的类的构造方法来创建对象,以及调用类的成员方法,修改类的成员变量的值。

在学习Spring框架中,AOP运用到了java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现动态代理。所以对于反射概念的熟悉是十分有必要的。