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:注解在运行时保留,可以通过反射机制访问。
相关推荐
xlsw_2 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹3 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭3 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
南宫生4 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石4 小时前
12/21java基础
java
李小白664 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp4 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶5 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb