Java反射机制,反射的基本使用与内省

反射

反射:把Java类中的各种成分映射成单独的Java对象进行操作。

类的对象:基于某个类new出来的对象,也称为实例对象。

类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)

反射的优缺点

  • 优点:提高了Java程序的灵活性和扩展性,降低了耦合性,提高自适应能力允许程序创建和控制任何类的对象,无需提前硬编码目标类
  • 缺点:反射降低了性能,代码维护难度增加

获取类对象

推荐使用forName获取类对象

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException {
        // 1 通过对象获取
        Student student = new Student("机器人", 21, "男");
        Class<? extends Student> studentClass = student.getClass();
        System.out.println(studentClass.hashCode());

        // 2 类名.Class
        System.out.println(Student.class.hashCode());

        // 3 forName获取
        Class<?> forName = Class.forName("com.robot.reflect.Student");
        System.out.println(forName.hashCode());
        
        // 获取父类对象
        Class<?> superclass = studentClass.getSuperclass();
        System.out.println(superclass);
    }
}

获取父类对象

Class<?> superclass = studentClass.getSuperclass();

只要元素类型与维度一样时,就是同一个Class

int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
/*
结果
1580066828
1580066828
*/

获取名字

public static void reflectOp2() throws Exception {
    Class<?> aClass = Class.forName("com.robot.reflect.Student");
    // 获取类的全限定名
    System.out.println(aClass.getName());
    // 获取类的简单名字
    System.out.println(aClass.getSimpleName());
    // 获取包名
    System.out.println(aClass.getPackage().getName());
}

获取类构造方法

public static void getConstructor() throws Exception {
    Class<?> aClass = Class.forName("com.robot.reflect.Student");
    // 获取构造方法,并使用构造方法创建对象
    Constructor<?> constructor;
    constructor = aClass.getConstructor(String.class, int.class, String.class);
    Student robot = (Student) constructor.newInstance("机器人1号", 20, "男");
    // 获取所有构造方法
    Constructor<?>[] constructors = aClass.getConstructors();
    for (Constructor<?> constructor1 : constructors) {
        System.out.println(constructor1);
    }
    // 直接创建对象
    Student student1 = (Student) aClass.newInstance();
}

获取类方法

public static void getMethod() throws Exception {
    Class<?> aClass = Class.forName("com.robot.reflect.Student");

    // 获取方法: 本类以及继承的public方法
    Method[] methods = aClass.getMethods();
    for (Method method : methods) {
        System.out.println(method);
    }

    // 获取方法: 本类的所有方法
    Method[] declaredMethods = aClass.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        System.out.println(declaredMethod);
    }

    Student student = (Student) aClass.newInstance();
    // 调用无参方法
    Method method1 = aClass.getMethod("show");
    method1.invoke(student);

    // 调用有参方法
    Method method2 = aClass.getMethod("show", String.class);
    method2.invoke(student, "上海");

    // 调用带返回值的方法
    Method getName = aClass.getMethod("getName");
    String result = (String) getName.invoke(student);
    System.out.println(result);

    // 调用静态方法
    Method sleep = aClass.getMethod("sleep");
    sleep.invoke(null);

    // 调用私有方法
    Method run = aClass.getDeclaredMethod("run");
    run.setAccessible(true); // 设置访问权限
    run.invoke(student);

}

一个通用方法,可以调用任意类的方法

传入参数:类对象,方法名,参数类型数组,参数

public static void invokeAny(Object obj, String methodName, Class<?>[] paramsType, Object... args) throws Exception {
    Class<?> aClass = obj.getClass();
    Method method = aClass.getDeclaredMethod(methodName, paramsType);
    if (!method.isAccessible()) {
        method.setAccessible(true);
    }
    method.invoke(obj, args);
}

调用

invokeAny(student, "show", new Class<?>[]{String.class}, "北京");
invokeAny(student, "run", null);

获取类属性

public static void getFiled() throws Exception{
    Class<?> aClass = Class.forName("com.robot.reflect.Student");
    // 获取类的指定属性
    Field name = aClass.getDeclaredField("name");
    System.out.println(name);
    

    // 获取类的所有public属性
    Field[] fields = aClass.getFields();
    for (Field field : fields) {
        System.out.println(field);
    }

    // 获取类的所有属性
    Field[] declaredFields = aClass.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println(declaredField);
    }
}

反射实现插件开发

创建接口

public interface CarService {
    /**
     * 汽车行驶
     */
    void run();

    /**
     * 汽车转弯
     */
    void turn(String direction);
}

创建2个实现类

public class BWM implements CarService{
    @Override
    public void run() {
        System.out.println("宝马 run...");
    }

    @Override
    public void turn(String direction) {
        System.out.println("宝马 turn to " + direction);
    }
}
public class Benz implements CarService{
    @Override
    public void run() {
        System.out.println("奔驰 run...");
    }

    @Override
    public void turn(String direction) {
        System.out.println("奔驰 turn to " + direction);
    }
}

创建一个文档,存储实现类的路径(cars.txt)

com.robot.reflect.BWM
com.robot.reflect.Benz

创建测试类

使用流的方式读取文件,并解析其中实现类的路径,然后使用反射创建对象

好处:可以只写一个测试类,就实现对任意实现类的测试(该类实现指定接口,并提供文档)

public class CarTest {
    public static void main(String[] args) throws Exception {
        FileReader fileReader = new FileReader("cars.txt");
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        String data;
        while ((data = bufferedReader.readLine()) != null) {
            Class<?> aClass = Class.forName(data);
            CarService car = (CarService) aClass.newInstance();
            car.run();
            car.turn("北");
        }
        fileReader.close();
    }
}

注:本测试使用txt文档存储实现类路径,但实际开发中都是解析jar包

内省

采用反射机制实现对属性进行操作的一种机制。

  • PropertyDescriptor:属性描述符,代表一个属性
  • BeanInfo:实体类信息,包含类的信息
  • Introspector:工具类

使用反射来访问其私有属性,并为其赋值

public class IntrospectorDemo {
    public static void main(String[] args) throws Exception{
        Class<?> class1 = Class.forName("com.robot.reflect.Student");
        Student student = (Student) class1.newInstance();

        // 获取类的属性
        PropertyDescriptor pdName = new PropertyDescriptor("name", class1);
        PropertyDescriptor pdAge = new PropertyDescriptor("age", class1);
        PropertyDescriptor pdGender = new PropertyDescriptor("gender", class1);

        // 获取属性类型
        System.out.println(pdName.getPropertyType());
        System.out.println(pdAge.getPropertyType());
        System.out.println(pdGender.getPropertyType());

        // 调用其Setter方法,为其赋值
        Method setName = pdName.getWriteMethod();
        setName.invoke(student, "Robot");
        Method setAge = pdAge.getWriteMethod();
        setAge.invoke(student, 21);
        Method setGender = pdGender.getWriteMethod();
        setGender.invoke(student, "男");
        System.out.println(student);

        // 调用其getter方法,获取属性值
        Method getName = pdName.getReadMethod();
        System.out.println(getName.invoke(student));
        Method getAge = pdAge.getReadMethod();
        System.out.println(getAge.invoke(student));
        Method getGender = pdGender.getReadMethod();
        System.out.println(getGender.invoke(student));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值