Как напечатать объект Java, не получив SomeType @ 2f92e0f4?

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

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

Что означает этот вывод? Как мне изменить этот вывод, чтобы он содержал имя моего человека? А как мне распечатать коллекции своих объектов?

Примечание: это канонический вопрос и ответ на эту тему.


person Duncan Jones    schedule 19.03.2015    source источник
comment
Вы можете использовать библиотеку GSON для преобразования объекта в json и наоборот. Очень полезно для отладки.   -  person Ashish Rawat    schedule 08.08.2015
comment
См. Также stackoverflow.com/questions / 27647567 /   -  person Raedwald    schedule 26.03.2016


Ответы (11)


Фон

Все объекты 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 для _ 13_. Например, [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() для своего класса. Что произойдет, если этот класс поместить в массив или коллекцию?

Массивы

Если у вас есть массив объектов, вы можете вызвать _ 36_ для создания простого представления содержимого массива. Например, рассмотрим этот массив из Person объектов:

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

// Prints: [Fred, Mike]

Примечание: это вызов статического метода, называемого toString() в классе Arrays, который отличается от того, что мы обсуждали выше.

Если у вас есть многомерный массив, вы можете использовать _ 40_, чтобы получить такой же результат.

Коллекции

Большинство коллекций будут производить красивый результат, основанный на вызове .toString() для каждого элемента.

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

// Prints [Alice, Bob]

Поэтому вам просто нужно убедиться, что элементы вашего списка определяют красивый toString(), как обсуждалось выше.

person Duncan Jones    schedule 19.03.2015

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

ReflectionToStringBuilder.toString(object)
person Rohith K    schedule 15.04.2015
comment
Это имеет то преимущество, что не требуется редактировать класс, что иногда невозможно. Однако как я могу рекурсивно печатать и вложенные объекты? - person lukas84; 23.03.2018
comment
Идеально! Это именно то, что нам нужно. Спасибо! - person Vũ Hồng Kỳ; 13.01.2021
comment
@ lukas84 ReflectionToStringBuilder.toString (ввод, новый RecursiveToStringStyle ()); Это также напечатает вложенные объекты - person Viraj Nimbalkar; 18.06.2021

Каждый класс в 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);
    }
}
person Pankaj Manali    schedule 19.03.2015
comment
Это хорошо сформулированный и короткий ответ, но чтобы прояснить, почему OP получает [Lcom.foo.Person;@28a418fc в качестве вывода: это также результат метода toString(), но того, который реализован в классе, который создается во время выполнения для типа Person[], не Person (см. stackoverflow.com/a/8546532/1542343). - person gvlasov; 25.03.2015

В Eclipse перейдите в свой класс, щелкните правой кнопкой мыши-> источник-> Создать toString();

Он переопределит метод toString() и напечатает объект этого класса.

person ketankk    schedule 21.04.2016

Я предпочитаю использовать служебную функцию, которая использует 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);
    }
}
person Agam    schedule 09.10.2018

В 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).

person Mr.Q    schedule 28.07.2016

По умолчанию каждый объект в 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 (используя потоки и ссылку на метод).

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

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

person adn.911    schedule 02.12.2017

Если вы напечатаете напрямую какой-либо объект Person, это приведет к 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());
  }
}
person Vikrant Kashyap    schedule 06.05.2016

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

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

всякий раз, когда вы печатаете какой-либо объект в Java, будет вызываться toString (). Теперь вам решать, если вы переопределите toString (), тогда ваш метод вызовет другой вызов метода класса Object.

person Yasir Shabbir Choudhary    schedule 27.03.2017

Для глубокого toString() есть альтернатива ответам на основе JSON (Джексон, GSON и т. Д.): ReflectionToStringBuilder из библиотеки Apache Commons Lang 3 с RecursiveToStringStyle или MultilineRecursiveToStringStyle. Пример кода:

System.out.println("My object: " +
    ReflectionToStringBuilder.toString(theObject, new RecursiveToStringStyle()));

Примеры вывода:

// RecursiveToStringStyle
Person@7f54[name=Stephen,age=29,smoker=false,job=Job@43cd2[title=Manager]]

// MultilineRecursiveToStringStyle
Person@7f54[
  name=Stephen,
  age=29,
  smoker=false,
  job=Job@43cd2[
    title=Manager
  ]
]
person t0r0X    schedule 01.05.2021

Мне удалось сделать это с помощью Jackson в Spring 5. В зависимости от объекта Джексон мог работать не во всех случаях.

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(json);

вывод будет примерно таким

{
  "id" : 1,
  "internalStaffId" : "1",
  "staffCms" : 1,
  "createdAt" : "1",
  "updatedAt" : "1",
  "staffTypeChange" : null,
  "staffOccupationStatus" : null,
  "staffNote" : null
}

Дополнительные примеры использования Jackson здесь

Вы также можете попробовать GSON. Это было бы что-то вроде

Gson gson = new Gson();
System.out.println(gson.toJson(objectYouWantToPrint).toString());
person user9869932    schedule 05.11.2020