¿Cómo imprimo mi objeto Java sin obtener “SomeType @ 2f92e0f4”?
Tengo una clase definida de la siguiente manera:
public class Person {
private String name;
// constructor and getter/setter omitted
}
Intenté 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 Person
objetos:
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 : se trata de una sesión de preguntas y respuestas canónicas sobre este tema.
Respuestas
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 Object
clase (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, com.foo.MyType@2f92e0f4
por tanto, se puede explicar como:
com.foo.MyType
- el nombre de la clase, es decir, la clase estáMyType
en el paquetecom.foo
.@
- une la cuerda2f92e0f4
el código hash del objeto.
El nombre de las clases de matriz se ve un poco diferente, lo que se explica bien en los Javadocs para Class.getName()
. Por ejemplo, [Ljava.lang.String
significa:
[
- una matriz unidimensional (a diferencia de[[
o[[[
etc.)L
- la matriz contiene una clase o interfazjava.lang.String
- el tipo de objetos en la matriz
Personalización de la salida
Para imprimir algo diferente cuando llama System.out.println(myObject)
, debe anular el toString()
método en su propia clase. He aquí un ejemplo sencillo:
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 de com.foo.Person@12345678
.
Tenga en cuenta que toString()
es solo una forma de convertir un objeto en una cadena. Por lo general, esta salida debe describir completamente su objeto de una manera clara y concisa. Un mejor toString()
para nuestra Person
clase podría ser:
@Override
public String toString() {
return getClass().getSimpleName() + "[name=" + name + "]";
}
Que imprimir, por ejemplo, Person[name=Henry]
. Esa es una pieza de datos realmente útil para depurar / probar.
Si desea enfocarse en un solo aspecto de su objeto o incluir mucho formato de jazz, podría ser mejor definir un método separado en su lugar, por ejemplo String toElegantReport() {...}
.
Autogenerar la salida
Muchos IDE ofrecen soporte para la generación automática de un toString()
método, según los campos de la clase. Consulte los documentos de Eclipse e IntelliJ , por ejemplo.
Varias bibliotecas populares de Java también ofrecen esta función. Algunos ejemplos incluyen:
@ToString
anotación del Proyecto Lombok
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 del contenido de la matriz. Por ejemplo, considere esta matriz de Person
objetos:
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 llamado toString()
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 llamar .toString()
a 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 bonito toString()
como se discutió anteriormente.
Creo que apache proporciona una mejor clase de utilidad que proporciona una función para obtener la cadena
ReflectionToStringBuilder.toString(object)
Cada clase en Java tiene el toString()
método de forma predeterminada, que se llama si le pasa algún objeto de esa clase System.out.println()
. De forma predeterminada, 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. Ver 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);
}
}
En Eclipse, vaya a su clase, haga clic derecho-> fuente-> Generar toString()
;
Anulará el toString()
método e imprimirá el objeto de esa clase.
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);
}
}
En intellij, puede generar automáticamente el método toString presionando alt + inset 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 un String concatenando, varios atributos de la clase, para primitivas imprimirá sus valores y para tipos de referencia usará su tipo de clase (en este caso al método string de Test2).
De forma predeterminada, 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 imprima el objeto persona que lo usa System.out.prtinln(personObj);
, imprimirá el nombre de la persona en lugar del nombre de la clase y el código hash.
En su segundo caso, cuando intenta imprimir la matriz, imprime [Lcom.foo.Person;@28a418fc
el tipo de matriz y su código hash.
Si desea imprimir los nombres de las personas, hay muchas formas.
Podría escribir su propia función que itera a cada persona e imprime
void printPersonArray(Person[] persons){
for(Person person: persons){
System.out.println(person);
}
}
Puede imprimirlo usando Arrays.toString (). Esto me parece el más simple.
System.out.println(Arrays.toString(persons));
System.out.println(Arrays.deepToString(persons)); // for nested arrays
Puede imprimirlo de la forma Java 8 (utilizando secuencias y referencia de método).
Arrays.stream(persons).forEach(System.out::println);
También puede haber otras formas. Espero que esto ayude. :)
Si imprime directamente cualquier objeto de Persona, lo hará ClassName@HashCode
al Código.
en su caso com.foo.Person@2f92e0f4
se está imprimiendo. Donde Person
es una clase a la que pertenece el objeto y 2f92e0f4
es el código hash 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 intentas usar el objeto de Person
, se imprimirá el nombre
Class Test
{
public static void main(String... args){
Person obj = new Person("YourName");
System.out.println(obj.toString());
}
}
Si observa la clase Object (clase principal de todas las clases en Java), la implementación del método toString () es
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
siempre 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.
Logré hacer esto usando Jackson
Spring 5. Dependiendo del objeto, Jackson podría no funcionar en todos los casos.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
ObjectMapper mapper = new ObjectMapper();
Staff staff = createStaff();
// pretty print
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff);
System.out.println("-------------------------------------------------------------------")
System.out.println(json);
System.out.println("-------------------------------------------------------------------")
la salida sería algo como
-------------------------------------------------------------------
{
"id" : 1,
"internalStaffId" : "1",
"staffCms" : 1,
"createdAt" : "1",
"updatedAt" : "1",
"staffTypeChange" : null,
"staffOccupationStatus" : null,
"staffNote" : null
}
-------------------------------------------------------------------
Más ejemplos usando Jackson
aquí
Puedes probar GSON
también. Debería ser algo como esto:
Gson gson = new Gson();
System.out.println(gson.toJson(objectYouWantToPrint).toString());