我有很多数据对象,我希望能够生成代表每个对象的String
,而不为每个对象实现toString
方法。
我正在考虑获取字段及其值的反射。
还有其他想法吗?
感谢。
答案 0 :(得分:20)
欢迎您使用雅加达的ToStringBuilder。它有2种模式,一种是需要使用API添加所需的所有字段,另一种是基于反射:
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
答案 1 :(得分:5)
使用JUtils插件在包级别生成toString方法
或者使用反射你可以尝试这样的事情:
public static void toString(Object object) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException{
Class c = object.getClass();
Method[] methods = c.getMethods();
for (Method method : methods) {
if(method.getName().startsWith("get")){
System.out.println(method.getName()+" -> " +method.invoke(object, null));
}
}
}
JUtil插件是最好的,因为如果你需要提供有关该对象的更多信息,这将允许你稍后更改对象的toString。
答案 2 :(得分:3)
如果你有很多对象,那么在每个类中使用代码检测而不是添加toString
(你可以在jar中更改.class或使用javaagent在加载时更改它们)。例如AspectJ会有所帮助,但还有很多其他选择。例如,你可以做这样的事情(使用AspectJ和ToStringBuilder from Apache Commons):
@Aspect
public class ToStringAspect {
@Around("execution(String *.toString()) && target(t) && within(your.target.package.*)")
public String toStringCall(Object t) {
return ToStringBuilder.reflectionToString(t);
}
}
ToStringBuilder非常灵活。例如如果您不需要通过设置StandardToStringStyle#setUseClassName(false):
来使用类名使用样式 public String toStringCall(Object t) {
StandardToStringStyle style = new StandardToStringStyle();
style.setUseClassName(false);
style.setUseIdentityHashCode(false);
ToStringBuilder builder = new ReflectionToStringBuilder(t, style);
return builder.toString();
}
答案 3 :(得分:1)
实现toString方法的方法很少。
思考(Apache库)
@Override
public String toString(){
return org.apache.commons.lang3.builder.ReflectionToStringBuilder.toString(this);
}
基于JSON的实现(GSON,Jackson库)
// GSON library for JSON
@Override
public String toString(){
return new com.google.gson.Gson().toJson(this);
}
// Jackson libabry for JSON/YAML
@Override
public String toString() {
try {
return new com.fasterxml.jackson.databind.ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
ToStringBuilder(可与apache-commons库一起使用)
@Override
public String toString() {
return new org.apache.commons.lang3.builder.ToStringBuilder(this).
append("field1", field1).
append("field2", field2).
toString();
}
硬核toString()实现
@Override
public String toString() {
return new StringBuilder()
.append("field1:"+field1)
.append("field2:"+field2)
.toString();
}
答案 4 :(得分:0)
toString
方法由Java中的每个类继承java.lang.Object
。我看不出你怎么能避免不实现(实际上覆盖)Object.toString
。此外,为每个类定义方法,而不是为每个对象定义方法。
您可以使用继承层次结构来解决此问题,方法是让您的类继承自覆盖默认toString
实现的公共类。此实现可能使用反射来反映类的字段(不是父类,但实际上是当前对象的类),并生成字符串。
如果您根本不想覆盖该方法,也可以调查字节码编织的使用。就个人而言,我认为投入字节码编织的努力并不值得,尤其是当你可以覆盖toString
时。
答案 5 :(得分:0)
某种静态String dataToString(Data data)
方法可能有效。我对反思没有任何了解,所以这是我的想法。
方法实现取决于数据对象的设置方式。继承还在进行吗?如果存在,则可以将超类型对象作为参数传入,并对所有数据全局使用该方法。您需要在方法中进行一些条件检查或其他形式的逻辑,具体取决于程序的设置方式,以返回正确的字符串。
有关您的程序的更多信息(如何设置,您想要打印什么,数据对象是什么等)可以帮助我更好地做出这个答案:)
答案 6 :(得分:0)
如果要为每个对象实现toString(),可以使用AspectJ。除此之外,您将无法为每个对象实施该方法。
答案 7 :(得分:0)
如上所述,您可以使用已经实现的库,如Apache commons-lang中的ReflectionToStringBuilder。如上所述。
或者使用 反射API 自行编写类似的smt。
以下是 某些示例 :
class ReflectionAnalyzer {
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;
}
}