Java的toString()使用reflection?
有一天,我正在为Java中的类写一个toString(),方法是将类的每个元素手动写入一个string,然后发现使用reflection可能会创build一个可以工作的通用toString()方法在所有类上。 IE会找出字段名称和值,并把它们发送到一个string。
获取字段名称非常简单,这是一名同事想出来的:
public static List initFieldArray(String className) throws ClassNotFoundException { Class c = Class.forName(className); Field field[] = c.getFields(); List<String> classFields = new ArrayList(field.length); for (int i = 0; i < field.length; i++) { String cf = field[i].toString(); classFields.add(cf.substring(cf.lastIndexOf(".") + 1)); } return classFields; }
使用工厂,我可以通过一次存储字段来减less性能开销,第一次调用toString()。 然而,find价值可能会更昂贵。
由于reflection的performance,这可能是比较实际的假设。 但是我对反思的想法感兴趣,并且我可以用它来改进我的日常节目。
Apache commons-lang ReflectionToStringBuilder为你做这个。
import org.apache.commons.lang3.builder.ReflectionToStringBuilder // your code goes here public String toString() { return ReflectionToStringBuilder.toString(this); }
W /reflection,因为我没有意识到的Apache库:
(请注意,如果你这样做,你可能需要处理子对象,并确保他们打印正确 – 特别是,arrays不会显示任何有用的东西)
@Override public String toString() { StringBuilder b = new StringBuilder("["); for (Field f : getClass().getFields()) { if (!isStaticField(f)) { try { b.append(f.getName() + "=" + f.get(this) + " "); } catch (IllegalAccessException e) { // pass, don't print } } } b.append(']'); return b.toString(); } private boolean isStaticField(Field f) { return Modifier.isStatic(f.getModifiers()); }
如果你使用的是Eclipse,你也可以看看JUtils toString生成器 ,它是静态的(在源代码中生成方法)。
另一个select是,如果您可以使用JSON,则是Google的GSON库。
public String toString() { return new GsonBuilder().setPrettyPrinting().create().toJson(this); }
这将为你做reflection。 这产生了一个很好的,易于阅读的JSON文件。 易于阅读是相对的,非技术人员可能会发现JSON威胁。
如果您不想每次都新build一个GSONBuilder,那么您也可以使GSONBuilder成为一个成员variables。
如果您有不能打印的数据(如stream)或者您不想打印的数据,则可以将@Expose标记添加到要打印的属性中,然后使用以下行。
new GsonBuilder() .setPrettyPrinting() .excludeFieldsWithoutExposeAnnotation() .create() .toJson(this);
不reflection,但我看了一下使用字节码操作生成toString方法(以及equals / hashCode)作为后编译步骤。 结果混杂。
您可以使用已经实现的库,如Apache commons-lang中的ReflectionToStringBuilder 。 如上所述。
或用reflectionAPI自己写类似的。
这是一个例子 :
class UniversalAnalyzer { private ArrayList<Object> visited = new ArrayList<Object>(); /** * Converts an object to a string representation that lists all fields. * @param obj an object * @return a string with the object's class name and all field names and * values */ public String toString(Object obj) { if (obj == null) return "null"; if (visited.contains(obj)) return "..."; visited.add(obj); Class cl = obj.getClass(); if (cl == String.class) return (String) obj; if (cl.isArray()) { String r = cl.getComponentType() + "[]{"; for (int i = 0; i < Array.getLength(obj); i++) { if (i > 0) r += ","; Object val = Array.get(obj, i); if (cl.getComponentType().isPrimitive()) r += val; else r += toString(val); } return r + "}"; } String r = cl.getName(); // inspect the fields of this class and all superclasses do { r += "["; Field[] fields = cl.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); // get the names and values of all fields for (Field f : fields) { if (!Modifier.isStatic(f.getModifiers())) { if (!r.endsWith("[")) r += ","; r += f.getName() + "="; try { Class t = f.getType(); Object val = f.get(obj); if (t.isPrimitive()) r += val; else r += toString(val); } catch (Exception e) { e.printStackTrace(); } } } r += "]"; cl = cl.getSuperclass(); } while (cl != null); return r; } }
这里是Netbeans相当于Olivier的答案; Netbeans的smart-codegen插件 。