Java反射基础(二)--Fileds对象的使用
在说Filed之前,我们先来了解一下Member接口. 反射中定义了一个接口 java.lang.reflect.Member
. java.lang.reflect.Field
, java.lang.reflect.Method
, 和java.lang.reflect.Constructor
都实现了该接口.我们将在接下来的部分介绍这些类.对于每个Member, 我们都会介绍相关的API去获取和操作该Member.每个概念我们都会使用示例代码和示例输出说明.
1.获得字段(Field)的类型
一个filed可以是一个基本数据类型或者一个引用类型.java中有八种基本的数据类型: boolean, byte
, short
, int
, long
, char
, float
, double
.引用类型可以使任何的直接或者间接的继承java.lang.Object
的接口,数组,或者枚举等.
FiledSpy示例类实现了将一个给定的类的二进制文件中包含的field类型和泛型打印出来.
import java.lang.reflect.Field; import java.util.List;public class FieldSpy<T> {public boolean[][] b = {{ false, false }, { true, true } };public String name = "Alice";public List<Integer> 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());// production code should handle these exceptions more gracefully} 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.lang.Integer> $ java FieldSpy FieldSpy val Type: class java.lang.Object GenericType: T
字段b的类型是一个二维的布尔型数组.
字段val的类型被认定为java.lang.Object.因为泛型的实现方式是在编译的过程中将和泛型有关的信息用相关的类替换.因此此处为java.lang.Object.
2.获取和解析字段修饰符(Filed Modifier)
java中有以下几种字段修饰符:
- 访问控制修饰符:
public
,protected
, andprivate
- 运行时领域管理修饰符:
transient
andvolatile
- 控制一个实例修饰符:
static
- 禁止值修改修饰符:
final
- 注解
方法Field.getModifiers()
可以用来获得一个以整型表示的字段修饰符.这些整形被定义在java.lang.reflect.Modifier
中.
示例类
说明了如何搜索一个类中指定的修饰符所修饰的字段.FieldModifierSpy
import java.lang.reflect.Field; import java.lang.reflect.Modifier; import static java.lang.System.out;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 presentif ((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 ]
注意到一些字段被显示出来,虽然他们并没有被定义在该类的源代码中.原因是编译器会自动生成一些字段(synthetic fields :这些字段指的是不是有用户显示声明的,而是在编译的时候,由编译器合成的).如果你想要知道一个字段是否是合成的(synthetic), 也已使用Field.isSynthetic()
方法.合成字段的集合是依赖于编译器的.然而普遍的使用this$0在内部类中表示最外层的封装类.枚举中使用$VALUES类定义隐式的静态方法values().合成类的名称不一定总是一样的,不同的编译器可能有不同的名字.并且并不是所有的合成字段都会被声明为public.
因为Field实现了java.lang.reflect.AnnotatedElement
接口,因此我们也可以使用java.lang.annotation.RetentionPolicy.RUNTIME
获取运行时注解.具体示例见Examining Class Modifiers and Types..
3.获取和设置字段值.
给我们一个Class实例,我们可以使用反射去修改字段的值.这经常被使用在不能通过通常的方式修改该字段的值的环境下.因为这样的操作通常违反类的设计意图,这应该被谨慎的使用.
Book示例类说明了如何设置long, array, enum类型的字段值.其他类型的对应方法,参考java API.
import java.lang.reflect.Field; import java.util.Arrays; import static java.lang.System.out;enum Tweedle { DEE, DUM }public class Book {public long chapters = 0;public String[] characters = { "Alice", "White Rabbit" };public Tweedle twin = Tweedle.DEE;public static void main(String... args) {Book book = new Book();String fmt = "%6S: %-12s = %s%n";try {Class<?> c = book.getClass();Field chap = c.getDeclaredField("chapters");out.format(fmt, "before", "chapters", book.chapters);chap.setLong(book, 12);out.format(fmt, "after", "chapters", chap.getLong(book));Field chars = c.getDeclaredField("characters");out.format(fmt, "before", "characters",Arrays.asList(book.characters));String[] newChars = { "Queen", "King" };chars.set(book, newChars);out.format(fmt, "after", "characters",Arrays.asList(book.characters));Field t = c.getDeclaredField("twin");out.format(fmt, "before", "twin", book.twin);t.set(book, Tweedle.DUM);out.format(fmt, "after", "twin", t.get(book));// production code should handle these exceptions more gracefully} catch (NoSuchFieldException x) {x.printStackTrace();} catch (IllegalAccessException x) {x.printStackTrace();}} }
示例输出:
$ java Book BEFORE: chapters = 0AFTER: chapters = 12 BEFORE: characters = [Alice, White Rabbit]AFTER: characters = [Queen, King] BEFORE: twin = DEEAFTER: twin = DUM
e:使用反射会导致一些运行时优化失效.例如,下面的代码很容易被java虚拟机优化:
int x = 1; x = 2; x = 3;
但是如果使用反射,则要使用Field.set*(),这是优化失效.
Java反射基础(二)--Fileds对象的使用相关推荐
- Java反射基础(一)--Class对象获取
Classes Java中,任何一个对象要么是一个引用类型要么是基本数据类型.引用类型指的是那些直接或间接 Java.lang.Object的类.Classse,enum,和接口都是应用类型.基本类型 ...
- Java反射基础(三)--Methods对象的使用
Method 原文地址:http://docs.oracle.com/javase/tutorial/reflect/member/method.html 1.获得方法类型信息 一个方法的声明包括方法 ...
- 一篇文章弄懂Java反射基础和反射的应用场景
文章目录 一.Java反射定义 二.Java反射机制实现 1.Class对象获取 2.获取class对象的摘要信息 3.获取class对象的属性.方法.构造函数等 三.反射的应用场景 1.动态代理 2 ...
- java 反射基础知识
java 反射 基础知识 反射:reflection 反射关键类 java 反射部分应用 反射:reflection 在运行中分析类. 在运行中查看和操作对象. 基于反射自己创建对象. 调用不可以访问 ...
- java 反射基础 万字详解(Class-Constructor-Method-Field一条龙)
目录 前言 一.反射及其相关概念 1.什么是反射? 2.反射的用途: ①分析类: ②查看并使用对象: 3.反射的应用场景: 4.类加载器: 类的加载时机: 5.Class对象: 联系: 二.获取Cla ...
- java反射基础_Java反射基础(一)--Class对象获取
ClassesJava中,任何一个对象要么是一个引用类型要么是基本数据类型.引用类型指的是那些直接或间接 Java.lang.Object的类.Classse,enum,和接口都是应用类型.基本类型是 ...
- Java反射基础,代码示例
文章出处:https://blog.csdn.net/ylyang12/article/details/53469957 说明:本文,在转载时,对内容略作修改,更方便阅读,代码做了调试和格式整理,总之 ...
- java反射之获取class对象,Java之反射机制(获取Class对象的三种方式)
Java之反射机制(获取Class对象的三种方式) 开发工具与关键技术:MyEclipse 10,java 作者:刘东标 撰写时间:2019-06-14 如何得到各个字节码对应的实例对象? 每个类被加 ...
- java 反射基础_Java基础教程:反射基础
Java基础教程:反射基础 引入反射 反射是什么 能够动态分析类能力的程序称为反射.反射是一种很强大且复杂的机制. Class类 在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时的 ...
最新文章
- 中国首次!2021年图计算挑战赛揭榜,华中科技大团队夺冠
- 线性表的C/C++实现(数据结构 严蔚敏版)
- abap submit 的使用方法
- 线段树HDU1698(成段更新)
- python数据分享人力资源_Python数据分析帮你清晰的了解整理员工们的工作效率和整体满意度...
- css的属性是变量是怎么表达,CSS自定义属性(变量)
- 动态生成的DOM不会触发onclick事件的原因及解决方法
- [JSOI2009]瓶子和燃料【数论】
- Excel曲线拟合的精度问题
- 个人商业画布分析-0408-v1.0王玉娟
- 魔戒三曲,黑暗散去;人皇加冕,光明归来
- 数学建模清风微信公众号的习题答案(挑战篇-完结)
- 第六篇:R语言数据可视化之数据分布图(直方图、密度曲线、箱线图、等高线、2D密度图)
- fatal unable to auto-detect email address (got ‘...@...(none)‘)
- POI生成word文档,包括标题,段落,表格,统计图(非图片格式)
- linux下迅雷远程下载服务,在 Linux 下使用迅雷的另一种无入侵方式
- MariaDB 版本
- 广州一机房上冰块制冷,法国一数据中心烧成废墟……
- 从win10(1909)中彻底卸载智能云输入法
- 操作系统-处理器调度算法