¿Cómo imprimo mi objeto Java sin obtener "SomeType @ 2f92e0f4"?

301

Tengo una clase definida de la siguiente manera:

public class Person {
  private String name;

  // constructor and getter/setter omitted
}

Traté de imprimir una instancia de mi clase:

System.out.println(myPerson);

pero me dio el siguiente resultado: com.foo.Person@2f92e0f4.

Algo similar sucedió cuando intenté imprimir una matriz de Personobjetos:

Person[] people = //...
System.out.println(people); 

Tengo la salida: [Lcom.foo.Person;@28a418fc

¿Qué significa esta salida? ¿Cómo cambio esta salida para que contenga el nombre de mi persona? ¿Y cómo imprimo colecciones de mis objetos?

Nota : esto pretende ser un Q&A canónico sobre este tema.

Duncan Jones
fuente
1
Puede usar la biblioteca GSON para convertir objetos a json y viceversa. Muy útil para depurar.
Ashish Rawat

Respuestas:

403

Antecedentes

Todos los objetos Java tienen un toString()método, que se invoca cuando intenta imprimir el objeto.

System.out.println(myObject);  // invokes myObject.toString()

Este método se define en la Objectclase (la superclase de todos los objetos Java). El Object.toString()método devuelve una cadena de aspecto bastante feo, compuesta por el nombre de la clase, un @símbolo y el código hash del objeto en hexadecimal. El código para esto se ve así:

// Code of Object.toString()
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

Un resultado como el que com.foo.MyType@2f92e0f4se puede explicar como:

  • com.foo.MyType - el nombre de la clase, es decir, la clase está MyTypeen el paquete com.foo.
  • @ - une la cuerda
  • 2f92e0f4 El código hash del objeto.

El nombre de las clases de matriz se ve un poco diferente, lo cual se explica bien en los Javadocs para Class.getName(). Por ejemplo, [Ljava.lang.Stringsignifica:

  • [- una matriz unidimensional (a diferencia de [[o [[[etc.)
  • L - la matriz contiene una clase o interfaz
  • java.lang.String - el tipo de objetos en la matriz

Personalizar la salida

Para imprimir algo diferente cuando llama System.out.println(myObject), debe anular el toString()método en su propia clase. Aquí hay un ejemplo simple:

public class Person {

  private String name;
  
  // constructors and other methods omitted
  
  @Override
  public String toString() {
    return name;
  }
}

Ahora, si imprimimos un Person, vemos su nombre en lugar decom.foo.Person@12345678 .

Tenga en cuenta que esta toString()es solo una forma de convertir un objeto en una cadena. Por lo general, esta salida debe describir completamente su objeto de manera clara y concisa. Un mejor toString()para nuestra Personclase podría ser:

@Override
public String toString() {
  return getClass().getSimpleName() + "[name=" + name + "]";
}

Lo que imprimiría, por ejemplo, Person[name=Henry] . Esa es una pieza de datos realmente útil para la depuración / prueba.

Si desea enfocarse en un solo aspecto de su objeto o incluir un gran formato de jazz, puede ser mejor definir un método separado, por ejemplo String toElegantReport() {...}.


Generando automáticamente la salida

Muchos IDE ofrecen soporte para autogenerar un toString()método, basado en los campos de la clase. Ver documentos para Eclipse e IntelliJ , por ejemplo.

Varias bibliotecas populares de Java también ofrecen esta característica. Algunos ejemplos incluyen:


Imprimir grupos de objetos

Así que has creado un bonito toString()para tu clase. ¿Qué sucede si esa clase se coloca en una matriz o una colección?

Matrices

Si tiene una matriz de objetos, puede llamar Arrays.toString()para producir una representación simple de los contenidos de la matriz. Por ejemplo, considere esta matriz de Personobjetos:

Person[] people = { new Person("Fred"), new Person("Mike") };
System.out.println(Arrays.toString(people));

// Prints: [Fred, Mike]

Nota: esta es una llamada a un método estático llamadotoString() en la clase Arrays, que es diferente a lo que hemos estado discutiendo anteriormente.

Si tiene una matriz multidimensional , puede usarla Arrays.deepToString()para lograr el mismo tipo de salida.

Colecciones

La mayoría de las colecciones producirán una salida bonita basada en la invocación .toString()de cada elemento.

List<Person> people = new ArrayList<>();
people.add(new Person("Alice"));
people.add(new Person("Bob"));    
System.out.println(people);

// Prints [Alice, Bob]

Por lo tanto, solo debe asegurarse de que los elementos de su lista definan un elemento agradable toString()como se discutió anteriormente.

Duncan Jones
fuente
return String.format( getClass().getSimpleName() + "[ name=%s ]", name);y realmente en lugar de nameusar el captador getName()(pero los captadores se omitieron en la clase Persona ...) pero si se utilizó un captador ...return String.format( getClass().getSimpleName() + "[ name=%s ]", getName());
CrandellWS
si tengo dos clases en el archivo java, entonces cómo crear un objeto de clase que no sea público A.java clase pública A {} clase B {} ------ C.java clase pública C {A a = nuevo A ( ); }
yatinbc
Tenga en cuenta que hay versiones sobrecargadas de Arrays.toString()modo que también puede usarlo para matrices de primitivas ( int[], double[]). También Arrays.deepToString()maneja arreglos multidimensionales de primitivas muy bien.
Ole VV
1
@ MasterJoe2 No estoy seguro, ¿tal vez pensaron que sería feo tratar de codificar valores negativos en la cadena?
Duncan Jones
55

Creo que apache proporciona una mejor clase de utilidad que proporciona una función para obtener la cadena

ReflectionToStringBuilder.toString(object)
Rohith K
fuente
55
Esto tiene la ventaja de que no requiere editar la clase, que a veces no es posible. Sin embargo, ¿cómo puedo imprimir recursivamente objetos anidados también?
lukas84
35

Cada clase en Java tiene el toString()método por defecto, que se llama si le pasa algún objeto de esa clase System.out.println(). Por defecto, esta llamada devuelve el className @ hashcode de ese objeto.

{
    SomeClass sc = new SomeClass();
    // Class @ followed by hashcode of object in Hexadecimal
    System.out.println(sc);
}

Puede anular el método toString de una clase para obtener una salida diferente. Mira este ejemplo

class A {
    String s = "I am just a object";
    @Override
    public String toString()
    {
        return s;
    }
}

class B {
    public static void main(String args[])
    {
        A obj = new A();
        System.out.println(obj);
    }
}
Pankaj Manali
fuente
3
Esta es una respuesta breve y bien planteada, pero para aclarar por qué OP se está obteniendo [Lcom.foo.Person;@28a418fccomo salida: esa también es la salida del toString()método, pero del que se implementa en la clase que se genera en tiempo de ejecución para el tipo Person[], no Person(ver stackoverflow.com/a/8546532/1542343 ).
gvlasov
Este resultado significa package.Class@Hashcode. El método predeterminado toString () tiene un tipo de retorno como. return Object.hasCode () o alguna declaración de devolución similar que devuelve código hash en forma hexadecimal junto con el nombre de la clase.
Pankaj Manali
14

En Eclipse, vaya a su clase, haga clic derecho-> fuente-> Generar toString();

Anulará el toString()método e imprimirá el objeto de esa clase.

ketankk
fuente
10

Prefiero usar una función de utilidad que usa GSON para deserializar el objeto Java en una cadena JSON.

/**
 * This class provides basic/common functionalities to be applied on Java Objects.
 */
public final class ObjectUtils {

    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

    private ObjectUtils() {
         throw new UnsupportedOperationException("Instantiation of this class is not permitted in case you are using reflection.");
    }

    /**
     * This method is responsible for de-serializing the Java Object into Json String.
     *
     * @param object Object to be de-serialized.
     * @return String
     */
    public static String deserializeObjectToString(final Object object) {
        return GSON.toJson(object);
    }
}
Agam
fuente
Debería ser return Gson.toJson(object);, de lo contrario funcionará perfectamente.
Nakrule
Es eso solo.
Agam
5

En intellij puede generar automáticamente el método toString presionando alt + recuadro y luego seleccionando toString () aquí hay una salida para una clase de prueba:

public class test  {
int a;
char b;
String c;
Test2 test2;

@Override
public String toString() {
    return "test{" +
            "a=" + a +
            ", b=" + b +
            ", c='" + c + '\'' +
            ", test2=" + test2 +
            '}';
 }
}

Como puede ver, genera una Cadena concatenando varios atributos de la clase, para las primitivas imprimirá sus valores y para los tipos de referencia usará su tipo de clase (en este caso, el método de cadena de Test2).

Mr.Q
fuente
4

Por defecto, cada objeto en Java tiene el toString()método que genera el ObjectType @ HashCode.

Si desea información más significativa, debe anular el toString()método en su clase.

public class Person {
  private String name;

  // constructor and getter/setter omitted

  // overridding toString() to print name
  public String toString(){
     return name;  
  }
}

Ahora cuando imprime el objeto persona usando System.out.prtinln(personObj); , imprimirá el nombre de la persona en lugar del nombre de clase y el código hash.

En su segundo caso, cuando intenta imprimir la matriz, imprime [Lcom.foo.Person;@28a418fcel tipo de matriz y su código hash.


Si desea imprimir los nombres de las personas, hay muchas formas.

Podrías escribir tu propia función que itera cada persona e imprime

void printPersonArray(Person[] persons){
    for(Person person: persons){
        System.out.println(person);
    }
}

Puede imprimirlo usando Arrays.toString (). Esto me parece lo más simple.

 System.out.println(Arrays.toString(persons));
 System.out.println(Arrays.deepToString(persons));  // for nested arrays  

Puede imprimirlo de la manera Java 8 (usando secuencias y referencia de método).

 Arrays.stream(persons).forEach(System.out::println);

Puede haber otras formas también. Espero que esto ayude. :)

adn.911
fuente
3

Si imprime directamente cualquier objeto de persona, se ClassName@HashCode en el Código.

en su caso se com.foo.Person@2f92e0f4esta imprimiendo. Where Persones una clase a la que pertenece el objeto y 2f92e0f4es hashCode del objeto.

public class Person {
  private String name;

  public Person(String name){
  this.name = name;
  }
  // getter/setter omitted

   @override
   public String toString(){
        return name;
   }
}

Ahora, si intenta usar el objeto de Person, imprimirá el nombre

Class Test
 {
  public static void main(String... args){
    Person obj = new Person("YourName");
    System.out.println(obj.toString());
  }
}
Vikrant Kashyap
fuente
2

Si observa la clase Object (clase padre de todas las clases en Java), la implementación del método toString () es

    public String toString() {
       return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

cada vez que imprima cualquier objeto en Java, se llamará a toString (). Ahora depende de usted si anula toString (), entonces su método llamará a otra llamada al método de la clase Object.

Yasir Shabbir Choudhary
fuente