Field作為反射中對應(yīng)類或?qū)ο笾械挠蚧蛘呓凶鰧傩缘牟僮黝悾宋仪耙黄恼轮械牡玫矫趾皖愋偷润镎拢現(xiàn)ield的作用不限于此烙荷。
*上篇文章:Java反射-初探反射基礎(chǔ))(點(diǎn)擊進(jìn)入) *
Java SE 8的Docs這樣說:A Field provides information about, and dynamic access to, a single field of a class or an interface. The reflected field may be a class (static) field or an instance field.
簡單理解就是:我們可用通過Field類對類或?qū)ο蟮膄ield進(jìn)行動態(tài)操作。
- 關(guān)于Field的一些方法:
返回值 | 名字和參數(shù) | 作用 |
---|---|---|
Object |
get(Object obj) |
返回這個object對應(yīng)field字段的Object |
xxx |
getXXX(Object obj) |
同上檬寂,不過XXX可以是Int,Char,Boolean等 |
void |
set(Object obj, Object value) |
設(shè)置obj對象的調(diào)用方法的這個field的值為value |
void |
setXXX(Object obj, XXX value) |
設(shè)置特定類型值,例setInt(Object obj,int value) |
Class |
getDeclaringClass() |
返回定義中的Class對象 |
String |
getName() |
得到名字的字符串 |
int |
getModifier() |
返回一個修飾符的值 |
Class |
getType() |
返回這個field的對象Class |
void |
setAccessible(boolean flag) |
設(shè)置是否允許set get |
boolean |
isAccessible() |
查看field是否允許set和get终抽。 |
... | ... | ... |
其他的可以去Java的官方文檔去查看。https://docs.oracle.com/javase/8/docs/api/
-
簡單案例:
package io.ilss.reflection; /** * className User * description User * * @author feng * @version 1.0 * @date 2019-01-26 19:11 */ public class User { private String username; private String password; private int sex; public String address; //注意這個是public public User() { } public User(String username, String password) { this.username = username; this.password = password; } ...//getter setter method }
package io.ilss.reflection; import java.lang.annotation.Annotation; import java.lang.reflect.Field; /** * className UserTest * description UserTest * * @author feng * @version 1.0 * @date 2019-01-26 19:12 */ public class UserTest { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { User user = new User("ilss", "ilss password"); Class cls = user.getClass(); //獲取username名字的Field Field usernameField = cls.getDeclaredField("username"); System.out.println(usernameField.toString()); //獲取user對象對應(yīng)的username Object o = getSafe(usernameField, user); System.out.println("The username value of user is " + o); //獲取基本數(shù)據(jù)類型 user.setSex(1); Field sexField = cls.getDeclaredField("sex"); sexField.setAccessible(true); sexField.setInt(user, 2); int sex = sexField.getInt(user); System.out.println("user sex : " + sex); //對user進(jìn)行修改值 pubic不需要setAccessible Field addressField = cls.getDeclaredField("address"); addressField.set(user, "ilss address"); System.out.println("user address : " + user.getAddress()); } public static Object getSafe(Field field, Object obj) { Object ret = null; try { if (field.isAccessible()) { ret = field.get(obj); } else { field.setAccessible(true); ret = field.get(obj); } } catch (IllegalAccessException e) { e.printStackTrace(); } return ret; } }
需要說的點(diǎn):
- setAccessible方法。是Field繼承自AccessibleObject類昼伴,AccessibleObject是Field匾旭、Method、Constuctor類的父類圃郊。簡單理解意思就是 如果類型是private修飾的价涝,你不可以直接訪問,就需要設(shè)置訪問權(quán)限為true.如果是public則不需要設(shè)置持舆。
- set和get調(diào)用的時候都需要確鄙瘢可以訪問,不然如果不能訪問拋出IllegalAccessException逸寓。
制作一個通用的toString(Object obj)方法
package io.ilss.reflection;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
/**
* className ObjectAnalyzer
* description ObjectAnalyzer
*
* @author feng
* @version 1.0
* @date 2019-01-26 19:34
*/
public class ObjectAnalyzer {
private ArrayList<Object> visited = new ArrayList<>();
public String toString(Object obj) {
//無效處理
if (obj == null) {
return "null";
}
//注意 如果不判斷contains可能會出現(xiàn)無限遞歸調(diào)用居兆。
if (visited.contains(obj)) {
return "...";
}
//將已經(jīng)處理的做記錄
visited.add(obj);
Class cls = obj.getClass();
//如果為String類型就直接返回
if (cls == String.class) {
return (String) obj;
}
//是否數(shù)組
if (cls.isArray()) {
//用StringBuilder來append字符串
StringBuilder r = new StringBuilder(cls.getComponentType() + "[]{");
//利用relect包的Array操作類來便利
for (int i = 0; i < Array.getLength(obj); i++) {
if (i > 0) {
r.append(",");
}
Object val = Array.get(obj, i);
// getComponentType() 得到數(shù)組對象元素的類型
// isPrimitive()是判斷是否是基本數(shù)據(jù)類型
if (cls.getComponentType().isPrimitive()) {
r.append(val);
} else {
//不是基本數(shù)據(jù)類型就遞歸調(diào)用。
r.append(toString(val));
}
}
return r + "}";
}
StringBuilder ret = new StringBuilder(cls.getName());
do {
ret.append("[");
Field[] fields = cls.getDeclaredFields();
//對fields數(shù)組的所有訪問權(quán)限設(shè)置為true
AccessibleObject.setAccessible(fields, true);
for (Field f : fields) {
//只對非static參數(shù)處理
if (!Modifier.isStatic(f.getModifiers())) {
//如果不是第一個就加逗號
if (!ret.toString().endsWith("[")) {
ret.append(",");
}
ret.append(f.getName()).append("=");
try {
//對field的值進(jìn)行獲取
Class t = f.getType();
Object val = f.get(obj);
//基本數(shù)據(jù)類型就直接append 不是就遞歸調(diào)用
if (t.isPrimitive()) {
ret.append(val);
} else {
ret.append(toString(val));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ret.append("]");
//處理父類
cls = cls.getSuperclass();
}
while (cls != null);
return ret.toString();
}
@Override
public String toString() {
//利用自己調(diào)用toString(this)來實(shí)現(xiàn)自己的toString
return this.toString(this);
}
}
注意:
里面有個Array類席覆,是java.lang.reflect包下一個數(shù)組操作類史辙。代碼里的調(diào)用意思都不難理解。就不解釋了
- 調(diào)用類
package io.ilss.reflection;
import java.util.ArrayList;
import java.util.List;
/**
* className ObjectAnalyzerTest
* description ObjectAnalyzerTest
*
* @author feng
* @version 1.0
* @date 2019-01-26 19:30
*/
public class ObjectAnalyzerTest {
public static void main(String[] args) {
List<Integer> squares = new ArrayList<>();
for (int i = 0; i < 5; i++) {
squares.add(i * i);
}
System.out.println(new ObjectAnalyzer().toString(squares));
System.out.println(new ObjectAnalyzer().toString());
User[] arr = new User[10];
System.out.println(new ObjectAnalyzer().toString(arr));
User user = new User("ilss", "ilss password");
System.out.println(new ObjectAnalyzer().toString(user));
}
}
相關(guān)代碼的github:https://github.com/imyiren/java-base-ilss