Java反射基础(二)--Fileds对象的使用
2015-10-25 17:50
701 查看
在说Filed之前,我们先来了解一下Member接口. 反射中定义了一个接口
和
我们都会介绍相关的API去获取和操作该Member.每个概念我们都会使用示例代码和示例输出说明.
1.获得字段(Field)的类型
一个filed可以是一个基本数据类型或者一个引用类型.java中有八种基本的数据类型:
boolean,
FiledSpy示例类实现了将一个给定的类的二进制文件中包含的field类型和泛型打印出来.
实例输出:
字段b的类型是一个二维的布尔型数组.
字段val的类型被认定为java.lang.Object.因为泛型的实现方式是在编译的过程中将和泛型有关的信息用相关的类替换.因此此处为java.lang.Object.
2.获取和解析字段修饰符(Filed Modifier)
java中有以下几种字段修饰符:
访问控制修饰符:
运行时领域管理修饰符:
控制一个实例修饰符:
禁止值修改修饰符:
注解
方法
示例类
示例输出:
注意到一些字段被显示出来,虽然他们并没有被定义在该类的源代码中.原因是编译器会自动生成一些字段(synthetic fields :这些字段指的是不是有用户显示声明的,而是在编译的时候,由编译器合成的).如果你想要知道一个字段是否是合成的(synthetic), 也已使用
因为Field实现了
Class Modifiers and Types..
3.获取和设置字段值.
给我们一个Class实例,我们可以使用反射去修改字段的值.这经常被使用在不能通过通常的方式修改该字段的值的环境下.因为这样的操作通常违反类的设计意图,这应该被谨慎的使用.
Book示例类说明了如何设置long, array, enum类型的字段值.其他类型的对应方法,参考java API.
示例输出:
注意: 通过反射设置字段的值往往需要很多的操作.因为很多额外的操作必须被执行,例如检测数据的可访问性.但是从运行时的角度来看,结果是一样的.因为所有的操作被看做一个院子操作来执行,等同于直接修改该变量的值.
e:使用反射会导致一些运行时优化失效.例如,下面的代码很容易被java虚拟机优化:
但是如果使用反射,则要使用Field.set*(),这是优化失效.
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, and
private
运行时领域管理修饰符:
transientand
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 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 ]
注意到一些字段被显示出来,虽然他们并没有被定义在该类的源代码中.原因是编译器会自动生成一些字段(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 = 0 AFTER: chapters = 12 BEFORE: characters = [Alice, White Rabbit] AFTER: characters = [Queen, King] BEFORE: twin = DEE AFTER: twin = DUM
注意: 通过反射设置字段的值往往需要很多的操作.因为很多额外的操作必须被执行,例如检测数据的可访问性.但是从运行时的角度来看,结果是一样的.因为所有的操作被看做一个院子操作来执行,等同于直接修改该变量的值.
e:使用反射会导致一些运行时优化失效.例如,下面的代码很容易被java虚拟机优化:
int x = 1; x = 2; x = 3;
但是如果使用反射,则要使用Field.set*(),这是优化失效.
相关文章推荐
- Spring学习笔记(三)
- eclipse中报错:Errors running builder “Integrated External Tool Builder” on project
- JAVA中return的用法
- Java基础学习8(程序流程控制)
- 主工程模块yycgproject三层构建
- Eclipse快捷键 10个最有用的快捷键
- java五分钟O(∩_∩)O哈哈~继承好坑
- Ubuntu安装JDK1.6
- Java程序如何生成Jar、exe及安装文件
- Eclipse项目转移到Android Studio
- java容器---Map集合的体系结构
- Java 中新增的 foreach 的用法
- 医药采购系统的主工程模块创建
- java在eclipse中的快捷键
- Java将一段逗号分割的字符串转换成一个数组
- Eclipse中写Hibernate的hbm.xml文件时不自动提示的问题解决
- Java的集合容器(上)
- Java 链接查询
- JAVA和JAVAC 命令行
- JAVAC 命令详解