1.反射的作用

首先用一段很简单易懂的话来说明反射的作用,一个类,如果里面没有get,set方法,那么我们即使有实例对象,也无法获取到里面的属性。如果里面还有私有的构造器以及私有的成员函数,我们同样无法通过实例对象去调用这些构造器和方法,但是反射机制就可以帮我们做到,可以仅仅通过一个类名,就去获取这个类的所有域,构造器和方法并进行调用和修改。

反射作用具体表现在:

  • 在运行时分析类的能力
  • 在运行时查看对象。例如可以编写一个toString方法供所有类使用
  • 实现通用的数组操作代码
  • 利用Method对象,这个对象很像C++中的函数指针

2.反射中的主要组成

  • 1)Class类:泛型类 和类名有关
  • 2)Field类:和类中的域有关
  • 3)Method类:和类中的成员方法有关
  • 4)Constructor类:和类中的构造器有关

3.反射获取类属性:

定义实体类:

这个类中有私有,共有的属性,构造器和方法,但是没有get,set方法

public class Animal {
    
        public Integer age;
        private String type;
        private String name;
    
        private Animal(String type) {
            this.type = type;
        }
    
        public Animal(){}
    
        public Animal(String type, String name) {
            this.type = type;
            this.name = name;
        }
    
        public Animal(Integer age, String type, String name) {
            this.age = age;
            this.type = type;
            this.name = name;
        }
    
    
        private void hello(String msg){
            System.out.println(msg);
        }
    
    
        @Override
        public String toString() {
            return "Animal{" +
                    "age='" + age + '\'' +
                    ", type='" + type + '\'' +
                    ", name='" + name + '\'' +
                    '}';
        }
        }

获取Class类的三种方法:

  • getClass():
  • forName(className):
Animal animal1 = new Animal("猫科","熊猫");
    //获取Class类对象第一种方式
    Class c1 = animal1.getClass();
    System.out.println(c1.getName());//test.Animal
    
   
   //获取Class类对象第二种方式
    String className = "java.util.Random";
    Class c2 = Class.forName(className);
    System.out.println(c2.getName());//java.util.Random
    
    
   //获取Class类对象第三种方式
    Class cl1 = Random.class;
    Class cl2 = int.class;
    Class cl3 = Double[].class;
    System.out.println(cl1.getName());
    System.out.println(cl2.getName());
    System.out.println(cl3.getName());
    //输出
    java.util.Random
    int
    [Ljava.lang.Double;

获取类中的域属性:Field

  • getFields():返回所有的public域
  • getDeclaredFields():返回所有级别的域
  • getDeclaredField(“xxx”):返回指定域名的域
```java
 //获取域
    Animal animal3 = new Animal("猫科","熊猫");
    Class cx3 = animal3.getClass();
    Field[] fields = cx3.getFields(); //返回public域
    for(Field field: fields){
        System.out.println(field.getName());
    }
    
    Field[] declaredFields = cx3.getDeclaredFields();//返回所有域
    for(Field field: declaredFields){
        System.out.println(field.getName());
    }
    
    Field field1 = cx3.getDeclaredField("name");//返回指定域
    System.out.println(field1.getType().getName());//这里的getType方法是获取类型
    
    //输出
    age
    
    age
    type
    name
    
    java.lang.String

获取构造器:Constructor

  • getConstructors():获取所有public级别的构造器
  • getDeclaredConstructors():获取所有级别的构造器
  • getDeclaredConstructor(String.class):获取指定构造器 传入参数类型列表
//获取构造器
Animal animal4 = new Animal("猫科","熊猫");
Class cx4 = animal4.getClass();
Constructor[] constructors = cx4.getConstructors();//获取public构造器
for(Constructor constructor:constructors){
    System.out.println(constructor.getName());
}


Constructor[] constructors1 = cx4.getDeclaredConstructors();//获取所有构造器
for(Constructor constructor:constructors1){
    System.out.println(constructor.getName());
}

Constructor constructor2 = cx4.getDeclaredConstructor(String.class);//获取指定构造器 传入参数类型列表
//constructor2.getModifiers()返回的是一个整形数值 用于判断修饰级别
System.out.println(Modifier.toString(constructor2.getModifiers()));

//输出
test.Animal
test.Animal
test.Animal

test.Animal
test.Animal
test.Animal
test.Animal

private

这里上面输出三个说明有一个private构造器没有获取到,后面是四个,最后一个输出了获取构造器的修饰级别

获取成员函数:Method

  • getMethods():获取所有public成员函数 包括了父类的方法
  • getDeclaredMethods():获取所有级别的成员函数
  • getDeclaredMethod(“functionName”, String.class):获取指定成员函数 前面是函数名后面是参数类型列表
//获取成员函数
    Animal animal5 = new Animal("猫科","熊猫");
    Class cx5 = animal5.getClass();
    Method[] methods = cx5.getMethods();//获取所有public成员函数 包括了父类的方法
    for(Method method: methods){
        System.out.println(method.getName());
    }
    System.out.println();
    
    Method[] declaredMethods = cx5.getDeclaredMethods();//获取所有级别的成员函数
    for (Method method: declaredMethods){
        System.out.println(method.getName());
    }
    System.out.println();
    
    //获取指定成员函数 前面是函数名 后面是参数类型列表
    Method method = cx5.getDeclaredMethod("hello", String.class);
    System.out.println(method.getName());
    System.out.println();

4.反射调用和访问类

上一部分仅仅是说了如何获取到类的属性,但是并没有进行访问和调用,现在来开始调用。

1)反射获取对象的私有域和公有域并进行修改

用get和set方法进行获取和修改,这里要注意实体类中并没有set和get方法

还有就是访问私有域的时候要用setAccessible()方法添加权限才可以

//通过反射获取某个对象的域值 并进行修改
    Animal animal6 = new Animal(20,"猫科","熊猫");
    Class cx6 = animal6.getClass();
    Field age = cx6.getDeclaredField("age");//获取公有属性age
    Object o = age.get(animal6);//获取animal6实例的age属性的值
    System.out.println("animal6的age: "+o);
    age.set(animal6,56);//修改该对象age的值为56
    Object o2 = age.get(animal6);
    System.out.println("animal6的age: "+o2);//56
    
    Field type = cx6.getDeclaredField("type");//获取私有属性
    type.setAccessible(true);//这里要设置权限
    Object o1 = type.get(animal6);
    System.out.println("animal6的type: "+o1);
    type.set(animal6,"虎类");
    Object o3 = type.get(animal6);
    System.out.println("animal6的type: "+o3);//虎类

2)通过反射调用私有和公有成员函数

用invoke方法来调用,第一个参数是对象名,第二个是方法参数列表

//通过反射调用方法 用invoke方法调用获取的方法 第一个参数是对象 之后是参数列表
    Animal animal7 = new Animal(20,"猫科","熊猫");
    Class cx7 = animal7.getClass();
    Method hello = cx7.getDeclaredMethod("hello", String.class);
    hello.setAccessible(true);//这个方法是私有的  所以要加权限
    hello.invoke(animal7,"11111");

3)通过反射调用私有公有构造器构造实例

获取构造器后用newInstance方法实例化!

//通过反射调用构造函数构造实例
Animal animal8 = new Animal(20,"猫科","熊猫");
Class cx8 = animal8.getClass();
Constructor constructor = cx8.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object o4 = constructor.newInstance("狗类");
System.out.println(o4);