Java反射

1.反射(Reflection)的定义

指程序在运行期间可以获取到一个对象的全部信息。

2.java中的反射有何特别之处

反射使得Java程序在运行时可以调用反射API获取任何类的内部信息(比如成员变量,成员方法,构造器,接口,父类等),并且可以操作类的实例对象的属性以及方法。

在Java程序中,JWM加载完一个类后,在堆内存中就会产生该类的一个class对象,并且该class对象是唯一的,这个Class对象包含了该类的完整结构信息。

3.获取class类的实例

java 复制代码
// 1 通过类名.class
Class<Student> studentClass1 = Student.class;
System.out.println(studentClass1.hashCode());
// 2 通过Class.forName("类的全类名")  会抛出类未找到异常
Class<?> studentClass2 = Class.forName("com.example.reflect_test.reflect.Student");
System.out.println(studentClass2.hashCode());
// 3 通过对象.getClass获得
Class<? extends Student> studentClass3 = new Student().getClass();
System.out.println(studentClass3.hashCode());
// 4 获取父类实例
Class<? super Student> superclass = studentClass1.getSuperclass();

4.获取该类的属性,方法,接口,父类等

1.获取类名

java 复制代码
String name = studentClass1.getName();              //全类名
String simpleName = studentClass1.getSimpleName();  //单纯类名

2.获取属性(public)

java 复制代码
studentClass1.getField("username");           //指定属性
Field[] fields = studentClass1.getFields();   // 获取所有属性

3.获取属性(public和private)

java 复制代码
Field username = studentClass1.getDeclaredField("username");
Field[] declaredFields = studentClass1.getDeclaredFields();

4.获取方法(public) 包括父类的方法

java 复制代码
// 无参
Method add = studentClass1.getMethod("add");     // 指定方法
Method[] methods = studentClass1.getMethods();   // 所有方法

//有参
Method declaredMethod = studentClass1.getDeclaredMethod("add",String.class,String.class);
declaredMethod.invoke(student,"111","222");

5.获取方法(public和private构造方法) 不包括父类的方法

java 复制代码
Method declaredMethod = studentClass1.getDeclaredMethod("add");
Method[] declaredMethods = studentClass1.getDeclaredMethods();

6.获取类的构造器 (public构造方法)

java 复制代码
Constructor<Student> constructor1 = studentClass1.getConstructor(String.class,String.class);
Constructor<?>[] constructors = studentClass1.getConstructors();

7.获取类的构造器 (public和private构造方法)

java 复制代码
Constructor<Student> declaredConstructor = studentClass1.getDeclaredConstructor(String.class, String.class);

8.获取父类

java 复制代码
Class<? super Student> superclass = studentClass1.getSuperclass();

9.获取接口

java 复制代码
Class<?>[] interfaces = studentClass1.getInterfaces();

5.利用反射创建对象

1.使用newInstance创建(其本质上还是通过无参构造方法创建, 前提是类要有一个无参的public的构造方法)

java 复制代码
Student student = studentClass1.newInstance();

2.利用类的构造器创建对象,无论构造方法是无参还是有参,私有还是公有

java 复制代码
Constructor<Student> declaredConstructor = studentClass1.getDeclaredConstructor(String.class,String.class);  //构造方法参数类型
// 若该构造方法是私有的,如下设置关闭检测
declaredConstructor.setAccessible(true);
Student student = declaredConstructor.newInstance("lisi","wangwu");// 构造方法参数

6.通过反射调用普通方法

  • 无参
java 复制代码
// 1.获取该方法实例
Method declaredMethod = studentClass1.getDeclaredMethod("add");
// 如果该方法是私有的,如下设置关闭检测,提高性能
declaredMethod.setAccessible(true);
// 2.收件利用newInstance或构造器创建对象
Student student = studentClass1.newInstance();
// 3.使用invoke执行该方法(第一个参数是实例对象,第二个是方法传入参数)
declaredMethod.invoke(student,null); 
  • 有参
