前面一章 讲了怎么通过Class获取到成员(成员变量、成员方法、构造器),本篇文章开始详细讲解成员变量(java.lang.reflect.Field)的详细用法。

获取field的类型

有两种方式可以获取到field的属性,Field.getType()和Field.getGenericType(),其中getGenericType可以获取到泛型的标识符,如果这个field是泛型,则返回泛型的标识,如果不是泛型,这会转而调用getType获取到真正的类型,也就是Object。

这里可以提一下,Java里的泛型是假泛型,从字节码到可以执行文件的时候,已经把泛型擦除了,变成真正的类型,但是getType()调用时,并没有真正的类型代入,所以会返回所有的类的父类Object。

我们举个例子:

public class FieldSpy {

public boolean[][] b = {{ false, false }, { true, true } };

public String name = "Alice";

public List list;

public T val;

public static void main(String[] args) {

try {

Class> c = Class.forName(args[0]);

Field f = c.getField(args[1]);

System.out.format("Type: %s%n", f.getType());

System.out.format("GenericType: %s%n", f.getGenericType());

} catch (ClassNotFoundException x) {

x.printStackTrace();

} catch (NoSuchFieldException x) {

x.printStackTrace();

}

}

}

执行命令以及执行结果:

$ java FieldSpy FieldSpy b

