java中反射的基本使用

一、参考文档:

  • https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html
  • chat gpt 问答

 二、前言

  • 反射是 java 的一个特性,是 java 提供的一种机制。
  • 反射允许程序在运行时查询和操作类的信息。
  • 反射对很多高级功能(框架设计、动态代理等)都很有用。
  • 反射提供了很多类和接口来操作class对象,如  java.lang.Class   java.lang.reflect.Constructor   java.lang.reflect.Method   java.lang.reflect.Field   
  • 反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

三、理论基础:

 1. 获取Class对象:

// 方式 1: 使用类的.class 属性
Class<?> clazz = MyClass.class;
// 方式 2: 使用 Class.forName()
Class<?> clazz2 = Class.forName("com.example.MyClass"); //这个字符串可能是一个参数,也就是“在运行时才知道要操作的类是什么
// 方式3: 使用对象的getClass()方法
MyClass myClass = new MyClass(); Class<?> clazz3 = myClass.getClass();
【注意】先获取反射对象 clazz,后续所有的操作都是用 clazz 来执行的,包括建立对象、获取类的构造器、方法、属性。

2. 获取类的构造函数

// 获取所有构造函数
Constructor<?>[] constructors = clazz.getConstructors();

// 获取指定的构造函数
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("John", 30);

3. 创建对象

// 通过无参构造方法创建实例
Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();

// 带参构造函数创建实例 (括号里的两个类型就是下面 newInstance() 里的两个参数类型)
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("Alice", 30);

4. 获取类的方法

// 获取所有公共方法
Method method = clazz.getMethod("methodName", String.class); // 指定方法名和参数类型
method.invoke(obj, "parameter");

// 获取私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true); // 允许访问私有方法
privateMethod.invoke(obj);

5. 获取类的字段

// 获取字段
Field field = clazz.getField("fieldName"); // 获取公共字段
Object fieldValue = field.get(obj); // 获取字段的值

// 访问私有字段
Field privateField = clazz.getDeclaredField("privateField");
privateField.setAccessible(true); // 允许访问私有字段
Object value = privatePrice.get(obj);//获取私有字段的值
privateField.set(obj, "newValue"); // 修改字段的值

 四、代码实践:

目录结构如下:

Apple.java

package com.example.reflect;

public class Apple {
    public String color;
    private int price;

    public Apple() {
    }
    public Apple(String color, int price) {
        this.color = color;
        this.price = price;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public int getPrice() {
        return price;
    }
}

 在Main.java中正常调用

Apple apple = new Apple();
apple.setColor("red");
apple.setPrice(5);
System.out.println("---------------- 正常调用 ----------------");
System.out.println("[public] color: " + apple.color);
System.out.println("[public] getColor(): " + apple.getColor());
System.out.println("[private] price: "+apple.getPrice());

运行结果:

 用反射调用(异常先都直接抛出):

获取class对象:

// 1. 获取class对象
Class<Apple> clazz = Apple.class;
Class<?> clz = Class.forName("com.example.reflect.Apple");
System.out.println(clazz);
System.out.println(clz);

 运行结果:证明两种方法获取的Class类是一样的(没有测试第三种方法)。

 获取反射对象 clazz后,后续所有的操作都是用 clazz 来执行的,包括建立对象、获取类/对象的构造器、方法、属性。

 用clazz获取类的构造器:只是用clazz来获取,不用clz(为了简化代码)

// 2. 获取构造器
// 2.1 获取空构造器
Constructor<Apple> constructor = clazz.getConstructor();
Apple apple = constructor.newInstance();//创建对象
System.out.println(apple);
// 2.2 获取有参构造器
Constructor<Apple> constructor1 = clazz.getConstructor(String.class,int.class );
Apple apple1 = constructor1.newInstance("Green", 2);//创建对象
System.out.println(apple1);

 运行结果:可见获取空构造器和有参构造器都成功了。

