toString
方法相信大家都不陌生适肠,在日常開發(fā)中我們經(jīng)常需要調(diào)用它來打印類的相關(guān)的信息,雖然可以通過重寫toString
方法以達(dá)到目的,但是每個(gè)類都去寫一個(gè)toSting
有的時(shí)候也是一件麻煩的事情佳励,所以本文將通過Java的反射機(jī)制來編寫一個(gè)可以供任意類使用的通用的toString
方法跨新。
具體的實(shí)現(xiàn)方式是先通過getDeclaredFileds
獲取所有的數(shù)據(jù)域背稼,然后使用setAccessible
將所有的域設(shè)置為可訪問的。對(duì)于每個(gè)域玻蝌,獲得到了名字和值蟹肘,再通過toString
方法將每個(gè)值轉(zhuǎn)換成字符串。
其次俯树,泛型toString
方法需要解釋幾個(gè)復(fù)雜的問題帘腹。循環(huán)引用將有可能導(dǎo)致無限遞歸。因此许饿,ObjectAnalyzer
將記錄已經(jīng)被訪問過的對(duì)象阳欲。
下面是實(shí)現(xiàn)代碼:
public static class ObjectAnalyzer {
//為了避免循環(huán)引用而導(dǎo)致的無限遞歸
private ArrayList<Object> visited = new ArrayList<>();
/**
* 將任意對(duì)象toString
*
* @param object object
* @return String
*/
@SuppressWarnings("WeakerAccess")
public String toString(Object object) {
if (object == null) return "null";
if (visited.contains(object)) return "...";
visited.add(object);
Class<?> c1 = object.getClass();
if (c1 == String.class) return (String) object;
//是否為數(shù)組
if (c1.isArray()) {
StringBuilder r = new StringBuilder(c1.getComponentType() + "[]{");
for (int i = 0; i < Array.getLength(object); i++) {
if (i > 0) {
r.append(",");
}
Object val = Array.get(object, i);
//Class.isPrimitive 判斷是否為原始類型(boolean char byte short int long float double )
if (c1.getComponentType().isPrimitive()) {
r.append(val);
} else {
r.append(toString(val));
}
}
return r.toString() + "}";
}
StringBuilder r = new StringBuilder(c1.getName());
do {
r.append("[");
//獲取所有的域(屬性)
Field[] fields = c1.getDeclaredFields();
//設(shè)置對(duì)象數(shù)組可訪問 true表示屏蔽Java語言的訪問檢查,使得私有屬性也可被查詢和設(shè)置
AccessibleObject.setAccessible(fields, true);
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers())) {
if (!r.toString().endsWith("[")) r.append(",");
r.append(field.getName()).append("=");
try {
Class<?> type = field.getType();
Object val = field.get(object);
//是否是原始類型
if (type.isPrimitive()) {
r.append(val);
} else {
r.append(toString(val));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
r.append("]");
c1 = c1.getSuperclass();
} while (c1 != null);
return r.toString();
}
}
測(cè)試類:
public class ReflectionTest {
public static void main(String[] args) {
ArrayList<Integer> squares = new ArrayList<>();
for (int i = 0; i <= 5; i++) {
squares.add(i * i);
}
System.out.println(new ReflectionUtils.ObjectAnalyzer().toString(squares));
}
}
打印結(jié)果:
java.util.ArrayList[elementData=class java.lang.Object[]{java.lang.Integer[value=0][][],java.lang.Integer[value=1][][],java.lang.Integer[value=4][][],java.lang.Integer[value=9][][],java.lang.Integer[value=16][][],java.lang.Integer[value=25][][],null,null,null,null},size=6][modCount=6][][]
注:該方法在JDK 1.9
及以上版本會(huì)報(bào)WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
警告:
暫時(shí)沒有弄清楚具體的原因陋率,想要消除此警告可以降低JDK版本(降到JDK 1.9以下)球化。