Comment imprimer mon objet Java sans obtenir «SomeType @ 2f92e0f4»?

301

J'ai une classe définie comme suit:

public class Person {
  private String name;

  // constructor and getter/setter omitted
}

J'ai essayé d'imprimer une instance de ma classe:

System.out.println(myPerson);

mais je suis la sortie suivante: com.foo.Person@2f92e0f4.

Une chose similaire s'est produite lorsque j'ai essayé d'imprimer un tableau d' Personobjets:

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

J'ai obtenu la sortie: [Lcom.foo.Person;@28a418fc

Que signifie cette sortie? Comment modifier cette sortie pour qu'elle contienne le nom de ma personne? Et comment imprimer des collections de mes objets?

Remarque : il s'agit d'un Q&A canonique sur ce sujet.

Duncan Jones
la source
1
Vous pouvez utiliser la bibliothèque GSON pour convertir un objet en json et vice versa. Très utile pour le débogage.
Ashish Rawat

Réponses:

403

Contexte

Tous les objets Java ont une toString()méthode, qui est invoquée lorsque vous essayez d'imprimer l'objet.

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

Cette méthode est définie dans la Objectclasse (la superclasse de tous les objets Java). La Object.toString()méthode renvoie une chaîne d'aspect assez laid, composée du nom de la classe, d'un @symbole et du code de hachage de l'objet en hexadécimal. Le code pour cela ressemble à ceci:

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

Un résultat tel que com.foo.MyType@2f92e0f4peut donc être expliqué comme:

  • com.foo.MyType - le nom de la classe, c'est-à-dire que la classe est MyTypedans le package com.foo.
  • @ - joint la chaîne ensemble
  • 2f92e0f4 le code de hachage de l'objet.

