当前位置: 首页 > article >正文

Java的反射(Reflection)

1.什么是反射

反射(Reflection)是Java被称为“准动态语言”的关键技术。反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
正常方式是通过完整的“包类”名称通过new来实例化对象。反射方式可以通过实例化对象调用getClass()方法来获得完整的“包类”名称。

2.Class类

在Object类中定义了getClass()方法,该方法的返回值是Class类,这个类是Java反射的源头。针对任何你想动态加载、运行的类,唯有先获得相应的Class对象。

    //获取Class对象的方法
    public static void main(String[] args) throws ClassNotFoundException {

        //方式一:通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1);

        //方式二:forName获得
        Class c2 = Class.forName("包名+类名");
        System.out.println(c2);

        //方式三:通过类名.class获得
        Class c3 = Person.class;
        System.out.println(c3);
    }

3.类加载器

  1. 类的加载过程:
    (1)加载(Load):将class文件加载到内存中,并为之创建一个java.lang.Class对象。此过程由类加载器完成。
    (2)链接(Link):将类的二进制数据合并到JVM中的过程。
    (3)初始化(Initialize):执行类构造器()方法的过程。由JVM负责对类进行初始化。
    在这里插入图片描述

  2. 类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。在这里插入图片描述

	public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

        //获取系统类加载器的父类加载器-->扩展加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);

        //获取扩展类加载器的父加载器-->根加载器(C/C++)
        ClassLoader parentParent = parent.getParent();
        System.out.println(parentParent);
	}

4.从Class对象获取信息

(1)访问 Class 对应的类所包含的属性
  1. 批量的属性:
    public Field[] getFields():获取所有public属性
    public Field[] getDeclaredFields():获取所有的属性
  2. 获取单个属性:
    public Field getField(String name): 获取单个的public属性
    public Field getDeclaredField(String name):获取任何属性
(2)访问 Class 对应的类所包含的方法
  1. 批量的方法:
    public Method[] getMethods():获取所有public构造器
    public Method[] getDeclaredMethods():获取所有的构造器
  2. 获取单个的方法:
    public Method getMethod(String name, Class… parameterTypes): 获取单个的public方法
    public Method getDeclaredMethod(String name, Class… parameterTypes):获取任何方法
(3)访问 Class 对应的类所包含的构造方法
  1. 批量的方法:
    public Constructor[] getConstructors():获取所有public构造器
    public Constructor[] getDeclaredConstructors():获取所有的构造器
  2. 获取单个的方法:
    public Constructor getConstructor(Class… parameterTypes): 获取单个的public构造器
    public Constructor getDeclaredConstructor(Class…parameterTypes):获取任何构造器

测试代码如下:

  1. 首先创建一个User实体类
class User{
    private int id;
    private int age;
    private String name;

    public User() {}

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 通过Class对象获取该实体类的方法、属性以及构造器
   public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.carry.reflection.User");

        //获得类的名字
        System.out.println(c1.getName());//包名+类名
        System.out.println(c1.getSuperclass());//类名

        //获得类的属性
        System.out.println("=======================");
        Field[] fields = c1.getFields();//只能找到public的属性
        fields = c1.getDeclaredFields();//找到全部属性
        for(Field field : fields){
            System.out.println(field);
        }

        //获得指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);

        //获得类的方法
        Method[] methods = c1.getMethods();//获得本类及其父类的所有方法
        for (Method method : methods) {
            System.out.println("正常的"+method);
        }
        methods = c1.getDeclaredMethods();//获得本类的所有方法
        for (Method method : methods) {
            System.out.println("getDeclaredMethods"+method);
        }

        //获得指定方法
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        //获得类的构造器
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("Declared"+constructor);
        }

        //获得指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(int.class,int.class,String.class);
        System.out.println("指定"+declaredConstructor);
    }

5.Class动态创建对象

  1. 使用 Class 对象的 newInstance() 方法创建对象
  2. 使用 Constructor 对象创建对象

测试代码如下:

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得Class对象
        Class c1 = Class.forName("com.carry.reflection.User");

        //构造一个对象
        User user = (User) c1.newInstance();//本质是调用了类的无参构造器
        System.out.println(user);

        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(int.class, int.class, String.class);
        User user2 = (User)constructor.newInstance(1, 18, "hello");
        System.out.println(user2);

        //通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        //通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke:激活的意思(对象,“方法的值”)
        setName.invoke(user3,"hi");
        System.out.println(user3.getName());

        //通过反射操作属性
        System.out.println("======================");
        User user4 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");

        //不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true)
        name.setAccessible(true);//取消安全检测
        name.set(user4,"hi2");
        System.out.println(user4.getName());
    }

6.通过反射获取泛型

通过反射的方法可以获得方法中的泛型。

  1. 首先创建两个测试方法,这两个方法的返回值和参数分别为泛型。
    public void test01(Map<String,User> map, List<User> list){
        System.out.println("test01");
    }

    public Map<String,User> test02(){
        System.out.println("test02");
        return null;
    }
  1. 分别通过Class获得两个方法的泛型。.
    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Test.class.getMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("#"+genericParameterType);
            if (genericParameterType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }

        method = Test.class.getMethod("test02",null);
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }

7.通过反射获取注解

  1. 定义两个注解
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableHello{
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldHello{
    String columnName();
    String type();
    int length();
}
  1. 定义一个实体类,在实体类中使用这两个注解
@TableHello("db_student")
class Student{

    @FieldHello(columnName = "db_id",type = "int",length = 10)
    private int id;
    @FieldHello(columnName = "db_age",type = "int",length = 10)
    private int age;
    @FieldHello(columnName = "db_name",type = "varchar",length = 5)
    private String name;

    public Student2() {
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 在主方法中获取实体类中的注解
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.carry.reflection.Student");

        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获得注解的value的值
        TableHello tableHello = (TableHello) c1.getAnnotation(TableHello.class);
        String value = tableHello.value();
        System.out.println(value);

        //获得类指定的注解
        Field field = c1.getDeclaredField("name");
        FieldHello annotation = field.getAnnotation(FieldHello.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }

http://www.kler.cn/a/420718.html

相关文章:

  • 使用ESP32通过Arduino IDE点亮1.8寸TFT显示屏
  • KAN-Transfomer——基于新型神经网络KAN的时间序列预测
  • 嵌入式硬件实战提升篇(三)商用量产电源设计方案 三路电源输入设计 电源管理 多输入供电自动管理 DCDC降压
  • Nginx学习-安装以及基本的使用
  • 嵌入式系统应用-LVGL的应用-平衡球游戏 part2
  • Linux详解:文件权限
  • AWTK fscript 中的 串口 扩展函数
  • Linux:systemd进程管理【1】
  • 如何在vue中禁用eslint检查?
  • Nextjs 前端设置正向代理 解决 跨域问题
  • GaussDB(类似PostgreSQL)常用命令和注意事项
  • springboot整合flowable工作流
  • 入门算法 二 递归
  • 用postgresql实现数组中的模糊字符串查询
  • 【C++】程序流程控制(中)
  • Linux系统 进程
  • 大模型开发和微调工具Llama-Factory-->安装
  • Unity下载文件断点续下
  • K8S疑难概念理解——Pod,应该以哪种Kind来部署应用,为什么不直接Pod这种kind?
  • 【Elasticsearch】04-RestAPI
  • 深度学习常用训练命令解释
  • 在线家具商城基于 SpringBoot:设计模式与实现方法探究
  • vue中v-for的细节
  • 02appdesigner学习记录
  • Kafka怎么发送JAVA对象并在消费者端解析出JAVA对象--示例
  • Flutter的文字高度及行高简单计算