JAVA 反射:

反射的真正价值在于处理编译时未知的类型,从而编写更通用化的代码。

一、反射基础概念

(一)什么是反射

反射是 Java 的一种机制,它允许程序在运行时获取任何已知名称的类的内部信息,包括类的属性、方法、构造函数等,并且能够在运行时操作这些成员。通过反射,Java 程序可以实现动态加载类、创建对象、调用方法等操作,这在许多场景下提供了极大的灵活性。

(二)反射的核心类

在 Java 反射体系中,Class类处于核心与基础的地位 ,它代表一个类的运行时实例。当 JVM 加载类时,会为每个类创建对应的Class对象,这个对象包含了类的完整元数据,像是类名、继承结构、实现的接口,以及类所拥有的属性、方法和构造函数等关键信息。通过Class类,可以获取到类的各种信息。

而Field、Method和Constructor类,则是依赖于Class类来获取并对类的不同成员进行具体操作。

  • Field:用于表示类的属性,通过Class类的getFields()(获取公共属性)或getDeclaredFields()(获取所有属性,包括私有属性)等方法获得Field实例后,便能够获取和设置属性的值。例如,使用field.get(obj)获取对象obj的属性值,field.set(obj, value)设置对象obj的属性值为value。
  • Method:用于表示类的方法,借助Class类的getMethods()(获取公共方法)或getDeclaredMethods()(获取所有方法,包括私有方法)等方法获取Method实例后,就可以通过method.invoke(obj, args)来调用方法,其中obj是方法所属的对象实例,args是方法参数,以此执行相应的业务逻辑。
  • Constructor:用于表示类的构造函数,通过Class类的getConstructors()(获取公共构造函数)或getDeclaredConstructors()(获取所有构造函数,包括私有构造函数)等方法获取Constructor实例后,能够使用constructor.newInstance(args)来创建类的实例,args为构造函数的参数。

二、反射的原理

Java 反射的实现依赖于 Java 虚拟机(JVM)在运行时对类的加载和管理机制。当 JVM 加载一个类时,会在内存中创建一个Class对象,这个对象包含了类的所有元数据信息,如类名、父类、接口、属性、方法等。反射机制就是通过操作这个Class对象及其相关的Field、Method、Constructor等对象来实现对类的动态操作。

三、获取 Class 的三种方式

(一)通过Class.forName(String className)

这是一种最常用的方式,它接收一个类的全限定名(包名 + 类名)作为参数,返回对应的Class对象。例如:

try {
    Class<?> clazz = Class.forName("com.example.MyClass");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

这种方式的好处是可以根据字符串动态加载类,常用于需要在运行时根据配置或其他条件决定加载哪个类的场景。

(二)通过对象的getClass()方法

如果已经有一个对象实例,可以通过调用其getClass()方法来获取对应的Class对象。例如:

MyClass myObject = new MyClass();
Class<?> clazz = myObject.getClass();

这种方式适用于已经有对象,需要获取其运行时类型信息的情况。

(三)通过类字面量ClassName.class

直接使用类的字面量形式获取Class对象,这种方式最为简洁直观。例如:

Class<?> clazz = MyClass.class;

这种方式在编译时就确定了类,通常用于在代码中明确知道类的情况下获取其Class对象。

四、如何操作类

  • 以下getXXX()方法,空参则获得对应结果的数组,指定参数(参数名)则获得单个变量。
  • getDeclaredXXX()方法,获取到的是所有成员,无关访问权限,不带Deaclared则获取的是public的成员。
    • 在获取到Field对象后,需要调用field.setAccessible(true)来打破封装,才允许访问私有成员,

(一)获取类的属性

通过Class对象的getFields()方法可以获取类的所有公共属性,返回一个Field数组。如果需要获取包括私有属性在内的所有属性,可以使用getDeclaredFields()方法。例如:

Class<?> clazz = MyClass.class;
Field[] fields = clazz.getFields();
for (Field field : fields) {
    System.out.println(field.getName());
}

(二)获取类的方法

使用Class对象的getMethods()方法获取类的所有公共方法,getDeclaredMethods()方法获取所有方法(包括私有方法)。例如:

Class<?> clazz = MyClass.class;
Method[] methods = clazz.getMethods();
for (Method method : methods) {
    System.out.println(method.getName());
}

(三)获取类的构造函数

通过Class对象的getConstructors()方法获取类的所有公共构造函数,getDeclaredConstructors()方法获取所有构造函数(包括私有构造函数)。例如:

Class<?> clazz = MyClass.class;
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
    System.out.println(constructor.getName());
}

(四)获取类的注解

  1. 获取类上的所有注解:可以使用Class对象的getAnnotations()方法,该方法会返回一个包含类上所有注解的数组。例如:
import java.lang.annotation.Annotation;

class MyClass {
    // 空类,仅用于示例
}

public class GetClassAnnotations {
    public static void main(String[] args) {
        Class<?> clazz = MyClass.class;
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("类上的注解: " + annotation.annotationType().getName());
        }
    }
}
  1. 获取类上特定类型的注解:使用Class对象的getAnnotation(Class<T> annotationClass)方法,传入想要获取的注解类型的Class对象,即可获取该类型的注解。如果类上不存在该类型的注解,则返回null。例如:
import java.lang.annotation.Annotation;

@interface MyAnnotation {
    String value();
}

@MyAnnotation("示例值")
class MyAnnotatedClass {
    // 空类,仅用于示例
}

public class GetSpecificClassAnnotation {
    public static void main(String[] args) {
        Class<?> clazz = MyAnnotatedClass.class;
        MyAnnotation myAnnotation = clazz.getAnnotation(MyAnnotation.class);
        if (myAnnotation!= null) {
            System.out.println("获取到的特定注解的值: " + myAnnotation.value());
        }
    }
}

五、如何操作对象

注:此处的对象也可以是从外部获取的,而并不是只有以下示例中通过类的反射的构造器新创建的对象。

(一)创建对象

通过Constructor对象的newInstance()方法可以创建类的实例。如果类有多个构造函数,可以根据参数类型选择合适的构造函数。例如:

Class<?> clazz = MyClass.class;
Constructor<?> constructor = clazz.getConstructor();
Object instance = constructor.newInstance();

(二)访问和修改对象的属性

获取Field对象后,通过field.get(Object obj)方法可以获取对象的属性值,field.set(Object obj, Object value)方法可以设置对象的属性值。需要注意的是,如果属性是私有的,需要先调用field.setAccessible(true)来打破封装。例如:

Class<?> clazz = MyClass.class;
Object instance = clazz.getConstructor().newInstance();
Field field = clazz.getDeclaredField("privateField");
field.setAccessible(true);
field.set(instance, "new value");
Object value = field.get(instance);

(三)调用对象的方法

获取Method对象后,通过method.invoke(Object obj, Object… args)方法可以调用对象的方法,其中args是方法的参数。例如:

Class<?> clazz = MyClass.class;
Object instance = clazz.getConstructor().newInstance();
Method method = clazz.getMethod("myMethod", String.class);
method.invoke(instance, "parameter");

具体实践:苍穹外卖笔记 – CMD137’s Blog 见公共字段自动填充

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