前言
日常开发中,我们可使用反射获取JavaBean的属性信息,而描述属性信息的就是Java Field,Field类位于java.lang.reflect包下。
Field
Field类提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或这个类的实例字段。
/**
* A {@code Field} provides information about, and dynamic access to, a
* single field of a class or an interface. The reflected field may
* be a class (static) field or an instance field.
*
* <p>A {@code Field} permits widening conversions to occur during a get or
* set access operation, but throws an {@code IllegalArgumentException} if a
* narrowing conversion would occur.
*
* @see Member
* @see java.lang.Class
* @see java.lang.Class#getFields()
* @see java.lang.Class#getField(String)
* @see java.lang.Class#getDeclaredFields()
* @see java.lang.Class#getDeclaredField(String)
*
* @author Kenneth Russell
* @author Nakul Saraiya
*/
public final class Field extends AccessibleObject implements Member {
// ...
}
getModifiers
以整数形式返回由此Field对象表示的字段的Java语言修饰符(例如private, final, static等)。
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class User {
private String name;
private Integer age;
}
public static void main(String[] args) throws Exception {
Class<?> userClass = User.class;
// private
// private
for (Field field : userClass.getDeclaredFields()) {
System.out.println(Modifier.toString(field.getModifiers()));
}
}
getType
- 返回一个Class对象,它标识了此Field对象所表示字段的类型。
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class User {
private String name;
private Integer age;
}
public static void main(String[] args) throws Exception {
Class<?> userClass = User.class;
for (Field field : userClass.getDeclaredFields()) {
// class java.lang.String
// class java.lang.Integer
System.out.println(field.getType());
}
}
getName
- 返回此Field对象表示的字段的名称。
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class User {
private String name;
private Integer age;
}
public static void main(String[] args) throws Exception {
Class<?> userClass = User.class;
for (Field field : userClass.getDeclaredFields()) {
// name
// age
System.out.println(field.getName());
}
}
set
将指定对象变量上此Field对象表示的字段设置为指定的新值。如果底层字段的类型为基本类型,则对新值进行自动拆装箱。那么就会有如下几种场景:
- 如果底层字段是静态字段,则忽略指定对象变量,对象变量而且也可以为null。
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class User {
public static String name;
private Integer age;
}
public static void main(String[] args) throws Exception {
User user = new User();
Field field = user.getClass().getField("name");
field.set(null, "Duan");
// User(age=null)
System.out.println(user);
// User(age=null)
field.set(user, "Duan");
System.out.println(user);
}
- 如果底层字段是实例字段,如果指定对象变量为null,则该方法将抛出一个NPE,见代码片段2。
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class User {
public String name;
public Integer age;
}
public static void main(String[] args) throws Exception {
User user = new User();
Field field = user.getClass().getField("name");
// NullPointerException
field.set(null, "Duan");
System.out.println(user);
}
- 如果指定对象变量不是声明底层字段的类或接口的实例,则该方法将抛出一个IllegalArgumentException。
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class User {
public String name;
public Integer age;
}
public static void main(String[] args) throws Exception {
User user = new User();
Field field = user.getClass().getField("name");
// IllegalArgumentException
field.set(new Object(), "Duan");
System.out.println(user);
}
- 如果字段为final字段,则该方法将抛出一个IllegalAccessException,除非设置setAccessible,并且该字段是一个非静态字段。在通过程序的其他部分可以访问类的实例之前,只有使用空白final字段反序列化或重构类的实例期间,以这种方式设置final字段才有意义。在其他任何上下文中使用该方法都可能会有不可预知的结果,包括程序的其他部分继续使用该字段的原始值的情况。
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class User {
public final String name = "";
public Integer age;
}
public static void main(String[] args) throws Exception {
User user = new User();
Field field = user.getClass().getField("name");
// IllegalArgumentException
field.set(user, "Duan");
System.out.println(user);
}
- 如果底层字段的类型为某一基本类型,则可以尝试使用解包转换将新值转换为基本类型的值。如果该尝试失败,则此方法将抛出一个IllegalArgumentException。
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class User {
public String name;
public int age;
}
public static void main(String[] args) throws Exception {
User user = new User();
Field field = user.getClass().getField("age");
field.set(user, 28);
// " java.lang.IllegalArgumentException: Can not set int field User.age to java.lang.Long
field.set(user, 22L);
System.out.println(user);
}
get
返回指定对象上此Field表示的字段的值。如果该值是一个基本类型值,则自动将其包装在一个对象中。get的几种场景,与set基本类似,此不在过多赘述。
常用方法
getType | 获取属性声明时类型对象,返回class对象。 |
---|---|
getGenericType | 返回属性的Type类型,可以试试如果是泛型的返回。 |
getAnnotations | 获得这个属性上所有的注解。 |
getName | 获取属性声明时名字。 |
getModifiers | 获取属性的修饰。 |
set | 向obj对象的这个Field设置值。 |
get | 取得obj对象这个Field上的值。 |
isSynthetic | 判断这个属性是否是合成字段,判断此字段是否为合成字段,如果是则返回true; 否则返回false |
isEnumConstant | 判断这个属性是否是枚举类。 |