Como imprimo meu objeto Java sem obter "SomeType @ 2f92e0f4"?

301

Eu tenho uma classe definida da seguinte maneira:

public class Person {
  private String name;

  // constructor and getter/setter omitted
}

Eu tentei imprimir uma instância da minha classe:

System.out.println(myPerson);

mas eu tenho o seguinte resultado: com.foo.Person@2f92e0f4.

Uma coisa semelhante aconteceu quando tentei imprimir uma matriz de Personobjetos:

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

Eu obtive a saída: [Lcom.foo.Person;@28a418fc

O que essa saída significa? Como altero essa saída para que ela contenha o nome da minha pessoa? E como imprimo coleções de meus objetos?

Nota : este é um questionário canônico sobre este assunto.

Duncan Jones
fonte
1
Você pode usar a biblioteca GSON para converter objetos em json e vice-versa. Muito útil para depuração.
Ashish Rawat
Veja também stackoverflow.com/questions/27647567/…
Raedwald 26/16

Respostas:

403

fundo

Todos os objetos Java possuem um toString()método que é chamado quando você tenta imprimir o objeto.

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

Este método é definido na Objectclasse (a superclasse de todos os objetos Java). O Object.toString()método retorna uma string de aparência bastante feia, composta pelo nome da classe, um @símbolo e o código de hash do objeto em hexadecimal. O código para isso se parece com:

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

Um resultado como o com.foo.MyType@2f92e0f4pode, portanto, ser explicado como:

  • com.foo.MyType - o nome da classe, ou seja, a classe está MyTypeno pacote com.foo.
  • @ - une a corda
  • 2f92e0f4 o código hash do objeto.

O nome das classes de matriz parece um pouco diferente, o que é explicado nos Javadocs Class.getName(). Por exemplo, [Ljava.lang.Stringsignifica:

  • [- uma matriz unidimensional (em oposição a [[ou [[[etc.)
  • L - a matriz contém uma classe ou interface
  • java.lang.String - o tipo de objetos na matriz

Personalizando a saída

Para imprimir algo diferente ao ligar System.out.println(myObject), você deve substituir o toString()método em sua própria classe. Aqui está um exemplo simples:

public class Person {

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

Agora, se imprimirmos um Person, veremos o nome deles em vez de com.foo.Person@12345678.

Lembre-se de que toString()é apenas uma maneira de um objeto ser convertido em uma string. Normalmente, essa saída deve descrever completamente seu objeto de maneira clara e concisa. Um melhor toString()para a nossa Personclasse pode ser:

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

O que imprimiria, por exemplo Person[name=Henry],. Esse é um dado realmente útil para depuração / teste.

Se você deseja focar apenas um aspecto do seu objeto ou incluir muita formatação jazzística, talvez seja melhor definir um método separado, por exemplo String toElegantReport() {...}.


Geração automática da saída

Muitos IDEs oferecem suporte para gerar automaticamente um toString()método, com base nos campos da classe. Consulte os documentos para Eclipse e IntelliJ , por exemplo.

Várias bibliotecas Java populares oferecem esse recurso também. Alguns exemplos incluem:


Imprimir grupos de objetos

Então você criou um ótimo toString()para sua classe. O que acontece se essa classe é colocada em uma matriz ou coleção?

Matrizes

Se você tiver uma matriz de objetos, poderá chamar Arrays.toString()para produzir uma representação simples do conteúdo da matriz. Por exemplo, considere esta matriz de Personobjetos:

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

// Prints: [Fred, Mike]

Nota: esta é uma chamada para um método estático chamado toString()na classe Arrays, que é diferente do que discutimos acima.

Se você tiver uma matriz multidimensional , poderá usar Arrays.deepToString()para obter o mesmo tipo de saída.

Colecções

A maioria das coleções produzirá uma saída bonita com base na chamada .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]

Então, você só precisa garantir que os elementos da sua lista definam um bom toString()como discutido acima.

Duncan Jones
fonte
return String.format( getClass().getSimpleName() + "[ name=%s ]", name);e realmente, em vez de nameele deve usar o getter getName()(mas getters foram omitidos na classe Pessoa ...) mas se foi utilizado um getter ...return String.format( getClass().getSimpleName() + "[ name=%s ]", getName());
CrandellWS
se eu tiver duas classes no arquivo java, como criar o objeto da classe que não é pública A.java public class A {} class B {} ------ C.java public class C {A a = new A ( ); }
yatinbc 10/10
Observe que há versões sobrecarregadas Arrays.toString()para que você possa usá-lo também para matrizes de primitivos ( int[], double[]). Também Arrays.deepToString()lida bem com matrizes multidimensionais de primitivas.
Ole VV
1
@ MasterJoe2 Não tenho certeza, talvez eles pensassem que seria feio tentar codificar valores negativos na string?
Duncan Jones
55

Eu acho que o apache fornece uma classe util melhor, que fornece uma função para obter a string

ReflectionToStringBuilder.toString(object)
Rohith K
fonte
5
Isso tem a vantagem de não exigir a edição da classe, o que às vezes não é possível. No entanto, como posso imprimir recursivamente objetos aninhados também?
Lukas84
35

Cada classe em Java possui o toString()método por padrão, que é chamado se você passar algum objeto dessa classe para System.out.println(). Por padrão, essa chamada retorna o className @ hashcode desse objeto.

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

Você pode substituir o método toString de uma classe para obter uma saída diferente. Veja este exemplo

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
fonte
3
Essa é uma resposta bem-colocada e curta, mas para esclarecer por que o OP está obtendo [Lcom.foo.Person;@28a418fccomo saída: essa também é a saída do toString()método, mas é aquela implementada na classe que é gerada em tempo de execução para o tipo Person[], não Person(consulte stackoverflow.com/a/8546532/1542343 ).
gvlasov
Esta saída significa package.Class@Hashcode. O método toString () padrão tem o tipo de retorno like. return Object.hasCode () ou alguma instrução de retorno semelhante que está retornando código hash em formato hexadecimal junto com o nome da classe.
Pankaj Manali
14

No Eclipse, Vá para a sua turma, Clique com o botão direito do mouse em-> fonte-> Gerar toString();

Ele substituirá o toString()método e imprimirá o objeto dessa classe.

ketankk
fonte
10

Prefiro usar uma função de utilitário que usa o GSON para desserializar o objeto Java na cadeia 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
fonte
Deveria ser return Gson.toJson(object);, caso contrário, funcionaria perfeitamente.
Nakrule 29/04
É apenas isso.
Agam
5

Em intellij, você pode gerar automaticamente o método toString pressionando alt + inset e, em seguida, selecionando toString () aqui está uma saída para uma classe de teste:

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 você pode ver, ele gera uma String concatenando vários atributos da classe, para primitivas imprime seus valores e para tipos de referência, usa seu tipo de classe (neste caso, para string do método Test2).

Mr.Q
fonte
4

Por padrão, todo objeto em Java possui o toString()método que gera o ObjectType @ HashCode.

Se você quiser informações mais significativas, precisará substituir o toString()método em sua classe.

public class Person {
  private String name;

  // constructor and getter/setter omitted

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

Agora, quando você imprimir o objeto da pessoa, System.out.prtinln(personObj);ele imprimirá o nome da pessoa em vez do nome da classe e do código de hash.

No segundo caso, quando você está tentando imprimir a matriz, ela imprime [Lcom.foo.Person;@28a418fco tipo de matriz e seu código de hash.


Se você deseja imprimir os nomes das pessoas, existem várias maneiras.

Você pode escrever sua própria função que itera cada pessoa e imprime

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

Você pode imprimi-lo usando Arrays.toString (). Isso parece o mais simples para mim.

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

Você pode imprimi-lo da maneira java 8 (usando fluxos e referência de método).

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

Pode haver outras maneiras também. Espero que isto ajude. :)

adn.911
fonte
3

Se você imprimir diretamente qualquer objeto de Pessoa, será ClassName@HashCodeo código.

no seu caso com.foo.Person@2f92e0f4está sendo impresso. Onde Personé uma classe à qual o objeto pertence e 2f92e0f4é hashCode do objeto.

public class Person {
  private String name;

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

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

Agora, se você tentar usar o objeto Person, ele imprimirá o nome

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

Se você observar a classe Object (classe pai de todas as classes em Java), a implementação do método toString () será

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

sempre que você imprimir qualquer objeto em Java, toString () será chamado. Agora depende de você, se você substituir toString (), seu método chamará outra chamada de método da classe Object.

Yasir Shabbir Choudhary
fonte