 用clazz创建对象:

在上一步获取构造器中, constructor.newInstance()  和   constructor1.newInstance("Green", 2);  就是创建了对象。

用clazz获取类的方法:以用有参构造器创建对象为例(为了简化代码)

// 4. 获取类的方法
// 4.1 获取有参方法(第一个参数是方法名,第二个参数是setColor(String color) 的类型)
Method setColorMethod = clazz.getMethod("setColor", String.class);
Method setPriceMethod = clazz.getMethod("setPrice", int.class);
// // 4.2 获取无参方法
Method getColorMethod = clazz.getMethod("getColor");
Method getPriceMethod = clazz.getMethod("getPrice");

// 4.1.1 调用有参方法, 
// .invoke() 就是调用这个方法,第一个参数是要操作的对象,第二个参数是修改的参数值
setColorMethod.invoke(apple, "Yellow");
setPriceMethod.invoke(apple,66);
// 4.2.1 调用无参方法
// .invoke() 就是调用这个方法,参数是要操作的对象
Object color = getColorMethod.invoke(apple);
Object price = getPriceMethod.invoke(apple);

System.out.println("color:  "+ color);
System.out.println("price:  "+ price);

运行结果:apple 从  constructor.newInstance("Green", 2); 变成了 Yellow,66

用clazz获取类的字段:上一步是用 getPrice() 获取price,这一步是直接访问price

Apple.java 中   public String color; private int price; 分别获取一下:

// 5. 获取类的字段
// 5.1 获取字段
Field field = clazz.getField("color");//获取公共字段
Object color = field.get(apple);//获取 apple对象中 字段color的值
System.out.println(color);
// 5.2 获取私有字段
Field privateField = clazz.getDeclaredField("price");//注意这里方法变成了 getDeclaredField()
privateField.setAccessible(true);//允许访问私有字段,不设置这一句运行会报错
Object price = privateField.get(apple);//获取私有字段的值
System.out.println(price);

  运行结果:

 


main全部代码如下:

package com.example;

import com.example.reflect.Apple;

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

public class Main {
    /**
     * 【正射】未运行时就已经确定了要运行的类
     * 【反射】就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
     *  
     * 反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性
     */
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        // 正常调用
        // Apple apple = new Apple();
        // apple.setColor("red");
        // apple.setPrice(5);
        // System.out.println("---------------- 正常调用 ----------------");
        // System.out.println("[public] color: " + apple.color);
        // System.out.println("[public] getColor(): " + apple.getColor());
        // System.out.println("[private] price: "+apple.getPrice());

        System.out.println("**********************************");
        // 1. 获取class对象
        Class<Apple> clazz = Apple.class;
        // 2. 获取构造器
        Constructor<Apple> constructor = clazz.getConstructor(String.class, int.class);
        // 3. 创建对象
        Apple apple = constructor.newInstance("Green", 2);
        // // 4. 获取类的方法
        // // 4.1 获取有参方法(第一个参数是方法名,第二个参数是setColor(String color) 的类型)
        // Method setColorMethod = clazz.getMethod("setColor", String.class);
        // Method setPriceMethod = clazz.getMethod("setPrice", int.class);
        // // // 4.2 获取无参方法
        // Method getColorMethod = clazz.getMethod("getColor");
        // Method getPriceMethod = clazz.getMethod("getPrice");
        // // 4.1.1 调用有参方法,
        // // .invoke() 就是调用这个方法,第一个参数是要操作的对象,第二个参数是修改的参数值
        // setColorMethod.invoke(apple, "Yellow");
        // setPriceMethod.invoke(apple,66);
        // // 4.2.1 调用无参方法
        // // .invoke() 就是调用这个方法,参数是要操作的对象
        // Object color = getColorMethod.invoke(apple);
        // Object price = getPriceMethod.invoke(apple);
        // System.out.println("color:  "+ color);
        // System.out.println("price:  "+ price);

        // 5. 获取类的字段
        // 5.1 获取字段
        Field field = clazz.getField("color");//获取公共字段
        Object color = field.get(apple);//获取 apple对象中 字段color的值
        System.out.println(color);
        // 5.2 获取私有字段
        Field privateField = clazz.getDeclaredField("price");//注意这里方法变成了 getDeclaredField()
        privateField.setAccessible(true);//允许访问私有字段,不设置这一句运行会报错
        Object price = privateField.get(apple);//获取私有字段的值
        System.out.println(price);
    }

}

 

posted @ 2025-01-08 10:03  sunshine233  阅读(235)  评论(0)    收藏  举报