Java反射机制

反射

  • 反射就是通过获取class字节码文件对象、Class的类对象,获取该字节码文件对象中的成员变量,构造方法,和成员方法。
  • 相当于是直接去访问编译后的class字节码文件。

获取class字节码文件对象

有三种方法

Object中的getClass() 方法

  • 同一个类的不同对象调用getClass()返回的是相同的class字节码对象
Student s1 = new Student();
Student s2 = new Student();
Class<? extends Student> class1 = s1.getClass();
Class<? extends Student> class2 = s2.getClass();
System.out.println(s1 == s2);// false
System.out.println(class1 == class2);// true

任何数据类型的静态属性.class

        Class<Student> c2=Student.class;
        Class<Integer> c3=Integer.class;

Class类中的方法

  • forName(String className),这里的参数需要填写一个全路径名
  • 可以在类名上右击选Copy Qualified Name来获取全路径:包名.类名
public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> name = Class.forName("reflect.Test");//包名.类名
    }
}

Class类

方法

Constructor:

Constructor<?>[] getConstructors()

获取当前类中所有公共的构造方法,返回的是一个数组。

Constructor<?>[] getDeclaredConstructors()

获取所有的构造方法,包括私有的,受保护的。返回的是一个数组。

Constructor<T> getConstructor(Class<?>... parameterTypes)

获取指定参数的公共的构造方法,如果访问无参构造就不需要指定参数,指定的参数是参数类型.class

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

获取指定参数的构造方法,可以获取任意权限的构造方法。


Field:

Field getField(String name)

获取指定的公共的成员变量,需要指定成员变量的变量名

Field[] getFields() 

获取所有的公共的成员变量。返回值是数组。

Field getDeclaredField(String name)

获取指定的成员变量,需要指定成员变量的变量名。可以获取任意权限的成员变量。

Field[] getDeclaredFields()

获取所有的成员变量


Method:

Method[] getMethods()

获取所有的公共的成员方法的数组,包括当前类中继承的公共的成员方法。

Method[] getDeclaredMethods()

获取当前类中的所有的成员方法的数组。不包含继承来的成员方法。

Method getMethod(String name, Class<?>... parameterTypes)
  • name:需要获取的方法的方法名
  • parameterTypes参数类型,对于有参方法,需要填写参数类型.class,对于无参方法则只需指定方法名即可,对于参数为泛型的可以写Object.class

获取当前类中指定的公共的方法。以及当前类的父类中公共的访问方法。

Method getDeclaredMethod(String name, Class<?>... parameterTypes)

获取当前类中任意的方法,不包括父类中的。


相关类

Field

  • 代表成员变量,提供有关类或接口的单个字段的信息,以及对它的动态访问权限。
  • 反射的字段可能是一个类(静态)字段或实例字段。

方法:

set(Object obj, Object value)
  • obj:准备被修改的对象
  • value:需要修改的值

对指定对象添加当前Field实例代表的成员变量。

setAccessible(boolean flag)

跳过Java权限检查

Constructor

  • 代表构造方法,提供关于类的单个构造方法的信息以及对它的访问权限。

方法:

T newInstance(Object... initargs)

使用指定的参数对类进行初始化并创建新的实例,返回值是Object类对象。

setAccessible(boolean flag)

参数为true时表示跳过Java权限检查。

Method

  • 代表成员方法,类或接口上单独某个方法(以及如何访问该方法)的信息

方法:

Object invoke(Object obj, Object... args)

obj:绑定的对象
args:传入的参数

  • 执行当前Method实例引用的方法,需要指定一个当前类的引用对象去执行。
  • 对于静态方法,指定的obj对象将被忽略也可以为null。
  • 对于需要传入参数的方法,还需要给传入相应类型的参数
  • 对于有返回值的方法,该方法的返回值就是invoke方法的返回值。
  • invoke方法的返回值都是Object类型

setAccessible(boolean flag)

参数为true时跳过Java的权限检查


案例

  • 以下案例中使用相同的自定义标准类:
/**
 * 自定义一个标准类
 */
