任何对象的java toString

时间:2011-07-24 15:37:21

标签: java reflection

我有很多数据对象,我希望能够生成代表每个对象的String,而不为每个对象实现toString方法。

我正在考虑获取字段及其值的反射。

还有其他想法吗?

感谢。

8 个答案:

答案 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方法的方法很少。

  1. 思考(Apache库)

    @Override
    public String toString(){
        return org.apache.commons.lang3.builder.ReflectionToStringBuilder.toString(this);
    }
    
  2. 基于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;
    }
    
  3. ToStringBuilder(可与apache-commons库一起使用)

    @Override
    public String toString() {
        return new org.apache.commons.lang3.builder.ToStringBuilder(this).
            append("field1", field1).
            append("field2", field2).
            toString();
    }
    
  4. 硬核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;
   }    
}