Java反射总结

反射的具体原理以后说明,以下面代码实例来说明反射的应用。

先写一个Person类

package exercise01;

public class Person {
    private String name;
    private int age;
    //无参构造方法
    public Person() {
        
    }
    //有参构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

获取Class对象的三种方法

Class clazz1 = Person.class;
Class clazz2 = new Person()。getClass();
Class clazz3 = Class.forName("exercise01.Person"); //forName方法的参数是类的路径,即包名加类名

Class对象中有三个数组,分别是

private Constructor[] constructor;  //构造方法数组,存放目标类的构造器
private Field[] field;  //属性数组,存放目标类属性
private Method[] method;  //普通方法数组,存放目标类的普通方法

得到三个数组的方法

    @Test
    public void getAll() throws Exception {
        Class clazz = Person.class;
        //得到构造器的数组
        Constructor[] constructor = clazz.getConstructors();
        //得到属性的数组
        Field[] field = clazz.getDeclaredFields();
        //得到普通方法的数组
        Method[] method = clazz.getDeclaredMethods();
    }

注意:

如果Class对象想设置目标类的私有属性或方法,要添加下面这个语句

//获取Class对象
Class clazz = Person.class;
//获取Person类中的name属性
Field field = clazz.getDeclaredField("name");
//name的访问权限是private,通过下面语句获取权限,r然后Field对象就可以为name属性赋值了
field.setAccessible(true);

调用目标类的无参构造方法

//获取无参的构造方法
    @Test
    public void getConstructor() throws Exception {
                //获取Class类对象
        Class clazz = Person.class;
        //得到Person的实例
        Person p = (Person)cla.newInstance();
        p.setName("example");
        System.out.println(p.getName());
    }

调用目标类的有参构造方法

@Test
    public void getConstructors() throws Exception{
        Class clazz = Person.class;
        //传递的是有参构造方法里的参数类型,类型是class的形式
        /*
         * 这里int的class形式要用int.class,而不是Integer.class
         * 如果要用Integer.class,要把Person类的age改成Integer类型
         */
        Constructor cs = clazz.getConstructor(String.class, int.class);
        //通过有参数的构造方法设置值
        Person p1 = (Person)cs.newInstance("lila", 24);
        System.out.println(p1);
    }

使用目标类的属性

@Test
    public void getField() {
        try {
            Class clazz = Class.forName("exercise01.Person");
            //得到name属性
            //c2.getDeclaredFields(); //得到所有的属性
            Field field = clazz.getDeclaredField("name");
//使用Person的无参构造方法实例化一个Person对象 Person person
= (Person)clazz.newInstance(); //设置访问权限,使field可以操作私有属性 field.setAccessible(true); //设置person对象的name属性 field.set(person, "example"); System.out.println(f1.get(person)); }catch(Exception e) { e.printStackTrace(); } }

使用目标类的普通方法

@Test
    public void getMethod() throws Exception{
        Class clazz = Class.forName("exercise01.Person");
        //使用Person类的无参构造方法实例化一个Person对象
        Person person = (Person)clazz.newInstance();
        //获取一个Method对象,该方法包含Person类的setName方法
        /*
         * getDeclaredMethod方法第一个参数是目标类的目标方法名,第二个参数是目标方法的参数类型的class形式
         * 可以把目标方法的所有参数都写进去
         */
        Method method = clazz.getDeclaredMethod("setName", String.class);
        //设置权限
        method.setAccessible(true);
        method.invoke(person, "example");
        //访问静态方法
        //method.invoke(null, "example");
        System.out.println(person.getName());
    }

这里有个值得注意的地方,如果要调用目标类的静态方法,此时invoke方法的书写方法有点不同。

因为调用静态方法,不必实例化一个对象,可以通过类名直接调用,所以当使用静态方法时,invoke方法的第一个参数写成null,第二个参数写静态方法的参数的值,比如

method.invoke(null, "example");
原文地址:https://www.cnblogs.com/songzj/p/7639759.html