public class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    // 私有的构造方法
    private Student(String name) {
        super();
        this.name = name;
    }

    public Student() {
        super();
    }

    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 "Student [name=" + name + ", age=" + age + "]";
    }
    //带参数有返回值的方法
    public String show(int a, int b) {
        return "a+b=" + (a + b);
    }
    //没有返回值不带参数的方法
    public void show1() {
        System.out.println("show1");
    }
    //带参数有返回值私有的方法
    private int show2(int a) {
        System.out.println("私有show2");
        return a;
    }
}

通过反射访问构造方法

import java.lang.reflect.Constructor;

public class Test {
    public static void main(String[] args) throws Exception {
        // 获取字节码文件
        Class<?> c = Class.forName("reflect.Student");
        // 获取公共的有参,需要添加参数类型.class,如果需要访问无参构造则不用写
        Constructor<?> con = c.getConstructor(String.class, int.class);

        System.out.println(con);
        // public reflect.Student(java.lang.String,int)

        // 初始化创建实例
        Object o1 = con.newInstance("张三", 22);
        System.out.println(o1);// Student [name=张三, age=22]

        // 获取私有的有参构造
        Constructor<?> con2 = c.getDeclaredConstructor(String.class);
        // 访问私有的有参构造需要跳过权限检查
        con2.setAccessible(true);
        // 初始化
        Object o2 = con2.newInstance("李四");
        System.out.println(o2);// Student [name=李四, age=0]

    }
}

访问成员变量

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> c = Class.forName("reflect.Student");
        // 访问私有的有参构造
        Constructor<?> con2 = c.getDeclaredConstructor(String.class);
        con2.setAccessible(true);
        Object o2 = con2.newInstance("李四");
        System.out.println(o2);// Student [name=李四, age=0]
        //给私有的成员变量赋值
        Field f1 = c.getDeclaredField("age");
        //跳过权限检查
        f1.setAccessible(true);
        //赋值
        f1.set(o2, 21);
        System.out.println(o2);//Student [name=李四, age=21]

    }
}

访问成员方法

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> c = Class.forName("reflect.Student");
        Constructor<?> con = c.getConstructor();
        Object o = con.newInstance();

        // 执行show1方法
        Method show1 = c.getMethod("show1");
        show1.invoke(o);//show1

        // 有返回值有参数的show方法
        Method show = c.getMethod("show", int.class, int.class);
        //参数为方法名,参数类型.class
        Object invoke = show.invoke(o, 5, 6);
        //参数为指定对象,参数值
        System.out.println(invoke);//a+b=11

        //私有的有返回值有参数的show2方法
        Method show2 = c.getDeclaredMethod("show2", int.class);
        //解除权限限制
        show2.setAccessible(true);
        Object invoke2 = show2.invoke(o, 5);//私有show2
        System.out.println(invoke2);//5
    }
}

自定义方法,可将obj对象中名为propertyName的属性的值设置为value。

import java.lang.reflect.Field;

public class Test {
    public static void setProperty(Object obj, String propertyName, Object value) throws Exception {
        // 获取对象字节码文件
        Class<? extends Object> c = obj.getClass();
        // 获取指定的字段
        Field f = c.getDeclaredField(propertyName);
        // 取消权限检查
        f.setAccessible(true);
        // 修改信息
        f.set(obj, value);

    }
    /**
     * 测试
     */
    public static void main(String[] args) throws Exception {
        Student s1 = new Student("张三", 18);
        System.out.println(s1);//Student [name=张三, age=18]
        Test.setProperty(s1, "name", "李四");
        System.out.println(s1);//Student [name=李四, age=18]
    }
}

给指定Integer泛型的ArrayList数组添加String类型数据


import java.lang.reflect.Method;
import java.util.ArrayList;

public class Test {

    public static void main(String[] args) throws Exception {
        // 创建一个泛型为Integer类型的ArrayList数组
        ArrayList<Integer> list = new ArrayList<>();
        list.add(100);
        list.add(200);
        // 获取Class字节码文件
        Class<? extends ArrayList> c = list.getClass();
        // 获取add方法,add方法参数类型为泛型,可以指定为Object.class
        Method m = c.getMethod("add", Object.class);
        // 执行方法
        m.invoke(list, "你好");
        m.invoke(list, "hello");
        System.out.println(list);// [100, 200, 你好, hello]

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值