Java反射基础(二)--Fileds对象的使用
在說(shuō)Filed之前,我們先來(lái)了解一下Member接口. 反射中定義了一個(gè)接口?java.lang.reflect.Member?.?java.lang.reflect.Field,?java.lang.reflect.Method, 和java.lang.reflect.Constructor?都實(shí)現(xiàn)了該接口.我們將在接下來(lái)的部分介紹這些類.對(duì)于每個(gè)Member, 我們都會(huì)介紹相關(guān)的API去獲取和操作該Member.每個(gè)概念我們都會(huì)使用示例代碼和示例輸出說(shuō)明.
?
1.獲得字段(Field)的類型
一個(gè)filed可以是一個(gè)基本數(shù)據(jù)類型或者一個(gè)引用類型.java中有八種基本的數(shù)據(jù)類型: boolean,?byte,?short,?int,?long,?char,?float,??double.引用類型可以使任何的直接或者間接的繼承java.lang.Object?的接口,數(shù)組,或者枚舉等.
FiledSpy示例類實(shí)現(xiàn)了將一個(gè)給定的類的二進(jìn)制文件中包含的field類型和泛型打印出來(lái).
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();}} }實(shí)例輸出:
$ 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的類型是一個(gè)二維的布爾型數(shù)組.
字段val的類型被認(rèn)定為java.lang.Object.因?yàn)榉盒偷膶?shí)現(xiàn)方式是在編譯的過程中將和泛型有關(guān)的信息用相關(guān)的類替換.因此此處為java.lang.Object.
?
2.獲取和解析字段修飾符(Filed Modifier)
java中有以下幾種字段修飾符:
- 訪問控制修飾符:?public,?protected, and?private
- 運(yùn)行時(shí)領(lǐng)域管理修飾符:?transient?and?volatile
- 控制一個(gè)實(shí)例修飾符:?static
- 禁止值修改修飾符:?final
- 注解
方法Field.getModifiers()可以用來(lái)獲得一個(gè)以整型表示的字段修飾符.這些整形被定義在java.lang.reflect.Modifier中.
示例類FieldModifierSpy說(shuō)明了如何搜索一個(gè)類中指定的修飾符所修飾的字段.
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 ]注意到一些字段被顯示出來(lái),雖然他們并沒有被定義在該類的源代碼中.原因是編譯器會(huì)自動(dòng)生成一些字段(synthetic fields? :這些字段指的是不是有用戶顯示聲明的,而是在編譯的時(shí)候,由編譯器合成的).如果你想要知道一個(gè)字段是否是合成的(synthetic), 也已使用Field.isSynthetic()方法.合成字段的集合是依賴于編譯器的.然而普遍的使用this$0在內(nèi)部類中表示最外層的封裝類.枚舉中使用$VALUES類定義隱式的靜態(tài)方法values().合成類的名稱不一定總是一樣的,不同的編譯器可能有不同的名字.并且并不是所有的合成字段都會(huì)被聲明為public.
因?yàn)镕ield實(shí)現(xiàn)了java.lang.reflect.AnnotatedElement接口,因此我們也可以使用java.lang.annotation.RetentionPolicy.RUNTIME獲取運(yùn)行時(shí)注解.具體示例見Examining Class Modifiers and Types..
?
3.獲取和設(shè)置字段值.
給我們一個(gè)Class實(shí)例,我們可以使用反射去修改字段的值.這經(jīng)常被使用在不能通過通常的方式修改該字段的值的環(huán)境下.因?yàn)檫@樣的操作通常違反類的設(shè)計(jì)意圖,這應(yīng)該被謹(jǐn)慎的使用.
?
Book示例類說(shuō)明了如何設(shè)置long, array, enum類型的字段值.其他類型的對(duì)應(yīng)方法,參考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注意: 通過反射設(shè)置字段的值往往需要很多的操作.因?yàn)楹芏囝~外的操作必須被執(zhí)行,例如檢測(cè)數(shù)據(jù)的可訪問性.但是從運(yùn)行時(shí)的角度來(lái)看,結(jié)果是一樣的.因?yàn)樗械牟僮鞅豢醋鲆粋€(gè)院子操作來(lái)執(zhí)行,等同于直接修改該變量的值.
e:使用反射會(huì)導(dǎo)致一些運(yùn)行時(shí)優(yōu)化失效.例如,下面的代碼很容易被java虛擬機(jī)優(yōu)化: int x = 1; x = 2; x = 3;
但是如果使用反射,則要使用Field.set*(),這是優(yōu)化失效.
?
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Java反射基础(二)--Fileds对象的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 会话 临时表,Oracle
- 下一篇: java实现文件合并_Java实现文件分