Le nom des classes de tableaux est un peu différent, ce qui est bien expliqué dans les Javadocs pour Class.getName(). Par exemple, [Ljava.lang.Stringsignifie:

  • [- un tableau unidimensionnel (par opposition à [[ou [[[etc.)
  • L - le tableau contient une classe ou une interface
  • java.lang.String - le type d'objets dans le tableau

Personnalisation de la sortie

Pour imprimer quelque chose de différent lorsque vous appelez System.out.println(myObject), vous devez remplacer la toString()méthode dans votre propre classe. Voici un exemple simple:

public class Person {

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

Maintenant, si nous imprimons un Person, nous voyons leur nom plutôt que com.foo.Person@12345678.

Gardez à l'esprit que ce toString()n'est qu'un moyen de convertir un objet en chaîne. Généralement, cette sortie doit décrire complètement votre objet de manière claire et concise. Un meilleur toString()pour notre Personclasse pourrait être:

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

Ce qui imprimerait, par exemple Person[name=Henry]. C'est une donnée vraiment utile pour le débogage / test.

Si vous souhaitez vous concentrer sur un seul aspect de votre objet ou inclure beaucoup de mise en forme jazzy, il serait préférable de définir une méthode distincte à la place, par exemple String toElegantReport() {...}.


Génération automatique de la sortie

De nombreux IDE prennent en charge la génération automatique d'une toString()méthode, en fonction des champs de la classe. Voir les documents pour Eclipse et IntelliJ , par exemple.

Plusieurs bibliothèques Java populaires offrent également cette fonctionnalité. Quelques exemples:


Impression de groupes d'objets

Vous avez donc créé un joli toString()pour votre classe. Que se passe-t-il si cette classe est placée dans un tableau ou une collection?

Tableaux

Si vous avez un tableau d'objets, vous pouvez appeler Arrays.toString()pour produire une représentation simple du contenu du tableau. Par exemple, considérez ce tableau d' Personobjets:

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

// Prints: [Fred, Mike]

Remarque: il s'agit d'un appel à une méthode statique appelée toString()dans la classe Arrays, qui est différente de ce que nous avons discuté ci-dessus.

Si vous disposez d'un tableau multidimensionnel , vous pouvez utiliser Arrays.deepToString()pour obtenir le même type de sortie.

Les collections

La plupart des collections produiront une jolie sortie basée sur l'appel .toString()à chaque élément.

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

// Prints [Alice, Bob]

Il vous suffit donc de vous assurer que vos éléments de liste définissent une belle, toString()comme indiqué ci-dessus.

Duncan Jones
la source
return String.format( getClass().getSimpleName() + "[ name=%s ]", name);et vraiment à la place nameil devrait utiliser le getter getName()(mais les getters ont été omis dans la classe Person ...) mais si un getter a été utilisé ...return String.format( getClass().getSimpleName() + "[ name=%s ]", getName());
CrandellWS
si j'ai deux classes dans un fichier java, alors comment créer un objet de classe qui n'est pas public A.java public class A {} class B {} ------ C.java public class C {A a = new A ( ); }
yatinbc
Notez qu'il existe des versions surchargées de Arrays.toString()sorte que vous pouvez également l'utiliser pour des tableaux de primitives ( int[], double[]). Arrays.deepToString()Gère également très bien les tableaux multidimensionnels de primitives.
Ole VV
1
@ MasterJoe2 Pas sûr, peut-être pensaient-ils que cela aurait l'air moche d'essayer de coder des valeurs négatives dans la chaîne?
Duncan Jones
55

Je pense qu'apache fournit une meilleure classe util qui fournit une fonction pour obtenir la chaîne

ReflectionToStringBuilder.toString(object)
Rohith K
la source
5
Cela a l'avantage de ne pas nécessiter d'éditer la classe, ce qui n'est parfois pas possible. Cependant, comment puis-je également imprimer récursivement des objets imbriqués?
lukas84
35

Chaque classe en Java a la toString()méthode par défaut, qui est appelée si vous passez un objet de cette classe à System.out.println(). Par défaut, cet appel renvoie le className @ hashcode de cet objet.

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

Vous pouvez remplacer la méthode toString d'une classe pour obtenir une sortie différente. Voir cet exemple

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
la source
3
Ceci est une réponse bien formulée et courte, mais pour clarifier pourquoi OP obtient [Lcom.foo.Person;@28a418fcen sortie: c'est aussi la sortie de la toString()méthode, mais de celle qui est implémentée dans la classe qui est générée au moment de l'exécution pour le type Person[], non Person(voir stackoverflow.com/a/8546532/1542343 ).
gvlasov
Cette sortie signifie package.Class@Hashcode. La méthode par défaut toString () a un type de retour comme. return Object.hasCode () ou une instruction de retour similaire qui renvoie un code de hachage sous forme hexadécimale avec le nom de la classe.
Pankaj Manali
14

Dans Eclipse, allez dans votre classe, clic droit-> source-> Générer toString();

Il remplacera la toString()méthode et affichera l'objet de cette classe.

ketankk
la source
10

Je préfère utiliser une fonction utilitaire qui utilise GSON pour désérialiser l'objet Java en chaîne 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
la source
Cela devrait être le return Gson.toJson(object);cas, sinon fonctionner parfaitement.
Nakrule
C'est seulement ça.
Agam
5

Dans intellij, vous pouvez générer automatiquement la méthode toString en appuyant sur alt + encart puis en sélectionnant toString () voici un résultat pour une classe de test:

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 +
            '}';
 }
}

Comme vous pouvez le voir, il génère une chaîne en concaténant plusieurs attributs de la classe, pour les primitives, il affichera leurs valeurs et pour les types de référence, il utilisera leur type de classe (dans ce cas, pour la méthode de chaîne de Test2).

Mr.Q
la source
4

Par défaut, chaque objet en Java a la toString()méthode qui génère l'ObjectType @ HashCode.

Si vous voulez plus d'informations utiles, vous devez remplacer la toString()méthode dans votre classe.

public class Person {
  private String name;

  // constructor and getter/setter omitted

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

Désormais, lorsque vous imprimez l'objet personne à l'aide de System.out.prtinln(personObj);celui-ci, le nom de la personne s'affiche à la place du nom de classe et du code de hachage.

Dans votre deuxième cas, lorsque vous essayez d'imprimer le tableau, il imprime [Lcom.foo.Person;@28a418fcle type de tableau et son code de hachage.


Si vous souhaitez imprimer les noms des personnes, il existe plusieurs façons.

Vous pouvez écrire votre propre fonction qui itère chaque personne et imprime

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

Vous pouvez l'imprimer en utilisant Arrays.toString (). Cela me semble le plus simple.

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

Vous pouvez l'imprimer à la manière de Java 8 (en utilisant les flux et la référence de méthode).

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

Il pourrait également y avoir d'autres moyens. J'espère que cela t'aides. :)

adn.911
la source
3

Si vous imprimez directement n'importe quel objet de la personne, cela correspondra ClassName@HashCodeau code.

dans votre cas com.foo.Person@2f92e0f4est en cours d'impression. Où Personest une classe à laquelle appartient l'objet et 2f92e0f4est hashCode de l'objet.

public class Person {
  private String name;

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

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

Maintenant, si vous essayez d'utiliser l'objet de Personalors il affichera le nom

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

Si vous regardez la classe Object (classe parent de toutes les classes en Java), l'implémentation de la méthode toString () est

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

chaque fois que vous imprimez un objet en Java, toString () sera appelé. Maintenant, c'est à vous de décider si vous remplacez toString (), votre méthode appellera un autre appel de méthode de classe Object.

Yasir Shabbir Choudhary
la source