Type: class [[Z

GenericType: class [[Z

$ java FieldSpy FieldSpy name

Type: class java.lang.String

GenericType: class java.lang.String

$ java FieldSpy FieldSpy list

Type: interface java.util.List

GenericType: java.util.List

$ java FieldSpy FieldSpy val

Type: class java.lang.Object

GenericType: T

检索和解析Field的修饰符

Field的修饰符可以通过public int getModifiers()方法获取,这个方法返回的是int型,代表意义可以参见修饰符,如果要判断一个field是否具有某个修饰符,可以通过位运算符&判断,比如判断一个field的修饰符是否有public属性:

Field f = OneClass.getField("field");

int modify = f.getModifiers();

return modify&Modifier.PUBLIC == Modifier.PUBLIC

可以看一个官方的例子:

enum Spy { BLACK , WHITE }

public class FieldModifierSpy {

volatile int share;

int instance;

class Inner {}

public static void main(String... args) {

try {

Class> c = Class.forName(args[0]);

int searchMods = 0x0;

for (int i = 1; i < args.length; i++) {

searchMods |= modifierFromString(args[i]);

}

Field[] flds = c.getDeclaredFields();

out.format("Fields in Class '%s' containing modifiers: %s%n",

c.getName(),

Modifier.toString(searchMods));

boolean found = false;

for (Field f : flds) {

int foundMods = f.getModifiers();

// Require all of the requested modifiers to be present

if ((foundMods & searchMods) == searchMods) {

out.format("%-8s [ synthetic=%-5b enum_constant=%-5b ]%n",

f.getName(), f.isSynthetic(),

f.isEnumConstant());

found = true;

}

}

if (!found) {

out.format("No matching fields%n");

}

// production code should handle this exception more gracefully

} catch (ClassNotFoundException x) {

x.printStackTrace();

}

}

private static int modifierFromString(String s) {

int m = 0x0;

if ("public".equals(s)) m |= Modifier.PUBLIC;

else if ("protected".equals(s)) m |= Modifier.PROTECTED;

else if ("private".equals(s)) m |= Modifier.PRIVATE;

else if ("static".equals(s)) m |= Modifier.STATIC;

else if ("final".equals(s)) m |= Modifier.FINAL;

else if ("transient".equals(s)) m |= Modifier.TRANSIENT;

else if ("volatile".equals(s)) m |= Modifier.VOLATILE;

return m;

}

}

这个例子的大致意思是查找输入类名是否具有输入的修饰符的成员变量,并把成员变量名,并且输出其是否是编译器生成的和是否输入枚举变量。

输入输出:

$ java FieldModifierSpy FieldModifierSpy volatile

Fields in Class 'FieldModifierSpy' containing modifiers: volatile

share [ synthetic=false enum_constant=false ]

$ java FieldModifierSpy Spy public

Fields in Class 'Spy' containing modifiers: public

BLACK [ synthetic=false enum_constant=true ]

WHITE [ synthetic=false enum_constant=true ]

$ java FieldModifierSpy FieldModifierSpy\$Inner final

Fields in Class 'FieldModifierSpy$Inner' containing modifiers: final

this$0 [ synthetic=true enum_constant=false ]

$ java FieldModifierSpy Spy private static final

Fields in Class 'Spy' containing modifiers: private static final

$VALUES [ synthetic=true enum_constant=false ]

是否是编译器生成可以通过方法 field.isSynthetic()判断。

是否是枚举变量可以通过方法field.isEnumConstant()判断。

是否是枚举变量我想很多人都明白,什么是编译器生成的成员变量呢?

比如枚举类型,每个枚举类型都有一个VALUES成员变量,这个变量我们并没有显式定义,但是可以通过它获取这个枚举类对应的所有没有常量,VALUES就是编译器生成的。

检索Field的注解

获取所有的注解可以用field.getDeclaredAnnotations()方式。

获取单个的可以用:

getAnnotatedType()

getAnnotation(Class annotationClass)

getAnnotationsByType(Class annotationClass)

实际上这几个方法都是从 class java.lang.reflect.AccessibleObject继承而来的,这里就不做详细介绍了。

设置和获取Field的值

set(Object obj, Object value)来设置Field,除了这个方式还有多种确定Field类型的方式,比如void setDouble(Object obj, double d)

Object get(Object obj)来获取Field的值,和set方法一直,get方法也有多种确定Field类型的方式,比如double getDouble(Object obj)。

以上方法都可能抛出NoSuchFieldException和IllegalAccessException异常。

官方文档上有一句话是这样说的: 因为这种访问通常违反了该类的设计意图,因此应尽可能谨慎的使用它。

前面就讲过,反射是破坏封装性的,违反的类的设计原则,所以能少用就少用。

这里要提一下setXXXX()内部如果是基础类型时要小心,这个方法不会进行装箱和拆箱操作,因为装箱和拆箱操作是编译器做的,运行时,JVM并不能做这个事情。

比如下面的例子就会抛出异常。

public class FieldTrouble {

public Integer val;

public static void main(String... args) {

FieldTrouble ft = new FieldTrouble();

try {

Class> c = ft.getClass();

Field f = c.getDeclaredField("val");

f.setInt(ft, 42); // IllegalArgumentException

} catch (NoSuchFieldException x) {

x.printStackTrace();

} catch (IllegalAccessException x) {

x.printStackTrace();

}

}

}

执行结果:

Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.lang.Integer field reflect.FieldTrouble.val to (int)42

at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)

at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:191)

at sun.reflect.UnsafeObjectFieldAccessorImpl.setInt(UnsafeObjectFieldAccessorImpl.java:114)

at java.lang.reflect.Field.setInt(Field.java:949)

at reflect.FieldTrouble.main(FieldTrouble.java:14)

做set方式之前可以通过isAssignableFrom方法来进行检测,检测之后再进行处理:

Integer.class.isAssignableFrom(int.class) == false;

int.class.isAssignableFrom(Integer.class) == false

另外,final 标识的成员变量是不能用set方法重新设置其值的,会抛出IllegalAccessException异常。

java反射设置access_Java反射之java.lang.reflect.Field相关推荐

  1. JAVA反射系列之Field,java.lang.reflect.Field使用获取方法。

    2019独角兽企业重金招聘Python工程师标准>>> 首先必须明一点 Field类主要是用来辅助获取和操作类的属性的! 1.怎么通过反射获取类的属性 先来看JDK提供的方法有如下几 ...

  2. 设置java进程名称_如何为Java程序设置进程名称? - java

    如果启动了Java程序,它将在系统进程中监视名称java.许多Java程序很难区分.因此,如果存在设置名称的方法,它将很好地显示在过程监视器中.我知道这在不同的操作系统上可能会有所不同. 一个简单的方 ...

  3. java安全级别设置_怎么调整java安全级别

    要在 Internet Explorer 中配置 Java 安全性,请执行以下操作: 启动 Internet Explorer,然后单击工具菜单上的 Internet 选项. 在 Internet 选 ...

  4. java偏好设置_Mountain lion下Java Preference(Java偏好设置)应用丢失

    Mountain lion 不是从lion升级上来的,是全新安装.安装完后,就未能在实用工具中发现 "Java 偏好设置"应用 查阅了一些文档,其中有建议安装http://supp ...

  5. java如何设置成中文字体,Java程序中文字体配置

    出自Linux Wiki 提示:此文已超过 8 年(3003 天)未更新,如发现内容过时或有误,欢迎改进:) 在Linux中,JAVA程序的中文默认可能不正常:或是显示为方框,或是不够清晰.这是由于J ...

  6. java http设置cookies_如何使用Java在Http Get方法中设置Cookies

    可以肯定的是,您应该从响应的Set-Cookie标头收集Cookie.要在后续请求中发回它们,您应该使用 URLConnection#addRequestProperty()逐个设置它们. 基本上: ...

  7. java 分析类_java--分析简单java类与反射的联系

    分析简单java类与反射的联系 web对反射的操作支持 在JSP之中有一种技术--javaBean.而且在jsp里面也配套有相应的操作方式,javaBean的核心在于简单java类,于是下面演示此操作 ...

  8. 注解和反射详细笔记。自定义注解,元注解,内置注解。反射机制,Java Reflection,Java内存分析,反射操作注解,java.lang.reflect.Method,Class

    文章目录 注解 什么是注解 内置注解 元注解 自定义注解 反射机制 静态语言 vs 静态语言 Java Reflection 反射相关的主要API Class类 Java内存分析 创建运行时类的对象 ...

  9. Java反射之java.lang.reflect.Method

    前一篇文章讲了Class中的成员变量(java.lang.reflect.Field)的常用使用方式以及其注意事项.我们接着讲Class中的方法(java.lang.reflect.Method). ...

最新文章

  1. mysql 表结构关系_mysql 表关系 与 修改表结构
  2. 转载:js跨域问题小结
  3. Django从理论到实战(part46)--View类
  4. tkinter 菜单添加事件_Python+tkinter设置Label字体、字号、样式、对齐方式、鼠标形状、响应鼠标事件...
  5. 前端学习(2756):condition模拟启动配置
  6. ORA-16019: cannot use LOG_ARCHIVE_DEST_1 with LOG_ARCHIVE_DEST or LOG_ARCHIVE_DUPLEX_DEST
  7. Serf:Gossip Protocol
  8. 计算机组成原理实验内存读数,计算机组成原理实验
  9. JAVA框架--hibernate、struts2、spring
  10. 完整的前端项目开发流程
  11. vs2013编译ffmpeg之三十五 xavs、xvidcore
  12. 从零开始编译LEDE固件 默认中文material主题_php_sir_新浪博客
  13. 通过PD4ML把html转pdf(包含显示页眉页脚,插入图片,显示页数)
  14. Let's talk OOP Again
  15. node: rimraf : 无法加载文件 C:\Users\goodDream\AppData\Roaming\npm\rimraf.ps1,因为在
  16. php自动驾驶面试题,一篇文章看懂“L0-L5”,自动驾驶分级标准最强解读
  17. 如何构建供应链服务平台?
  18. Redis(七) - 封装Redis工具类
  19. java华氏度xhuan_java摄氏度转换华氏度
  20. 转:乔布斯《遗失的访谈》全文:尘封16年的预见

热门文章

  1. Oracle 触发器使用实例
  2. Silve37.Silverlight和ASP.NET相互传参的两种常用方式(QueryString,Cookie)
  3. 机器学习者应知的五大深度学习框架
  4. FaceL:一个靠谱的开源人脸标注训练识别程序
  5. Springboot 原理篇(一)
  6. 易评:软银收购ARM会扼住中国芯发展的咽喉吗?
  7. openssl生成自签证书
  8. Java Se:自定义ClassLoader
  9. Reboot与init 6的区别
  10. 真正能解决 Windows 7下安装Office 2007—2010出现1402和1406类错误的方法