51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

彻底吃透Java反射

反射的概念

反射(Reflection)是Java中一种强大的能力,它允许程序在运行时逻辑地检查类的能力和属性。
反射的主要功能包括:
1. 在运行时判断任意一个对象所属的类;
2. 在运行时构造任意一个类的对象;
3. 在运行时判断任意一个类所具有的成员变量和方法;
4. 在运行时调用任意一个对象的方法;
5. 生成动态代理。
反射的基本API包括:
1. Class类:代表一个类
2. Field类:代表类的成员变量
3. Method类:代表类的方法
4. Constructor类:代表类的构造方法

获取类的三种方式

  • 1、通过已知的类型,获取class
public class GetClass {

    public static void main(String[] args) {
        Class<Apple> appleClass = Apple.getAppleClass();
        System.out.println("appleClass = " + appleClass);
    }
}
class Apple {
    private String color;
    public static Class<Apple> getAppleClass() {
        Class<Apple> appleClass = Apple.class;
        return appleClass;
    }
}
  • 2、通过实例化对象获取class
public class Class01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //Class类对象不是new出来的,而是系统生成的
        Dog dog = new Dog();

        Class<? extends Dog> aClass = dog.getClass();
    }
}
  • 3、通过class.forName()获取
public class Class02 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        String classPath = "com.jorry.reflection.domain.Car";
        Class<?> aClass = Class.forName(classPath);
        //输出Class
        System.out.println(aClass.getClass());
        //得到包名
        System.out.println(aClass.getPackage().getName());
        //得到类名
        System.out.println(aClass.getName());

        //创建对象实例
        Car o = (Car) aClass.newInstance();


        //通过反射获取所有的属性
        Field[] fields = aClass.getFields();
        List<Field> list = Arrays.asList(fields);
        list.forEach(field -> field.setAccessible(true));
        Field fieldName = aClass.getField("name");
        System.out.println("fieldName = " + fieldName);

        //通过反射给属性设置值
        fieldName.set(o, "zhangsan");
        System.out.println(fieldName.get(o));
    }
}

Java反射相关API

  • Class常用操作
//获取所有的构造方法 / private public
public Constructor<?>[] getDeclaredConstructors()
//获取特定的构造方法 / private public
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//获取类的父类
public native Class<? super T> getSuperclass()
//获取类实现的接口
private Class<?>[] getInterfaces(boolean cloneArray)
//获取在类内定义的内部类或接口
public Class<?>[] getDeclaredClasses()
//获取所有的方法
public Method[] getDeclaredMethods() throws SecurityException
//根据方法名和参数获得特定的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
//获取类型的定义的所有属性
public Field[] getFields() throws SecurityException
// 根据属性命名获得特定的Field
public Field getField(String name)
- Method常用的操作方法
//获取所有的构造方法 / private public
public Constructor<?>[] getDeclaredConstructors()
//获取特定的构造方法 / private public
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//获取类的父类
public native Class<? super T> getSuperclass()
//获取类实现的接口
private Class<?>[] getInterfaces(boolean cloneArray)
//获取在类内定义的内部类或接口
public Class<?>[] getDeclaredClasses()
//获取所有的方法
public Method[] getDeclaredMethods() throws SecurityException
//根据方法名和参数获得特定的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
//获取类型的定义的所有属性
public Field[] getFields() throws SecurityException
// 根据属性命名获得特定的Field
public Field getField(String name)
- Field常用的操作方法
//属性与obj相等则返回true
public boolean equals(Object obj)
//获得obj中对应的属性值
public Object get(Object obj)
//设置obj中对应属性值
public void set(Object obj, Object value)
- Constructor
//根据传递的参数创建类的对象:initargs 构造方法参数
public T newInstance(Object... initargs)

##创建对象实例

public class User {
    private Integer value;

    public User() {
    }

