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 的,需要使用不同的反射机制来访问和使用