Java 反射机制

简介

Java反射机制是运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于人一个对象,都能够调用它的任一方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java反射机制

  • 在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息

反射作用

  1. 运行时判断任意一个对象所属的类
  2. 运行时构造任意一个类的对象
  3. 运行时判断任意一个类所具有的的成员变量和方法
  4. 运行时获取泛型信息
  5. 运行时调用任意一个对象的成员变量和方法
  6. 运行时处理注解
  7. 生成动态代理

反射组成

  • java.lang.Class --- 实现反射的关键所在
    • Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解(Annotation)、数组、基本数据类型 和 void
    • Class 没有公有的构造方法,Class 实例是由 JVM 在类加载时自动创建的
      • public final class Class<T> implements java.io.Serializable,GenericDeclaration,Type,AnnotatedElement {
            private static final int ANNOTATION= 0x00002000;
            private static final int ENUM      = 0x00004000;
            private static final int SYNTHETIC = 0x00001000;
        
            private static native void registerNatives();
            static {
                registerNatives();
            }
                                          
            private Class(ClassLoader loader) {
                classLoader = loader;
            }
        }
  • java.lang.reflect.Method --- 提供类或接口成员方法信息
  • java.lang.reflect.Field --- 提供类或接口中成员变量信息
  • java.lang.reflect.Constructor --- 提供类的构造方法信息
  • ……

必须先获得Class才能获取Method、Constructor、Field

反射中类的加载过程:根据JVM工作原理,一般情况下类需要经过 加载-验证-准备-解析-初始化-使用-卸载 过程,如果需要反射的类没有在内存中,那么先经过加载这个过程并在内存中生成一个Class对象,有了这个Class对象后就可以进行反射的操作

  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个 .class 文件
  • 每个类的实例都记得属于哪个Class实例生成的
  • 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,可通过不同的方式来获取此运行时类

获取 Class 对象的四种方式

如果想要动态获取类的所有信息,需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序

  1. 知道具体类的情况
    1. Class<Person> clazz = Person.class;
  2. 通过对象实例获取
    1. Person person = new Person();
      Class<? extends Person> clazz = person.getClass();
  3. 通过 Class.forName()
    1. Class<?> clazz = Class.forName("类的全路径名");
  4.  通过类加载器获取(通过类加载器获取 Class 对象不会进行初始化)
    1. Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass("类的全路径名");

反射实例

public class Person {

    private String name;

    public 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;
    }

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }

    private void privateMethod(String name){
        this.name = name;
        System.out.println("I will change my name to "+name);
    }

    public void publicMethod(int age){
        System.out.println("I am " + age + " years old");
    }
}

反射实例使用

@Test
public void m() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
    //获取 Person 类的 Class 对象并且创建 Person 类实例
    Class<?> clazz = Class.forName("com.wen.reflection.Person");
    Person person = (Person) clazz.newInstance();
    System.out.println(person);

    //获取 Person 类中定义的所有方法
    Method[] methods = clazz.getDeclaredMethods();
    for (Method method : methods) {
        System.out.println(method.getName());
    }

    //获取指定方法并调用
    Method publicMethod = clazz.getDeclaredMethod("publicMethod",int.class);
    publicMethod.invoke(person,23);

    //获取指定成员变量并对其参数进行修改
    Field name = clazz.getDeclaredField("name");
    //为了对类中的参数进行修改而取消安全检查
    name.setAccessible(true);
    name.set(person,"cheng");

    //调用 private 方法
    Method privateMethod = clazz.getDeclaredMethod("privateMethod", String.class);
    //为了调用private方法,而取消安全检查
    privateMethod.setAccessible(true);
    privateMethod.invoke(person,"wen");
}

应用场景

  • 像 Spring/Spring Boot、MyBatis 等框架中都大量使用了反射机制--动态代理

  • 注解 的实现也用到了反射
posted @   伊文小哥  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示