    public User(int value) {
        this.value = value;
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        /**
         * 1、根据class创建实例
         */
        Class<User> userClass = User.class;
        User user = userClass.newInstance();
        /**
         * 2、根据构造函数创建对象实例
         */
        Constructor<User> constructor = User.class.getDeclaredConstructor();
        constructor.newInstance();

        /**
         * 3、根据指定的参数类型的构造函数,实例化对象
         */
        Constructor<User> cst = User.class.getDeclaredConstructor(Integer.class);
        cst.newInstance();
    }
}

反射执行方法

public class User {
    private Integer value;

    public User() {
    }

    public User(int value) {
        this.value = value;
    }

    public void eat(String name) {
        System.out.println("人吃饭,name:" + "\t" + name);
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        /**
         * 1、根据class创建实例
         */
        Class<User> userClass = User.class;
        User user = userClass.newInstance();
        Method method = userClass.getDeclaredMethod("eat", String.class);
        method.invoke(user, "Jorry");
    }
}

反射获取Field,并对Field进行操作

public class User {
    private Integer value;

    public User() {
    }

    public User(int value) {
        this.value = value;
    }

    public void eat(String name) {
        System.out.println("人吃饭,name:" + "\t" + name);
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        /**
         * 1、根据class创建实例
         */
        Class<User> userClass = User.class;
        User user = userClass.newInstance();
        //获取所有的属性,getField只能获取public的属性
        Field[] fields = userClass.getFields();
        Field field = userClass.getField("value");
        
        
        Field[] fields = userClass.getDeclaredFields();
        //获取特点字段的值
        Field field = userClass.getDeclaredField("value");
        //使用反射机制可以打破封装性,导致了java对象的属性不安全
        field.setAccessible(true);
        field.set(user,1007);
        System.out.println("value = " + user.value);
    }
}
  • 反射的使用场景
1. 框架设计:反射被广泛用在框架的设计中,如Spring、Hibernate等,利用反射提供了更加灵活和松耦合的框架结构。
2. 调试和测试工具:IDE、代码分析工具等需要通过反射来了解代码的能力和属性,如Eclipse、IDEA都使用了反射。
3. 扩展性实现:通过反射来实例化对象和调用方法,可以实现动态加载类、根据配置来组装类的功能,提高代码的扩展性。
4. 安全框架:安全框架需要通过反射来检查类、方法的访问权限。如Java自身的SecurityManager。
5. 高级编程:通过反射实现依赖注入、动态代理等高级功能,提高编程灵活性。
6. 访问私有成员:反射可以通过setAccessible()方法访问私有成员,用于测试、调试等场景。
7. 性能优化:通过动态生成代码和JIT编译,使用反射提高某些场景下的性能。
8. 其它元编程:反射是元编程的重要方式,用于各种代码分析、生成等场景。

小彩蛋

高效的Hutool 当我用了一次Hutool中的反射工具类,真香,所以在此安利给大家:

  • 1、导入Pom
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.21</version>
</dependency>
  • 相关Api
public class ReflectionUtil {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1、获取所有属性
        Field[] fields = ReflectUtil.getFields(Person.class);
        Arrays.asList(fields).forEach(field -> field.setAccessible(true));

        Person person = new Person();
        //设置属性值
        ReflectUtil.setFieldValue(person, "name", "jorry");
        ReflectUtil.setFieldValue(person, "age", 18);
        //获取属性字段值
        String name = (String) ReflectUtil.getFieldValue(person, "name");
        Integer age = (Integer) ReflectUtil.getFieldValue(person, "age");

        //实例化对象
        Person personInstance= ReflectUtil.newInstance(Person.class, "zhangsan", 18);
        System.out.println("personInstance = " + personInstance);

        //执行方法
        ReflectUtil.invoke(person, "eat");
    }
}

class Person {
    private String name;

    private int age;


    public Person() {
    }

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

    public void eat() {
        System.out.println("我要吃饭");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
赞(1)
未经允许不得转载:工具盒子 » 彻底吃透Java反射