Как напечатать мой Java-объект, не получая «SomeType @ 2f92e0f4»?


301

У меня есть класс, определенный следующим образом:

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 и наоборот. Очень полезно для отладки.
Ашиш Рават

Ответы:


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 публичный класс A {} class B {} ------ C.java публичный класс C {A a = new A ( ); }
yatinbc 10.10.16

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

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

55

Я думаю, что Apache предоставляет лучший класс утилит, который предоставляет функцию для получения строки

ReflectionToStringBuilder.toString(object)

5
Это имеет то преимущество, что не требует редактирования класса, что иногда невозможно. Однако как я могу рекурсивно печатать вложенные объекты?
lukas84

35

У каждого класса в Java есть toString()метод по умолчанию, который вызывается, если вы передаете некоторый объект этого класса System.out.println(). По умолчанию этот вызов возвращает className @ hashcode этого объекта.

{
    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
Это хороший и короткий ответ, но для пояснения, почему OP получает в [Lcom.foo.Person;@28a418fcкачестве вывода: это тоже вывод toString()метода, но того, который реализован в классе, который генерируется во время выполнения для типа Person[], а не Person(см. stackoverflow.com/a/8546532/1542343 ).
Гвласов

Этот вывод означает package.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;  
  }
}

Теперь, когда вы печатаете объект person, используя System.out.prtinln(personObj);его, выведите имя человека вместо имени класса и хэш-кода.

Во втором случае, когда вы пытаетесь напечатать массив, он печатает [Lcom.foo.Person;@28a418fcтип Array и его хэш-код.


Если вы хотите напечатать имена людей, есть много способов.

Вы можете написать свою собственную функцию, которая повторяет каждого человека и печатает

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 (используя потоки и ссылку на метод).

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

Могут быть и другие способы. Надеюсь это поможет. :)


3

Если вы напрямую печатаете какой-либо объект личности, он будет ClassName@HashCodeв коде.

в вашем случае com.foo.Person@2f92e0f4печатается. Где Personкласс, к которому принадлежит объект, и 2f92e0f4hashCode объекта.

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.