Як надрукувати об'єкт Java без отримання "SomeType @ 2f92e0f4"?


300

У мене клас визначений так:

public class Person {
  private String name;

  // constructor and getter/setter omitted
}

Я спробував надрукувати екземпляр свого класу:

System.out.println(myPerson);

але я отримав наступний результат: com.foo.Person@2f92e0f4.

Подібне сталося, коли я намагався надрукувати масив Personоб’єктів:

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

Я отримав вихід: [Lcom.foo.Person;@28a418fc

Що означає цей вихід? Як змінити цей вихід, щоб він містив ім’я моєї людини? І як я друкую колекції своїх предметів?

Примітка . Це задумано як канонічне запитання щодо цієї теми.


1
Ви можете використовувати бібліотеку GSON для перетворення об'єкта в json і навпаки. Дуже корисно для налагодження.
Ashish Rawat

Відповіді:


403

Фон

Усі об'єкти Java мають toString()метод, який викликається при спробі друку об'єкта.

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

Цей метод визначений у Objectкласі (надклас усіх об'єктів Java). Object.toString()Метод повертає досить потворний шукає рядок, що складається з імені класу, з @символом і хеш - код об'єкта в шістнадцятковому форматі. Код цього виглядає так:

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

Таким чином, такий результат com.foo.MyType@2f92e0f4можна пояснити як:

  • com.foo.MyType - назва класу, тобто клас знаходиться MyTypeв пакеті com.foo.
  • @ - з'єднує рядок разом
  • 2f92e0f4 хеш-код об’єкта.

Назва класів масиву виглядає дещо інакше, що добре пояснено в Javadocs для Class.getName(). Наприклад, [Ljava.lang.Stringозначає:

  • [- одновимірний масив (на відміну від [[або [[[т.п.)
  • L - масив містить клас або інтерфейс
  • java.lang.String - тип об’єктів у масиві

Налаштування виходу

Для того, щоб надрукувати що - то інше , коли ви називаєте System.out.println(myObject), ви повинні перевизначити в toString()метод в вашому власному класі. Ось простий приклад:

public class Person {

  private String name;

  // constructors and other methods omitted

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

Тепер, якщо ми друкуємо а Person, ми бачимо їх ім’я, а не com.foo.Person@12345678.

Майте на увазі, що toString()це лише один спосіб перетворення об’єкта в рядок. Зазвичай цей вихід повинен повністю описувати ваш об'єкт чітко і стисло. Кращим toString()для нашого Personкласу може бути:

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

Який би друкувати, наприклад, Person[name=Henry]. Це дійсно корисний фрагмент даних для налагодження / тестування.

Якщо ви хочете зосередитись лише на одному аспекті вашого об'єкта або включити безліч форматних форматів, можливо, краще визначити окремий метод, наприклад, наприклад String toElegantReport() {...}.


Автогенерування результату

Багато IDE пропонують підтримку toString()методу автоматичного генерування на основі полів у класі. Наприклад, див. Документи для Eclipse та IntelliJ .

Кілька популярних бібліотек Java також пропонують цю функцію. Деякі приклади включають:


Друк груп об'єктів

Так ви створили приємне toString()для свого класу. Що станеться, якщо цей клас помістити у масив чи колекцію?

Масиви

Якщо у вас є масив об'єктів, ви можете зателефонувати, Arrays.toString()щоб створити просте зображення вмісту масиву. Наприклад, розглянемо цей масив Personоб'єктів:

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

// Prints: [Fred, Mike]

Примітка. Це виклик статичного методу, який називається toString()в класі Arrays, який відрізняється від того, про який ми говорили вище.

Якщо у вас є багатовимірний масив , ви можете використовувати Arrays.deepToString()для досягнення одного виду вихід.

Колекції

Більшість колекцій дають неабиякий вихід на основі виклику .toString()кожного елемента.

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

// Prints [Alice, Bob]

Тому вам просто потрібно забезпечити, щоб елементи списку визначали приємне, toString()як обговорювалося вище.


return String.format( getClass().getSimpleName() + "[ name=%s ]", name);і справді замість nameнього слід використовувати геттер getName()(але геттери були пропущені в класі Person ...), але якщо геттер був використаний ...return String.format( getClass().getSimpleName() + "[ name=%s ]", getName());
CrandellWS

якщо у мене два файли у файлі java, то як створити об’єкт класу, який не є загальнодоступним A.java public class A {} клас B {} ------ C.java public class C {A a = new A ( ); }
yatinbc

Зауважте, що існують перевантажені версії, Arrays.toString()тому ви можете використовувати їх і для масивів примітивів ( int[], double[]). Також Arrays.deepToString()чудово обробляє багатовимірні масиви примітивів.
Оле ВВ

1
@ MasterJoe2 Не впевнені, можливо, вони думали, що це буде виглядати некрасиво, намагаючись кодувати негативні значення в рядок?
Дункан Джонс

55

Я думаю, що apache забезпечує кращий util-клас, який забезпечує функцію отримання рядка

ReflectionToStringBuilder.toString(object)

5
Це має ту перевагу, що не потрібно редагувати клас, що іноді неможливо. Однак як я можу рекурсивно друкувати вкладені об'єкти?
lukas84

34

Кожен клас у Java toString()за замовчуванням містить у ньому метод, який викликається, якщо ви передаєте якомусь об'єкту цього класу System.out.println(). За замовчуванням цей виклик повертає хеш-код className @ цього об’єкта.

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

Ви можете змінити метод toString класу, щоб отримати різні результати. Дивіться цей приклад

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);
    }
}

3
Це чітка відповідь і коротка відповідь, але для уточнення, чому ОП отримує [Lcom.foo.Person;@28a418fcяк вихід: це також результат toString()методу, але той, який реалізується в класі, що генерується під час виконання для типу Person[], а не Person(див. stackoverflow.com/a/8546532/1542343 ).
гвласов

Цей вихід означає пакет.Class@Hashcode. Метод toString () має тип повернення типу. return Object.hasCode () або якийсь подібний оператор return, який повертає хеш-код у шістнадцятковій формі разом із назвою класу.
Панкай Маналі

14

У Eclipse перейдіть до свого класу, клацніть правою кнопкою миші-> source-> Generate toString();

Він замінить toString()метод і надрукує об’єкт цього класу.


10

Я вважаю за краще використовувати функцію утиліти, яка використовує GSON для десериалізації об'єкта Java в рядок 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);
    }
}

Так і має бути return Gson.toJson(object);, інакше працювати чудово.
Накруле

Це тільки те.
Агам

5

У Intellij ви можете автоматично генерувати метод toString, натискаючи клавіші alt + inset, а потім вибираючи toString ().

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

Як бачимо, він створює String шляхом об'єднання декількох атрибутів класу, для примітивів він буде друкувати їх значення, а для посилальних типів використовуватиме їх тип класу (у цьому випадку для рядкового методу Test2).


4

За замовчуванням кожен Об'єкт у Java має toString()метод, який виводить ObjectType @ HashCode.

Якщо ви хочете отримати більше значущої інформації, тоді вам потрібно перекрити toString()метод у вашому класі.

public class Person {
  private String name;

  // constructor and getter/setter omitted

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

Тепер, коли ви друкуєте об'єкт особи, використовуючи System.out.prtinln(personObj);його, виведете ім'я особи замість імені класу та хеш-коду.

У другому випадку, коли ви намагаєтеся надрукувати масив, він друкує [Lcom.foo.Person;@28a418fcтип масиву і це хеш-код.


Якщо ви хочете роздрукувати імена осіб, існує багато способів.

Ви можете написати власну функцію, яка повторює кожну людину та друкує

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

Ви можете роздрукувати його за допомогою Arrays.toString (). Мені це здається найпростішим.

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

Ви можете роздрукувати його java 8 way (використовуючи потоки та посилання на метод).

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

Можуть бути й інші способи. Сподіваюсь, це допомагає. :)


3

Якщо Ви безпосередньо надрукуєте будь-який об’єкт Особи, це буде ClassName@HashCodeКодекс.

у вашому випадку com.foo.Person@2f92e0f4друкується. Де Personє клас, до якого належить об'єкт, і 2f92e0f4є хеш-код об'єкта.

public class Person {
  private String name;

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

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

Тепер, якщо ви спробуєте використовувати об'єкт, Personтоді він буде надрукувати ім'я

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

2

Якщо ви подивитеся на клас Object (батьківський клас усіх класів на Java), реалізація методу toString () є

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

щоразу, коли ви друкуєте будь-який об’єкт на Java, то toString () буде викликатись. Тепер від вас залежить, якщо ви перекриєте toString (), тоді ваш метод викличе інший виклик методу класу Object.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.