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:注解在运行时保留,可以通过反射机制访问。
相关推荐
RainbowSea6 分钟前
6. RabbitMQ 死信队列的详细操作编写
java·消息队列·rabbitmq
RainbowSea13 分钟前
5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
java·消息队列·rabbitmq
李少兄2 小时前
Unirest:优雅的Java HTTP客户端库
java·开发语言·http
此木|西贝2 小时前
【设计模式】原型模式
java·设计模式·原型模式
可乐加.糖2 小时前
一篇关于Netty相关的梳理总结
java·后端·网络协议·netty·信息与通信
s9123601012 小时前
rust 同时处理多个异步任务
java·数据库·rust
9号达人2 小时前
java9新特性详解与实践
java·后端·面试
cg50172 小时前
Spring Boot 的配置文件
java·linux·spring boot
啊喜拔牙3 小时前
1. hadoop 集群的常用命令
java·大数据·开发语言·python·scala
anlogic3 小时前
Java基础 4.3
java·开发语言