java 复制代码
// 1.获取该方法实例 (方法名+参数类型)
Method declaredMethod = studentClass1.getDeclaredMethod("add",String.class,String.class);
// 如果该方法是私有的,如下可设置可访问标志
declaredMethod.setAccessible(true);
// 2.利用newInstance或构造器创建对象
Student student = studentClass1.newInstance();
// 2.使用invoke执行该方法(第一个参数是实例对象,第二个是方法传入参数)
declaredMethod.invoke(student,"111","222");

7.通过反射操作属性

java 复制代码
// 1.获取属性实例
Field username = studentClass1.getDeclaredField("username");
// 如果该属性是私有的,如下设置关闭权限检测
username.setAccessible(true);
// 2.获取对象实例
Student student = studentClass1.newInstance();
// 设置属性值
username.get(student);
// 获取属性值
username.set(student,"李四");

8.通过反射获取注解

8.1 读取类上的注解

当作用于类上时,使用类对象.getAnnotation得到注解类型,然后就可以获取变量信息了

java 复制代码
// 自定义一个注解
@Target(ElementType.TYPE) // 该注解用于类上
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String username();
    int age();
}

@MyAnnotation(username = "lisi",age = 20)
class Student1 {
    
}

使用反射获取注解的变量

java 复制代码
// 首先获取类对象
Class<Student1> student1Class = Student1.class;
// 通过 类对象.getAnnotation 获取注解类型
MyAnnotation annotation = student1Class.getAnnotation(MyAnnotation.class);
// 获取变量信息
annotation.username();
annotation.age();

8.2 读取方法上的注解

当作用于方法上时,使用方法类型实例.getAnnotation得到注解类型

java 复制代码
@Target(ElementType.METHOD) // 该注解用于方法上
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String username();
    int age();
}

class Student1 {
    @MyAnnotation(username = "lisi",age = 20)
    public void add() {

    }
}

获取注解的变量

java 复制代码
Class<Student> studentClass = Student.class;
// 得到方法类型
Method add = studentClass.getDeclaredMethod("add");
// 方法类型实例.getAnnotation 获取注解
MyAnnotation annotation = add.getAnnotation(MyAnnotation.class);
// 注解里的变量
annotation.username();
annotation.age();

注解

自定义一个注解

java 复制代码
@Target(ElementType.TYPE)            //指定注解的生命周期(只在属性上生效)
@Retention(RetentionPolicy.RUNTIME)  //指定注解可以应用的目标元素
@interface Order {
    String value() default "";  //这是一个属性,并非方法,注解中比较特殊,加了括号
}

注解的生命周期分类

  • ElementType.TYPE:类、接口、枚举。
  • ElementType.FIELD:字段。
  • ElementType.METHOD:方法。
  • ElementType.PARAMETER:方法参数。
  • ElementType.CONSTRUCTOR:构造函数。
  • ElementType.LOCAL_VARIABLE:局部变量。
  • ElementType.ANNOTATION_TYPE:注解类型。
  • ElementType.PACKAGE:包。

注解可以应用的目标元素

  • RetentionPolicy.SOURCE:注解仅在源代码中保留,编译时会被丢弃。
  • RetentionPolicy.CLASS:注解在编译时被保留,但在运行时不可访问。
  • RetentionPolicy.RUNTIME:注解在运行时保留,可以通过反射机制访问。
相关推荐
我命由我123451 小时前
执行 Gradle 指令报错,无法将“grep”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
考虑考虑1 小时前
Sentinel安装
java·后端·微服务
凤凰院凶涛QAQ3 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
掘金_答案4 小时前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
猿与禅4 小时前
CosId 分布式 ID 生成器完全教程:从架构原理到生产落地
java·shardingsphere·雪花算法·分布式id·高性能·cosid·号段模式
MindUp4 小时前
企业网盘权限模型解析:多层级访问控制与审计能力选型指南
java·linux·运维
NG4774 小时前
【软件设计与体系结构】-策略设计模式
java·设计模式·软件工程
程序员天天困5 小时前
优雅记录操作日志:从注解到 SpEL 的全链路实践与开源方案对比
java·后端
战血石LoveYY5 小时前
Integer类型超限,导致数据异常
java·算法
乐观的Terry6 小时前
1、为什么要自己造发布系统
java·spring boot·后端·spring cloud·架构