java toString用于任何对象



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

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

还有其他想法吗?

谢谢。

欢迎您使用来自jakarta的ToStringBuilder。它有两种模式,一种需要使用API添加所有需要的字段,另一种是基于反射的:

@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this);
}

使用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,如果您需要提供有关该对象的更多信息。

如果您有很多对象,那么不要在每个类中添加toString,而是使用代码插装(您可以在jar中更改.class或在加载时使用javaagent更改它们)。例如,AspectJ会有帮助,但是还有很多其他的选择。例如,你可以做这样的事情(使用AspectJ和ToStringBuilder从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();
}

有几种方法可以实现toString方法。

  1. Reflections (Apache库)

    @Override
    public String toString(){
        return org.apache.commons.lang3.builder.ReflectionToStringBuilder.toString(this);
    }
    
  2. 基于JSON的实现(GSON, Jackson libraries)

    // 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();
    }
    

toString方法由Java中的每个类继承自java.lang.Object。我不明白你怎么能避免不实现(实际上覆盖)Object.toString。此外,方法是为每个类定义的,而不是为每个对象定义的。

您可以使用继承层次结构来解决这个问题,通过让您的类从覆盖默认toString实现的公共类继承。这个实现可以使用反射来反射类的字段(不是父类,而是当前对象的类),并生成字符串。

如果您根本不想覆盖该方法,还可以研究字节码编织的使用。就我个人而言,我不认为在字节码编织上投入的努力是不值得的,特别是当您可以覆盖toString时。

某种静态字符串dataToString(Data data)方法可能会起作用。我对反射一无所知,所以这是我的想法。

方法的实现取决于数据对象的设置方式。有遗传吗?如果有的话,您可以将超类类型的对象作为参数传入,并对所有数据全局使用该方法。您需要在方法中执行一些条件检查或其他形式的逻辑,以返回正确的字符串,具体取决于您的程序是如何设置的。

关于你的程序的更多信息(它是如何设置的,你想要打印什么,数据对象是什么,等等)将帮助我使这个答案更好:)

如果您想为每个对象实现toString(),您可以使用AspectJ。在这样的事情之外,您将被困在为每个对象实现方法。

如前所述,您可以使用已经实现的库,如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;
   }    
}

相关内容

  • 没有找到相关文章

最新更新