Как напечатать мой 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
Что означает этот вывод? Как мне изменить этот вывод, чтобы он содержал имя моего человека? И как мне распечатать коллекции моих предметов?
Примечание: это подразумевается как канонический вопрос и ответ на этот вопрос.
15 ответов
Фон
Все объекты 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 также предлагают эту функцию. Вот некоторые примеры:
ToStringBuilder
от Apache Commons LangMoreObjects.ToStringHelper
из Google Guava@ToString
аннотация от проекта Ломбок
Печать групп объектов
Итак, вы создали хороший 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()
как обсуждалось выше.
Я думаю, что Apache предоставляет лучший класс утилит, который предоставляет функцию для получения строки
ReflectionToStringBuilder.toString(object)
Каждый класс в 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);
}
}
В Eclipse перейдите в свой класс, щелкните правой кнопкой мыши ->source->Generate. toString()
;
Это переопределит toString()
метод и напечатает объект этого класса.
Я предпочитаю использовать служебную функцию, которая использует 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);
}
}
По умолчанию каждый объект в 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);
Могут быть и другие способы. Надеюсь это поможет.:)
В 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).
Если вы напрямую напечатать какой-либо объект лица, он будет ClassName@HashCode
к Кодексу.
в твоем случае com.foo.Person@2f92e0f4
печатается. куда Person
это класс, к которому принадлежит объект и 2f92e0f4
это hashCode объекта.
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());
}
}
Для «глубокого»
toString()
есть альтернатива ответам на основе JSON (Jackson, 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
]
]
Мне удалось это сделать, используя
Jackson
весной 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("-------------------------------------------------------------------")
System.out.println(json);
System.out.println("-------------------------------------------------------------------")
вывод будет примерно таким
-------------------------------------------------------------------
{
"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());
Использование аннотации Lombok @Data для класса предоставит геттер, сеттер, toString и хэш-код. Использование Lombok лучше, так как оно обрабатывает шаблонный код.
Если вы посмотрите на класс Object (родительский класс всех классов в Java), реализация метода toString()
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
всякий раз, когда вы печатаете какой-либо объект в Java, вызывается toString(). Теперь вам решать, если вы переопределите toString(), тогда ваш метод вызовет вызов метода другого класса Object.
Если вы используете проект Lombok, вы можете использовать
@ToString
аннотацию и сгенерируйте стандартную
toString()
метод без добавления шаблона.
import lombok.ToString;
@ToString
public class LoginDto {
private String user;
private String pass;
}
...
System.out.println(loginDto.toString());
// LoginDto(user=x@xxx.x, pass=xxxxx)
Если вы не хотите переопределятьtoString()
метод, который вы можете использовать,
public static void printJson(Object o) {
ObjectMapper mapper = new ObjectMapper();
try {
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(o);
System.out.println(json);
} catch (Exception e) {
e.printStackTrace();
}
}
Нам также необходимо импортировать,import com.fasterxml.jackson.databind.ObjectMapper;
Мы можем создать метод Utils, и это будет очень удобно.
Arrays.deepToString(arrayOfObject)
Над функцией вывести массив объектов разных примитивов.
[[AAAAA, BBBBB], [6, 12], [2003-04-01 00:00:00.0, 2003-10-01 00:00:00.0], [2003-09-30 00:00:00.0, 2004-03-31 00:00:00.0], [Interim, Interim], [2003-09-30, 2004-03-31]];