Java:获取类的属性以构造字符串表示

假设我有一个这样的类(并且还假设所有私有变量:

public class Item { private String _id = null; private String _name = null; private String _description = null; ... } 

现在,如果我想构建这个类的toString()表示,我会在Item类中做这样的事情:

 @Override public String toString() { return (_id + " " + _name + " " + _description); } 

但是如果我在课堂上说15个私有变量呢? 我是否必须像这样写出每个变量的名称?

理想情况下,我想通过遍历此类的私有变量列表并构造字符串表示来完成任务:

 @Override public String toString() { ArrayList members = getClass().getMembers(); //Some method like this String string = ""; for(...) string += members[i] + " "; } 

或者也许是一个toJSON方法,我仍然需要访问这些变量的名称。 有什么建议么?

你可以这样做:

 @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getName()); sb.append(": "); for (Field f : getClass().getDeclaredFields()) { sb.append(f.getName()); sb.append("="); sb.append(f.get(this)); sb.append(", "); } return sb.toString(); } 

不要使用字符串连接来构造来自15个数据成员的最终结果,特别是如果要调用toString() 。 内存碎片和开销可能非常高。 使用StringBuilder构造大型动态字符串。

我通常让我的IDE(IntelliJ)为我生成toString()方法,而不是使用reflection。

另一个有趣的方法是使用Project Lombok中的@ToString注释 :

 import lombok.ToString; @ToString(excludes="id") public class ToStringExample { private static final int STATIC_VAR = 10; private String name; private Shape shape = new Square(5, 10); private String[] tags; private int id; @ToString(callSuper=true, includeFieldNames=true) public static class Square extends Shape { private final int width, height; public Square(int width, int height) { this.width = width; this.height = height; } } } 

我发现这比Jakarta Commons toString构建器更加可取,因为这种方法更易于配置,而且它也是在编译时而不是运行时构建的。

检查这个API org.apache.commons.lang.builder.ToStringBuilder ,它提供了多种方法来创建toString使用reflection或不reflection。 看看其他子类。

有这样一个api,它叫做Java Reflection

要完成您的要求,您可以简单地执行以下操作:

  Class cls = this.getClass(); Field fieldlist[] = cls.getDeclaredFields(); for (Field aFieldlist : fieldlist) { // build toString output with StringBuilder() } 

这应该是你正在寻找的

  public String toString() { StringBuilder sb = new StringBuilder(); try { Class c = Class.forName(this.getClass().getName()); Method m[] = c.getDeclaredMethods(); Object oo; for (int i = 0; i < m.length; i++) if (m[i].getName().startsWith("get")) { oo = m[i].invoke(this, null); sb.append(m[i].getName().substring(3) + ":" + String.valueOf(oo) + "\n"); } } catch (Throwable e) { System.err.println(e); } return sb.toString(); } 

大多数IDE提供了在给定类中创建toString方法的方法。

给定具有多个字段的Item类:

 class Item { int i; int j; int k; int l; int m; int n; int o; } 

例如,在Eclipse中,在上面的Item类中执行“Generate toString()”function将创建以下内容:

 @Override public String toString() { return "Item [i=" + i + ", j=" + j + ", k=" + k + ", l=" + l + ", m=" + m + ", n=" + n + ", o=" + o + "]"; } 

使用reflection将允许以编程方式观察自己的字段,但reflection本身是一个相当昂贵的(读取:慢)过程,因此除非确实需要,否则使用在运行时编写的固定toString方法可能会更加可取。

你可能会遇到速度问题。 如果您使用reflection,与运行本机代码相比,它可能非常慢。 如果你打算使用reflection,那么你应该有一个内存缓存,你要迭代的变量。

从良好的medopal答案开始 ,您可以使用此代码来获取对象的所有字段的字符串表示forms, 即使您在其类之外 (显然它仅适用于具有getter方法的字段):

 /**Gives a string representation of the fields of the object * @param obj the object * @return */ private static String objectToString(Object obj) { StringBuilder sb = new StringBuilder(); try { Class c = Class.forName(obj.getClass().getName()); Method m[] = c.getDeclaredMethods(); Object oo; for (int i = 0; i < m.length; i++) if (m[i].getName().startsWith("get")) { oo = m[i].invoke(obj, null); sb.append(m[i].getName().substring(3) + "=" + String.valueOf(oo) + "\n"); } } catch (Throwable e) { System.err.println(e); } return sb.toString(); }