2009-10-06 115 views
50

值我有一個關於一個人的信息類,看起來是這樣的:打印所有變量從一個類

public class Contact { 
    private String name; 
    private String location; 
    private String address; 
    private String email; 
    private String phone; 
    private String fax; 

    public String toString() { 
     // Something here 
    } 
    // Getters and setters. 
} 

我想toString()返回this.name +" - "+ this.locations + ...所有變量。我試圖用this question所示的反射來實現它,但我無法打印實例變量。

解決此問題的正確方法是什麼?

+0

當你試圖用反射來做什麼時發生了什麼?它適用於我... – CPerkins 2009-10-06 18:01:26

+0

我不知道要傳遞給field.get()。 在閱讀cletus的答案後,我知道「this」應該通過。 – Macarse 2009-10-07 13:09:23

+0

[轉儲Java對象的屬性]的可能的重複(http://stackoverflow.com/questions/603013/dumping-a-java-objects-properties) – 2016-10-14 14:49:03

回答

73

Implementing toString

public String toString() { 
    StringBuilder result = new StringBuilder(); 
    String newLine = System.getProperty("line.separator"); 

    result.append(this.getClass().getName()); 
    result.append(" Object {"); 
    result.append(newLine); 

    //determine fields declared in this class only (no fields of superclass) 
    Field[] fields = this.getClass().getDeclaredFields(); 

    //print field names paired with their values 
    for (Field field : fields ) { 
    result.append(" "); 
    try { 
     result.append(field.getName()); 
     result.append(": "); 
     //requires access to private field: 
     result.append(field.get(this)); 
    } catch (IllegalAccessException ex) { 
     System.out.println(ex); 
    } 
    result.append(newLine); 
    } 
    result.append("}"); 

    return result.toString(); 
} 
+11

清潔的實現可以在commons-lang的['ReflectionToStringBuilder'] (http://commons.apache.org/lang/api-release/org/apache/commons/lang3/builder/ReflectionToStringBuilder.html) – 2012-09-29 14:17:55

+5

@SivakumarK鏈接被破壞使用:http://commons.apache.org/正確/ commons-lang/apidocs/org/apache/commons/lang3/builder/ReflectionToStringBuilder.html而不是 – Kuchi 2013-08-20 16:26:33

+0

@kuchi他們已將其更新至3.1更改了我提供的網址將使其工作 – 2013-08-21 17:52:11

7

訪問字段值時,傳遞實例而不是null。

爲什麼不在這裏使用代碼生成?例如,Eclipse將爲您生成可重用的toString實現。

32

你爲什麼要當有開源那些已經在做這份工作很漂亮推倒重來。

兩個阿帕奇common-langsspring支持一些非常靈活的生成器模式

對於Apache,這裏是你如何做到這一點反思

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

這裏是你怎麼做,如果你只想打印字段你在乎。

@Override 
public String toString() 
{ 
    return new ToStringBuilder(this) 
     .append("name", name) 
     .append("location", location) 
     .append("address", address) 
     .toString(); 
} 

你可以去儘可能與自己的風格非默認ToStringStyle甚至定製它「造型」您的打印輸出。

我沒有親自嘗試彈簧ToStringCreator API,但它看起來非常相似。

+0

春天是跛腳,它只是它的樣式,沒有反射那裏 – 2013-08-30 20:08:34

8

通用的toString()一行程序,使用反射和樣式定製:

import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 
import org.apache.commons.lang3.builder.ToStringStyle; 
... 
public String toString() 
{ 
    return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE); 
} 
+0

這不適合我。我的課有私有變量和get-set方法 – 2013-10-28 07:05:44

22

如果您使用的是Eclipse,這應該是很容易:

1.Press Alt鍵 + + S

2.選擇「生成toString()...」

享受!你可以有任何toString()的模板。

這也適用於getter/setter。

0

此外,@cletus答案,您必須提取所有模型字段(上層),並設置field.setAccessible(true)訪問私人成員。以下是完整的片段:

@Override 
public String toString() { 
    StringBuilder result = new StringBuilder(); 
    String newLine = System.getProperty("line.separator"); 

    result.append(getClass().getSimpleName()); 
    result.append(" {"); 
    result.append(newLine); 

    List<Field> fields = getAllModelFields(getClass()); 

    for (Field field : fields) { 
     result.append(" "); 
     try { 
      result.append(field.getName()); 
      result.append(": "); 
      field.setAccessible(true); 
      result.append(field.get(this)); 

     } catch (IllegalAccessException ex) { 
//    System.err.println(ex); 
     } 
     result.append(newLine); 
    } 
    result.append("}"); 
    result.append(newLine); 

    return result.toString(); 
} 

private List<Field> getAllModelFields(Class aClass) { 
    List<Field> fields = new ArrayList<>(); 
    do { 
     Collections.addAll(fields, aClass.getDeclaredFields()); 
     aClass = aClass.getSuperclass(); 
    } while (aClass != null); 
    return fields; 
} 
2

另一個簡單的辦法是讓Lombok爲您生成toString方法。

對於這一點:

  1. 只需添加Lombok到項目
  2. 註釋@ToString添加到您的類
  3. 的定義編譯類/項目,它完成

因此,例如在你的情況下,你的班級應該是這樣的:

@ToString 
public class Contact { 
    private String name; 
    private String location; 
    private String address; 
    private String email; 
    private String phone; 
    private String fax; 

    // Getters and setters. 
} 

在這種情況下輸出的實施例:

Contact(name=John, location=USA, address=SF, [email protected], phone=99999, fax=88888) 

進一步瞭解細節how to use the annotation @ToString

注:您也可以讓Lombok產生getters and setters你,here是完整的功能列表。

0

如果從ReflectionToStringBuilder.toString()輸出是不夠的讀取你,這裏是代碼:
1)排序字段名稱的字母順序
2)標誌,在該行的開頭星號的非空字段

