Java反射基础(二)--Fileds对象的使用

在说Filed之前,我们先来了解一下Member接口. 反射中定义了一个接口 java.lang.reflect.Member . java.lang.reflect.Fieldjava.lang.reflect.Method, 和java.lang.reflect.Constructor 都实现了该接口.我们将在接下来的部分介绍这些类.对于每个Member, 我们都会介绍相关的API去获取和操作该Member.每个概念我们都会使用示例代码和示例输出说明.

 

1.获得字段(Field)的类型

一个filed可以是一个基本数据类型或者一个引用类型.java中有八种基本的数据类型: booleanbyteshortintlongcharfloat,  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中有以下几种字段修饰符:

  • 访问控制修饰符: publicprotected, and private
  • 运行时领域管理修饰符: transient and volatile
  • 控制一个实例修饰符: 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*(),这是优化失效.

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499706.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java反射基础(三)--Methods对象的使用

Method 原文地址:http://docs.oracle.com/javase/tutorial/reflect/member/method.html 1.获得方法类型信息 一个方法的声明包括方法名,修饰符, 参数, 和返回类型,同时还有一些方法可能抛出的异常. 类 java.lang.reflect.Method 提供了一种方式让我们可以得到方法的这些信息. …

Guice基本用法

本文适合对依赖注入有相对了解的读者&#xff0c;文章中对于部分名词未作详细解释。对于没有恰当的中文与之对应的英文内容&#xff0c;遂未翻译 Guice简介 Guice 简介&#xff0c;本文中的内容也是参考该文档完成&#xff0c;如有不一致&#xff0c;以该文为准。 快速上手 …

Guice之Servlet基础

如果读者对于Guice没有大体的了解&#xff0c;可以参考本人的另一篇Guice基础文章 Guice 提供了一个完整的体系使得我们在web应用中也可以使用它作为依赖注入的工具. 为什么使用 Guice : 使用Guice的好处: 构造函数注入类型安全的, 方便的配置方式(只需要在web.xml中进行很…

矩阵 I : 矩阵基础

学习机器学习, 基础的线性代数知识是必备的基础功, 对于线性代数的探索, 矩阵是线性代数的主要研究对象. 今天我们就开始学习一下矩阵的基础知识. 这是本人关于线性代数矩阵的第一篇分享. 章节目录 矩阵及其基本运算 1.1 矩阵定义 1.2 矩阵基本运算(,-,*) 1.3 转置矩阵 1…

矩阵 II : 线性组的线性相关性

学习机器学习, 基础的线性代数知识是必备的基础功, 对于线性代数的探索, 向量组也是线性代数的重要基础. 今天我们就开始学习一下线性代数中重要的向量组知识. 这是本人关于线性组的线性相关性的学习分享. 章节目录 相关性基本概念 1.1 相性相关和线性无关 1.2 相性相关性的…

汇编语言笔记(一):基础

章节目录 简单程序 使用段简单字符串处理程序使用 bx, si, di, bp 寄存器寻址寻址方法指明数据长度div指令 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢! 本文中所有程序均在DOSBox下使用MASM, LINK编译运…

汇编学习笔记(二):转移指令

章节目录 转移指令原理 jmp 指令 jcxz 指令 loop 指令 ret 和 retf 指令 call 指令 callret 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢! 本文中所有程序均在DOSBox下使用MASM, LINK编译运行 转移指令…

汇编语言笔记(三): 标志寄存器

章节目录 简介 ZF 标志寄存器PF 标志寄存器SF 标志寄存器CF 标志寄存器OF 标志寄存器几条相关指令DF 标志寄存器PUSHF and POPF 标志寄存器 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢! 简介 8086 CPU…

汇编语言笔记(四):内中断

汇编语言笔记:内中断 章节目录 概念 中断过程示例: 0 号中断处理 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢! 概念 中断信息: 任何一个通用 CPU 都具备一种能力, 可以在执行完当前正在执行的指令之…

sync.Map 源码学习

golang 线程安全的 Map 作者水平有限,而并发博大精深. 如文章中有任何错误, 希望读者不吝指出.谢谢! 章节目录 Map 基本类型定义StoreLoadDeleteRange Map 基本类型定义## Map 这里我们先看一下 Map 都涉及到那些类型. type Map struct {// 互斥锁. 用于互斥的读写 dirty.…

ASN.1 学习

ASN.1 章节目录 简介常用数据类型 2.1 常见的简单类型 2.2 结构类型Basic Encoding RulesDistinguished Encoding Rules编码示例 5.1 BIT STRING 5.2 IA5String 5.3 INTEGER 5.4 NULL 5.5 OCTET STRING 5.6 UTCTime 5.6 OBJECT IDENTIFIER编码 Name (X.501 type) 参考 http://…

证书体系: PFX 文件格式解析

原文同时发布于本人个人博客&#xff1a; https://kutank.com/blog/cert-pfx/ 章节目录 PFX 简介PFX 格式解析 2.1 最外层结构 2.2 AuthenticatedSafe 结构 参考 https://tools.ietf.org/html/rfc7292. PFX 简介## 以下引用自维基百科 在密码学中&#xff0c;PKCS #12 定义了…

C10K 非阻塞 Web 服务器

本文由作为 Going Concurrency in Go 的作者 Nathan Kozyra 撰写, 解决了互联网上最著名,最受尊敬的挑战之一, 并试图通过核心 Go 包来解决它. 原文地址: https://hub.packtpub.com/c10k-non-blocking-web-server-go/ 我们已经构建了一些可用的应用程序,并且可以在日常使用的真…

MD5 算法描述及实现

MD5 算法的原理及实现 章节目录 简介算法描述 实现 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢! 简介## Wiki对其的描述: MD5消息摘要算法&#xff08;英语&#xff1a;MD5 Message-Digest Algorithm&…

SHA 算法描述与实现

SHA 算法的原理及实现 章节目录 简介算法描述 2.1 数据准备 2.1.1 数据填充 2.1.2 数据分块 2.1.3 设置初始 Hash 值 2.2 Hash 计算 2.2.1 SHA-1 2.2.2 SHA-256 2.2.3 SHA-512实现 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者…

SHA算法描述及实现

SHA 算法的原理及实现 章节目录 简介算法描述 2.1 数据准备 2.1.1 <数据填充 2.1.2 数据分块 2.1.3 设置初始 Hash 值 2.2 Hash 计算 2.2.1 SHA-1 2.2.2 SHA-256 2.2.3 SHA-512实现<b>作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, …

CNG 关于 Key 相关的操作

章节目录 简介创建 Key查看系统中的 Key从 Windows Store 导出 key导入 Key 到 Windows Store<b>作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢!</b> 简介 CNG 全称 Cryptography API: Next G…

Golang 词法分析器浅析

浅析 Go 语言的词法分析器 章节目录 简介TokenScanner例子 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢! 简介## 在本文我们将简单的走读 Go 语言的词法分析器实现(go/scanner/scanner.go). 本文基于 G…

如何读懂 C 语言复杂的声明

如何读懂 C 语言复杂的声明 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢! 参考<<C专家编程>> 废话 虽说 C 语言相比于其他更高级的语言来讲&#xff0c;有着非常精简的语法结构&#xff0c;对…

C 语言笔记: 链表节点实现技巧--struct的妙用

链表节点实现技巧–struct的妙用 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢! 废话 C 语言虽然只提供了非常简单的语法&#xff0c;但是丝毫不影响 C 语言程序员使用 C 来实现很多让人叹为观止的高级功能…