[英]Java: Getting the properties of a class to construct a string representation
假设我有一个这样的类(并进一步假设所有私有变量:
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<String> 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()
方法,而不是为此使用反射。
另一个有趣的方法是使用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 使用反射或不反射。 也看看其他子类。
有这么一个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()”功能将创建以下内容:
@Override
public String toString() {
return "Item [i=" + i + ", j=" + j + ", k=" + k + ", l=" + l + ", m="
+ m + ", n=" + n + ", o=" + o + "]";
}
使用反射将允许以编程方式观察自己的字段,但反射本身是一个相当昂贵(读取:慢)的过程,因此除非确实需要,否则使用在运行时编写的固定toString
方法可能会更可取。
您可能会遇到速度问题。 如果您使用反射,与运行本机代码相比,它可能真的很慢。 如果您打算使用反射,那么您可能应该在内存中缓存要迭代的变量。
从good medopal answer 开始,您可以使用此代码来获得对象所有字段的字符串表示,即使您在其类之外(显然它仅适用于具有 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();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.