Java 类之 java.lang.reflect.Field
Java 类之 java.lang.reflect.Field
文章目录
一、概述
1、java.lang.Class 类获取字段的方法
获取全部公有字段(含继承的,不含私有的)
getField(String name)
:- 获取该类及其父类指定名称的公有字段。
- 如果字段不存在,则抛出
NoSuchFieldException
异常。
getFields()
:- 获取该类及其父类中所有公有字段的数组。
- 返回一个
Field
对象数组。
获取本类的所有字段(不含继承的,含私有的)
getDeclaredField(String name)
:- 获取该类中指定名称的任意访问权限的字段,包括私有字段。
- 如果字段不存在,则抛出
NoSuchFieldException
异常。
getDeclaredFields()
:- 获取该类中所有声明的字段,包括私有字段。
- 返回一个
Field
对象数组。
代码示例
// 获取公有字段(含继承的,不含私有的)
Field publicField = MyClass.class.getField("publicField");
System.out.println("Public Field: " + publicField);
// 获取所有公有字段(含继承的,不含私有的)
Field[] publicFields = MyClass.class.getFields();
System.out.println("All Public Fields: ");
for (Field field : publicFields) {
System.out.println(field);
}
// 获取本类的私有字段(不含继承的,含私有的)
Field privateField = MyClass.class.getDeclaredField("privateField");
System.out.println("Private Field: " + privateField);
// 获取本类的所有字段(不含继承的,含私有的)
Field[] allFields = MyClass.class.getDeclaredFields();
System.out.println("All Fields: ");
for (Field field : allFields) {
System.out.println(field);
}
2、java.lang.reflect.Field 类简介
java.lang.reflect.Field
类是 Java 反射机制中用于表示类的字段(成员变量)的类。它提供了一种在运行时获取和操作类的字段的方式。
3、类定义信息
public final class Field extends AccessibleObject implements Member
二、基本功能
1、基本功能
- 获取字段对象:
Class.getField(String name)
: 返回一个Field
对象,该对象反映了指定公有字段的类或接口。Class.getDeclaredField(String name)
: 返回一个Field
对象,该对象反映了指定声明字段的类或接口。
- 获取所有字段:
Class.getFields()
: 返回一个包含某个类或接口的所有公有字段的数组。Class.getDeclaredFields()
: 返回一个包含某个类或接口的所有字段的数组,包括私有字段。
- 操作字段:
Field.get(Object obj)
: 返回指定对象上此Field
表示的字段的值。Field.set(Object obj, Object value)
: 将指定对象上此Field
表示的字段设置为指定的新值。
- 字段信息获取:
Field.getName()
: 返回字段的名称。Field.getType()
: 返回字段的类型(Class
对象)。Field.getModifiers()
: 返回表示字段修饰符的整数。
- 访问字段修饰符:
Modifier.toString(int modifiers)
: 将修饰符转换为字符串形式。
- 设置可访问性:
Field.setAccessible(boolean flag)
: 设置字段的可访问性。如果字段是私有的,需要设置为true
才能访问。
2、代码示例
import java.lang.reflect.Field;
public class FieldExample {
public String publicField;
private int privateField;
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
FieldExample obj = new FieldExample();
// 获取公有字段对象
Field publicField = FieldExample.class.getField("publicField");
System.out.println("Public Field: " + publicField);
// 获取私有字段对象
Field privateField = FieldExample.class.getDeclaredField("privateField");
System.out.println("Private Field: " + privateField);
// 获取字段的名称、类型和修饰符
System.out.println("Field Name: " + publicField.getName());
System.out.println("Field Type: " + publicField.getType());
System.out.println("Field Modifiers: " + publicField.getModifiers());
// 获取并设置公有字段值
publicField.set(obj, "Hello, Public Field!");
System.out.println("Public Field Value: " + publicField.get(obj));
// 获取并设置私有字段值(需要设置可访问性)
privateField.setAccessible(true);
privateField.set(obj, 42);
System.out.println("Private Field Value: " + privateField.get(obj));
}
}
三、扩展
1、关于注解的方法
- 获取指定类型的注解:
Annotation getAnnotation(Class<? extends Annotation> annotationClass)
: 返回指定类型的注解对象,如果字段没有指定类型的注解,则返回 null。
- 获取所有注解:
Annotation[] getAnnotations()
: 返回包含此元素上存在的所有注解的数组。Annotation[] getDeclaredAnnotations()
: 返回直接存在于此元素上的所有注解的数组,与继承的注解无关。
- 判断是否存在指定类型的注解:
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
: 如果指定类型的注解存在于此元素上,则返回 true。
2、getAnnotations()
与 getDeclaredAnnotations()
的区别
getAnnotation
方法
- 该方法用于获取指定类型的注解,如果该注解不存在于该字段上,则返回
null
。 - 如果注解存在于该字段上,且是继承关系的,该方法会沿着继承链一直找到最终的注解。
- 这个方法也会考虑到注解的继承,即如果指定类型的注解不存在于当前字段上,但存在于该字段的父类或父接口上,也会被返回。
getDeclaredAnnotation
方法
- 该方法用于获取指定类型的注解,如果该注解不存在于该字段上,则返回
null
。 - 与
getAnnotation
不同的是,getDeclaredAnnotation
不会考虑继承关系,只会在当前字段上查找指定类型的注解。
3、其他注意点
访问控制: 如果字段是私有的,确保在使用前调用 setAccessible(true)
方法,以便绕过访问控制检查。否则,在访问私有字段时可能会抛出 IllegalAccessException
异常。
field.setAccessible(true);
静态字段: 如果操作的是静态字段,可以将对象设置为 null
,而不需要创建实例。
field.set(null, value); // 设置静态字段
Object value = field.get(null); // 获取静态字段的值
字段类型检查: 在设置字段值之前,最好进行类型检查,以确保所设置的值与字段的类型相匹配。否则,在运行时可能会抛出 IllegalArgumentException
。
if (field.getType() == int.class) {
field.setInt(object, 42);
}
异常处理: 在使用反射操作字段时,要考虑可能抛出的异常,如 NoSuchFieldException
、IllegalAccessException
等。适当地进行异常处理是很重要的。
try {
Field field = MyClass.class.getDeclaredField("fieldName");
// 其他操作
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
性能影响: 反射操作相比直接访问字段的性能较差。如果性能是一个关键问题,考虑使用其他手段,如直接访问字段或者使用生成的代码(如使用字节码增强库)。
字段注解: 如果你使用注解,注意使用 getAnnotation
或 getDeclaredAnnotation
方法时的细微差别,根据需求选择合适的方法。