Como imprimo meu objeto Java sem obter “SomeType @ 2f92e0f4”?
Eu tenho uma classe definida da seguinte forma:
public class Person {
private String name;
// constructor and getter/setter omitted
}
Tentei imprimir uma instância da minha classe:
System.out.println(myPerson);
mas eu tenho o seguinte resultado: com.foo.Person@2f92e0f4
.
Algo semelhante aconteceu quando tentei imprimir uma série de Person
objetos:
Person[] people = //...
System.out.println(people);
Eu tenho o resultado: [Lcom.foo.Person;@28a418fc
O que significa essa saída? Como altero esta saída para que contenha o nome da minha pessoa? E como faço para imprimir coleções de meus objetos?
Observação : trata-se de uma pergunta e resposta canônica sobre este assunto.
Respostas
fundo
Todos os objetos Java possuem um toString()
método, que é invocado quando você tenta imprimir o objeto.
System.out.println(myObject); // invokes myObject.toString()
Este método é definido na Object
classe (a superclasse de todos os objetos Java). O Object.toString()
método retorna uma string de aparência bastante feia, composta do nome da classe, um @
símbolo e o código 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 com.foo.MyType@2f92e0f4
pode, portanto, ser explicado como:
com.foo.MyType
- o nome da classe, ou seja, a classe estáMyType
no pacotecom.foo
.@
- junta a corda2f92e0f4
o hashcode do objeto.
O nome das classes de array parece um pouco diferente, o que é bem explicado nos Javadocs para Class.getName()
. Por exemplo, [Ljava.lang.String
significa:
[
- uma matriz unidimensional (em oposição a[[
ou[[[
etc.)L
- a matriz contém uma classe ou interfacejava.lang.String
- o tipo de objetos na matriz
Personalizando a saída
Para imprimir algo diferente ao chamar 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 seu nome em vez de com.foo.Person@12345678
.
Lembre-se de que essa toString()
é apenas uma forma de um objeto ser convertido em string. Normalmente, essa saída deve descrever totalmente seu objeto de maneira clara e concisa. Um melhor toString()
para nossa Person
classe pode ser:
@Override
public String toString() {
return getClass().getSimpleName() + "[name=" + name + "]";
}
Que imprimiria, por exemplo Person[name=Henry]
,. Esse é um dado realmente útil para depuração / teste.
Se você deseja se concentrar em apenas um aspecto do seu objeto ou incluir uma grande formatação jazzística, pode ser melhor definir um método separado, por exemplo String toElegantReport() {...}
.
Gerando automaticamente a saída
Muitos IDEs oferecem suporte para a geração automática de um toString()
método, com base nos campos da classe. Veja documentos para Eclipse e IntelliJ , por exemplo.
Várias bibliotecas Java populares também oferecem esse recurso. Alguns exemplos incluem:
@ToString
anotação do Projeto Lombok
Impressão de grupos de objetos
Então você criou um bom toString()
para sua classe. O que acontece se essa classe for colocada em uma matriz ou coleção?
Arrays
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 Person
objetos:
Person[] people = { new Person("Fred"), new Person("Mike") };
System.out.println(Arrays.toString(people));
// Prints: [Fred, Mike]
Observação: 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 , pode usar Arrays.deepToString()
para obter o mesmo tipo de saída.
Coleções
A maioria das coleções produzirá uma saída bonita baseada 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]
Portanto, você só precisa garantir que os elementos da lista definam um bom, toString()
conforme discutido acima.
Eu acho que o apache fornece uma classe de utilitário melhor que fornece uma função para obter a string
ReflectionToStringBuilder.toString(object)
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, esta 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);
}
}
No Eclipse, vá para sua classe, clique com o botão direito-> fonte-> Gerar toString()
;
Ele substituirá o toString()
método e imprimirá o objeto daquela classe.
Eu prefiro usar uma função de utilitário que usa GSON para desserializar o objeto Java em uma string 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);
}
}
No 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 ele imprimirá seus valores e para tipos de referência usará seu tipo de classe (neste caso para o método string de Test2).
Por padrão, cada objeto em Java tem o toString()
método que produz 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 pessoa, System.out.prtinln(personObj);
ele imprimirá o nome da pessoa em vez do nome da classe e do código hash.
Em seu segundo caso, quando você está tentando imprimir o array, ele imprime [Lcom.foo.Person;@28a418fc
o tipo de Array e seu código hash.
Se você quiser 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. :)
Se você imprimir diretamente qualquer objeto de Pessoa, isso fará parte ClassName@HashCode
do Código.
no seu caso, com.foo.Person@2f92e0f4
está 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 de Person
então ele irá imprimir o nome
Class Test
{
public static void main(String... args){
Person obj = new Person("YourName");
System.out.println(obj.toString());
}
}
Se você olhar para a classe Object (classe pai de todas as classes em Java), a implementação do método toString () é
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
sempre que você imprimir qualquer objeto em Java, toString () será chamado. Agora é com você se você sobrescrever toString (), então seu método irá chamar outra chamada de método da classe Object.
Consegui fazer isso usando Jackson
no Spring 5. Dependendo do objeto, Jackson pode não funcionar em todos os 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("-------------------------------------------------------------------")
a saída seria algo como
-------------------------------------------------------------------
{
"id" : 1,
"internalStaffId" : "1",
"staffCms" : 1,
"createdAt" : "1",
"updatedAt" : "1",
"staffTypeChange" : null,
"staffOccupationStatus" : null,
"staffNote" : null
}
-------------------------------------------------------------------
Mais exemplos usando Jackson
aqui
Você GSON
também pode tentar . Deve ser algo assim:
Gson gson = new Gson();
System.out.println(gson.toJson(objectYouWantToPrint).toString());