public static Collection<Field> getAllFields(Class<?> type) { 
    TreeSet<Field> fields = new TreeSet<Field>(
      new Comparator<Field>() { 
     @Override 
     public int compare(Field o1, Field o2) { 
      int res = o1.getName().compareTo(o2.getName()); 
      if (0 != res) { 
       return res; 
      } 
      res = o1.getDeclaringClass().getSimpleName().compareTo(o2.getDeclaringClass().getSimpleName()); 
      if (0 != res) { 
       return res; 
      } 
      res = o1.getDeclaringClass().getName().compareTo(o2.getDeclaringClass().getName()); 
      return res; 
     } 
    }); 
    for (Class<?> c = type; c != null; c = c.getSuperclass()) { 
     fields.addAll(Arrays.asList(c.getDeclaredFields())); 
    } 
    return fields; 
} 
public static void printAllFields(Object obj) { 
    for (Field field : getAllFields(obj.getClass())) { 
     field.setAccessible(true); 
     String name = field.getName(); 
     Object value = null; 
     try { 
      value = field.get(obj); 
     } catch (IllegalArgumentException | IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
     System.out.printf("%s %s.%s = %s;\n", value==null?" ":"*", field.getDeclaringClass().getSimpleName(), name, value); 
    } 
} 

測試工具:

public static void main(String[] args) { 
    A a = new A(); 
    a.x = 1; 
    B b = new B(); 
    b.x=10; 
    b.y=20; 
    System.out.println("======="); 
    printAllFields(a); 
    System.out.println("======="); 
    printAllFields(b); 
    System.out.println("======="); 
} 

class A { 
    int x; 
    String z = "z"; 
    Integer b; 
} 
class B extends A { 
    int y; 
    private double z = 12345.6; 
    public int a = 55; 
} 
0

我會得到我的回答如下:

import java.io.IOException; 
import java.io.Writer; 
import java.lang.reflect.Array; 
import java.lang.reflect.Field; 
import java.util.HashMap; 
import java.util.Map; 

public class findclass { 
    public static void main(String[] args) throws Exception, IllegalAccessException { 
     new findclass().findclass(new Object(), "objectName"); 
     new findclass().findclass(1213, "int"); 
     new findclass().findclass("ssdfs", "String"); 
    } 


    public Map<String, String>map=new HashMap<String, String>(); 

    public void findclass(Object c,String name) throws IllegalArgumentException, IllegalAccessException { 
     if(map.containsKey(c.getClass().getName() + "@" + Integer.toHexString(c.hashCode()))){ 
      System.out.println(c.getClass().getSimpleName()+" "+name+" = "+map.get(c.getClass().getName() + "@" + Integer.toHexString(c.hashCode()))+" = "+c);   
      return;} 
     map.put(c.getClass().getName() + "@" + Integer.toHexString(c.hashCode()), name); 
     Class te=c.getClass(); 
     if(te.equals(Integer.class)||te.equals(Double.class)||te.equals(Float.class)||te.equals(Boolean.class)||te.equals(Byte.class)||te.equals(Long.class)||te.equals(String.class)||te.equals(Character.class)){ 
      System.out.println(c.getClass().getSimpleName()+" "+name+" = "+c); 
      return; 
     } 


     if(te.isArray()){ 
      if(te==int[].class||te==char[].class||te==double[].class||te==float[].class||te==byte[].class||te==long[].class||te==boolean[].class){ 
       boolean dotflag=true; 
       for (int i = 0; i < Array.getLength(c); i++) { 
        System.out.println(Array.get(c, i).getClass().getSimpleName()+" "+name+"["+i+"] = "+Array.get(c, i)); 
       } 
       return; 
      } 
      Object[]arr=(Object[])c; 
      for (Object object : arr) { 
       if(object==null)  
        System.out.println(c.getClass().getSimpleName()+" "+name+" = null"); 
       else { 
        findclass(object, name+"."+object.getClass().getSimpleName()); 
       } 
      } 


     } 

     Field[] fields=c.getClass().getDeclaredFields(); 
     for (Field field : fields) { 
      field.setAccessible(true); 

      if(field.get(c)==null){ 
       System.out.println(field.getType().getSimpleName()+" "+name+"."+field.getName()+" = null"); 
       continue; 
      } 

      findclass(field.get(c),name+"."+field.getName()); 
     } 
     if(te.getSuperclass()==Number.class||te.getSuperclass()==Object.class||te.getSuperclass()==null) 
      return; 
     Field[]faFields=c.getClass().getSuperclass().getDeclaredFields(); 

     for (Field field : faFields) { 
      field.setAccessible(true); 
       if(field.get(c)==null){ 
        System.out.println(field.getType().getSimpleName()+" "+name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName()+" = null"); 
        continue; 
       } 
       Object check=field.get(c); 
       findclass(field.get(c),name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName()); 

     } 

    } 

    public void findclass(Object c,String name,Writer writer) throws IllegalArgumentException, IllegalAccessException, IOException { 
     if(map.containsKey(c.getClass().getName() + "@" + Integer.toHexString(c.hashCode()))){ 
      writer.append(c.getClass().getSimpleName()+" "+name+" = "+map.get(c.getClass().getName() + "@" + Integer.toHexString(c.hashCode()))+" = "+c+"\n");   
      return;} 
     map.put(c.getClass().getName() + "@" + Integer.toHexString(c.hashCode()), name); 
     Class te=c.getClass(); 
     if(te.equals(Integer.class)||te.equals(Double.class)||te.equals(Float.class)||te.equals(Boolean.class)||te.equals(Byte.class)||te.equals(Long.class)||te.equals(String.class)||te.equals(Character.class)){ 
      writer.append(c.getClass().getSimpleName()+" "+name+" = "+c+"\n"); 
      return; 
     } 


     if(te.isArray()){ 
      if(te==int[].class||te==char[].class||te==double[].class||te==float[].class||te==byte[].class||te==long[].class||te==boolean[].class){ 
       boolean dotflag=true; 
       for (int i = 0; i < Array.getLength(c); i++) { 
        writer.append(Array.get(c, i).getClass().getSimpleName()+" "+name+"["+i+"] = "+Array.get(c, i)+"\n"); 
       } 
       return; 
      } 
      Object[]arr=(Object[])c; 
      for (Object object : arr) { 
       if(object==null){ 
        writer.append(c.getClass().getSimpleName()+" "+name+" = null"+"\n"); 
       }else { 
        findclass(object, name+"."+object.getClass().getSimpleName(),writer); 
       } 
      } 


     } 

     Field[] fields=c.getClass().getDeclaredFields(); 
     for (Field field : fields) { 
      field.setAccessible(true); 

      if(field.get(c)==null){ 
       writer.append(field.getType().getSimpleName()+" "+name+"."+field.getName()+" = null"+"\n"); 
       continue; 
      } 

      findclass(field.get(c),name+"."+field.getName(),writer); 
     } 
     if(te.getSuperclass()==Number.class||te.getSuperclass()==Object.class||te.getSuperclass()==null) 
      return; 
     Field[]faFields=c.getClass().getSuperclass().getDeclaredFields(); 

     for (Field field : faFields) { 
      field.setAccessible(true); 
       if(field.get(c)==null){ 
        writer.append(field.getType().getSimpleName()+" "+name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName()+" = null"+"\n"); 
        continue; 
       } 
       Object check=field.get(c); 
       findclass(field.get(c),name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName(),writer); 

     } 
    } 

}