2009-10-06 13 views
50

Ho una classe con informazioni su una persona che sembra qualcosa di simile:stampa tutte le variabili valore da una classe

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. 
} 

voglio toString() di tornare this.name +" - "+ this.locations + ... per tutte le variabili. Stavo cercando di implementarlo utilizzando la riflessione come mostrato da this question ma non riesco a stampare le variabili di istanza.

Qual è il modo corretto per risolvere questo problema?

+0

Che cosa è successo quando hai provato a farlo con la riflessione? Funziona per me ... – CPerkins

+0

Non sapevo cosa passare a field.get(). Dopo aver letto la risposta di cletus, apprendo che "questo" deve essere passato. – Macarse

+0

Possibile duplicato di [Dumping delle proprietà di un oggetto java] (http://stackoverflow.com/questions/603013/dumping-a-java-objects-properties) –

risposta

73

Da 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

L'implementazione pulita di questo è disponibile in commons-lang's ['ReflectionToStringBuilder'] (http://commons.apache.org/lang/api-release/org/apache/commons/lang3/builder/ReflectionToStringBuilder.html) –

+5

@SivakumarK il link è rotto usa: http://commons.apache.org/ corretto/commons-lang/apidocs/org/apache/commons/lang3/builder/ReflectionToStringBuilder.html invece – Kuchi

+0

@kuchi lo hanno aggiornato a 3.1 cambiando che nell'URL che ho dato lo farebbe funzionare –

7

Quando si accede al valore del campo, passare l'istanza anziché null.

Perché non utilizzare la generazione del codice qui? Ad esempio, Eclipse genererà un'implementazione reasoble toString per te.

32

Perché vuoi di reinventare la ruota quando ci sono opensource che stanno già facendo il lavoro abbastanza bene.

Sia apache common-langs e spring supporto alcuni builder molto flessibile

Per Apache, ecco come si fa riflessiva

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

Ecco come si fa se si desidera stampare solo i campi che ti preoccupi di.

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

Si può andare fino a "styling" l'output di stampa con non predefinito ToStringStyle o addirittura personalizzandolo con il proprio stile.

Non ho provato personalmente la primavera ToStringCreator api, ma sembra molto simile.

+0

spring one è zoppo, semplicemente lo disegna, non ci riflette –

8

toString generico() one-liner, utilizzando la riflessione e lo stile di personalizzazione:

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

questo non funziona per me. La mia classe sta avendo variabili private e metodi get-set –

22

Se si utilizza Eclipse, questo dovrebbe essere facile:

1.Press Alt + Maiusc + S

2.Scegliere "Genera toString() ..."

Buon divertimento! È possibile avere qualsiasi modello di toString() s.

Questo funziona anche con getter/setter.

0

Aggiunta con @cletus answer, È necessario recuperare tutti i campi del modello (gerarchia superiore) e impostare field.setAccessible(true) per accedere ai membri privati. Ecco il frammento di piena:

@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

Un altro approccio semplice è quello di lasciare Lombok generare il metodo toString per voi.

Per questo:

  1. Basta aggiungere Lombok al progetto
  2. Aggiungere l'annotazione @ToString alla definizione della classe
  3. Compilare la classe/progetto, ed è fatto

Quindi, ad esempio nel tuo caso, la tua classe sarebbe simile a questa:

@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. 
} 

Esempio di uscita in questo caso:

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

Maggiori dettagli circa how to use the annotation @ToString.

NB: È anche possibile lasciare Lombok generare il getters and setters per voi, here è l'elenco completo di funzionalità.

0

Se l'uscita dal ReflectionToStringBuilder.toString() non è abbastanza leggibile per voi, ecco il codice che:
1) ordina i nomi dei campi in ordine alfabetico
2) bandiere campi non nulli con l'asterisco nel all'inizio della riga

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

test harness:

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

mi metterò la mia risposta come segue:

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); 

     } 
    } 

} 
Problemi correlati