跳到主要内容

Java 反射

信息

示例代码:code/learn-java/com.xzp.demo.reflects

Java 的反射是一种能够在运行时动态获取和操作类、接口、方法和字段的能力。它允许程序在运行时获取类的结构,并且可以分析和调用类中的方法和成员变量。

反射机制可以使程序自省,可以检查自身的类和对象,并可以构造新的对象,以及调用他们的方法。反射是Java的核心机制之一,它为我们提供了一种操纵 Java 类的方式,从而可以更加灵活地使用 Java 类库。

在 Java 的反射应用中,最常见的就是对 Class 类的相关操作。以下是常用的 class 类常用反射接口:

  • String getName() 返回类的完整名称,包括包名
  • Class getSuperclass() 返回当前类的直接父类
  • Class getDeclaringClass() 返回声明当前类的Class对象
  • Class[] getInterfaces() 返回当前类实现的接口Class对象数组
  • int getModifiers() 返回类的修饰符(public、private、protected等)
  • Field[] getFields() 返回类的公共属性
  • Method[] getMethods() 返回类的公共方法
  • Constructor[] getConstructors() 返回类的构造方法
  • Field[] getDeclaredFields() 返回类的所有属性(包括私有属性)
  • Method[] getDeclaredMethods() 返回类的所有方法(包括私有方法)
  • Constructor[] getDeclaredConstructors() 返回类的所有构造方法(包括私有构造方法)
  • Object newInstance() 创建实例

示例:

首先我们需要创建一个 Person 类:

package com.test.demo;

public class Person {
String name;
int age;

public Person() {
}

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

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;
}

public void sayHello() {
System.out.println("你好,我是" + this.name + ",今年" + this.age + "岁");
}
private void test() {
System.out.println("this is test");
}

@Override
public String toString() {
return "Person{" + "name='" + name + ", age=" + age + "}";
}
}

接着是创建一个新的类,然后在该类里面去引用我们的 Person 类,并且利用反射机制去读取内部的属性:

package reflects;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class clazz = Class.forName("reflects.Person");

// 获取类名
String className = clazz.getName();
System.out.println("className is " + className); // className is reflects.Person

// 获取父类
Class superClass = clazz.getSuperclass();
System.out.println("superClass is " + superClass); // superClass is class java.lang.Object

// 获取声明类
Class declaringClass = clazz.getDeclaringClass();
System.out.println("declaringClass is " + declaringClass); // declaringClass is null

// 获取接口
Class[] interfaces = clazz.getInterfaces();
System.out.println("interfaces is " + interfaces); // interfaces is [Ljava.lang.Class;@4617c264

// 获取类的修饰符
int modifiers = clazz.getModifiers();
System.out.println("modifiers is " + modifiers); // modifiers are 1(Q:为什么是数字?)

// 获取类的公共属性(只能访问public属性)
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println("field is " + field.getName()); // field is name(要将Person类的属性加public修饰符)
}

// 获取类的公共方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println("method is " + method.getName());
}

// 获取类的构造方法
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("constructor is " + constructor.getName());
}

// 获取类的所有属性(包括私有属性)
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("declaredField is " + declaredField.getName());
}

// 获取类的所有方法(包括私有方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("declaredMethod is " + declaredMethod.getName());
}

// 获取类的所有构造方法(包括私有构造方法)
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println("declaredConstructor is " + declaredConstructor.getName());
}

// 创建实例
// Object obj = clazz.newInstance(); // JDK9已废弃
// System.out.println("obj is " + obj);
Object obj = null;
try {
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
obj = constructor.newInstance();
System.out.println("obj is " + obj); // obj is Person { name = null, age = 0 }.
} catch (NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}

使用 Class 对象时候需要注意哪些点?

  • 首先要了解 class 对象的作用,它的作用是可以获取类的信息,包括其中的成员变量、方法等
  • 如果要使用 class 对象,必须先要确定类的名称,通过 Class.forName() 方法来获取 class 对象
  • 使用 class 对象可以获取类的成员变量、方法、构造器等信息,但是需要注意的是,获取到的成员变量、方法等信息可能是 private 的,需要使用不同的反射机制来访问和使用