简体   繁体   English

如何打印我的 Java object 而不会得到“SomeType@2f92e0f4”?

[英]How do I print my Java object without getting "SomeType@2f92e0f4"?

I have a class defined as follows:我有一个 class 定义如下:

public class Person {
  private String name;

  // constructor and getter/setter omitted
}

I tried to print an instance of my class:我试图打印我的 class 的实例:

System.out.println(myPerson);

but I got the following output: com.foo.Person@2f92e0f4 .但我得到了以下 output: com.foo.Person@2f92e0f4

A similar thing happened when I tried to print an array of Person objects:当我尝试打印Person对象数组时发生了类似的事情:

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

I got the output: [Lcom.foo.Person;@28a418fc我得到了 output: [Lcom.foo.Person;@28a418fc

What does this output mean?这个 output 是什么意思? How do I change this output so it contains the name of my person?如何更改此 output 使其包含我的人名? And how do I print collections of my objects?以及如何打印我的对象的 collections?

Note : this is intended as a canonical Q&A about this subject.注意:这旨在作为有关此主题的规范问答。

Background背景

All Java objects have a toString() method, which is invoked when you try to print the object.所有 Java 对象都有一个toString()方法,当您尝试打印该对象时会调用该方法。

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

This method is defined in the Object class (the superclass of all Java objects).此方法在Object类(所有 Java 对象的超类)中定义。 The Object.toString() method returns a fairly ugly looking string, composed of the name of the class, an @ symbol and the hashcode of the object in hexadecimal. Object.toString()方法返回一个看起来相当难看的字符串,由类名、 @符号和对象的十六进制哈希码组成。 The code for this looks like:代码如下:

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

A result such as com.foo.MyType@2f92e0f4 can therefore be explained as:因此,诸如com.foo.MyType@2f92e0f4这样的结果可以解释为:

  • com.foo.MyType - the name of the class, ie the class is MyType in the package com.foo . com.foo.MyType - 类的名称,即类是com.foo包中的MyType
  • @ - joins the string together @ - 将字符串连接在一起
  • 2f92e0f4 the hashcode of the object. 2f92e0f4对象的哈希码。

The name of array classes look a little different, which is explained well in the Javadocs for Class.getName() .数组类的名称看起来有些不同,Javadocs 中对Class.getName()进行了很好的解释。 For instance, [Ljava.lang.String means:例如, [Ljava.lang.String表示:

  • [ - an single-dimensional array (as opposed to [[ or [[[ etc.) [ - 一维数组(相对于[[[[[等)
  • L - the array contains a class or interface L - 数组包含一个类或接口
  • java.lang.String - the type of objects in the array java.lang.String - 数组中对象的类型

Customizing the Output自定义输出

To print something different when you call System.out.println(myObject) , you must override the toString() method in your own class.要在调用System.out.println(myObject)时打印不同的内容,您必须在自己的类中重写toString()方法。 Here's a simple example:这是一个简单的例子:

public class Person {

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

Now if we print a Person , we see their name rather than com.foo.Person@12345678 .现在如果我们打印一个Person ,我们会看到他们的名字而不是com.foo.Person@12345678

Bear in mind that toString() is just one way for an object to be converted to a string.请记住, toString()只是将对象转换为字符串的一种方法。 Typically this output should fully describe your object in a clear and concise manner.通常,此输出应以清晰简洁的方式完整描述您的对象。 A better toString() for our Person class might be:对于我们的Person类,一个更好的toString()可能是:

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

Which would print, eg, Person[name=Henry] .哪个会打印,例如Person[name=Henry] That's a really useful piece of data for debugging/testing.这对于调试/测试来说是非常有用的数据。

If you want to focus on just one aspect of your object or include a lot of jazzy formatting, you might be better to define a separate method instead, eg String toElegantReport() {...} .如果您想只关注对象的一个​​方面或包含大量花哨的格式,则最好定义一个单独的方法,例如String toElegantReport() {...}


Auto-generating the Output自动生成输出

ManyIDEs offer support for auto-generating a toString() method, based on the fields in the class.许多IDE支持基于类中的字段自动生成toString()方法。 See docs for Eclipse and IntelliJ , for example.例如,请参阅EclipseIntelliJ的文档。

Several popular Java libraries offer this feature as well.几个流行的 Java 库也提供此功能。 Some examples include:一些例子包括:


Printing groups of objects打印对象组

So you've created a nice toString() for your class.因此,您已经为您的班级创建了一个不错的toString() What happens if that class is placed into an array or a collection?如果将该类放入数组或集合中会发生什么?

Arrays数组

If you have an array of objects, you can call Arrays.toString() to produce a simple representation of the contents of the array.如果您有一个对象数组,则可以调用Arrays.toString()来生成数组内容的简单表示。 For instance, consider this array of Person objects:例如,考虑这个Person对象数组:

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

// Prints: [Fred, Mike]

Note: this is a call to a static method called toString() in the Arrays class, which is different to what we've been discussing above.注意:这是对 Arrays 类中名为toString()静态方法的调用,这与我们上面讨论的不同。

If you have a multi-dimensional array , you can use Arrays.deepToString() to achieve the same sort of output.如果你有一个多维数组,你可以使用Arrays.deepToString()来实现相同的输出。

Collections收藏品

Most collections will produce a pretty output based on calling .toString() on every element.大多数集合将基于在每个元素上调用.toString()产生漂亮的输出。

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

// Prints [Alice, Bob]

So you just need to ensure your list elements define a nice toString() as discussed above.所以你只需要确保你的列表元素定义一个好的toString()如上所述。

我认为 apache 提供了一个更好的 util 类,它提供了一个获取字符串的函数

ReflectionToStringBuilder.toString(object)

Every class in Java has the toString() method in it by default, which is called if you pass some object of that class to System.out.println() .默认情况下,Java 中的每个类都有toString()方法,如果您将该类的某个对象传递给System.out.println() ,就会调用该方法。 By default, this call returns the className@hashcode of that object.默认情况下,此调用返回该对象的 className@hashcode。

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

You can override the toString method of a class to get different output.您可以覆盖类的 toString 方法以获得不同的输出。 See this example看这个例子

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

In Eclipse, Go to your class, Right click->source->Generate toString() ;在 Eclipse 中,转到你的类,右键单击->source->Generate toString()

It will override the toString() method and will print the object of that class.它将覆盖toString()方法并打印该类的对象。

I prefer to use a utility function which uses GSON to de-serialize the Java object into JSON string.我更喜欢使用使用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);
    }
}

In intellij you can auto generate toString method by pressing alt+inset and then selecting toString() here is an out put for a test class:在 intellij 中,您可以通过按 alt+inset 然后选择 toString() 来自动生成 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 +
            '}';
 }
}

As you can see, it generates a String by concatenating, several attributes of the class, for primitives it will print their values and for reference types it will use their class type (in this case to string method of Test2).正如你所看到的,它通过连接类的几个属性来生成一个字符串,对于基元,它将打印它们的值,对于引用类型,它将使用它们的类类型(在本例中为 Test2 的字符串方法)。

By default, every Object in Java has the toString() method which outputs the ObjectType@HashCode.默认情况下,Java 中的每个 Object 都有输出 ObjectType@HashCode 的toString()方法。

If you want more meaningfull information then you need to override the toString() method in your class.如果您想要更有意义的信息,那么您需要覆盖类中的toString()方法。

public class Person {
  private String name;

  // constructor and getter/setter omitted

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

Now when you print the person object using System.out.prtinln(personObj);现在,当您使用System.out.prtinln(personObj); it will print the name of the person instead of the classname and hashcode.它将打印人名而不是类名和哈希码。

In your second case when you are trying to print the array, it prints [Lcom.foo.Person;@28a418fc the Array type and it's hashcode.在第二种情况下,当您尝试打印数组时,它会打印[Lcom.foo.Person;@28a418fc数组类型及其哈希码。


If you want to print the person names, there are many ways.如果要打印人名,有很多方法。

You could write your own function that iterates each person and prints您可以编写自己的函数来迭代每个人并打印

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

You could print it using Arrays.toString().您可以使用 Arrays.toString() 打印它。 This seems the simplest to me.这对我来说似乎是最简单的。

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

You could print it the java 8 way (using streams and method reference).您可以使用 java 8 方式打印它(使用流和方法参考)。

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

There might be other ways as well.可能还有其他方法。 Hope this helps.希望这可以帮助。 :) :)

If you Directly print any object of Person It will the ClassName@HashCode to the Code.如果您直接打印 Person 的任何对象,它将ClassName@HashCode到 Code。

in your case com.foo.Person@2f92e0f4 is getting printed .在您的情况下com.foo.Person@2f92e0f4正在打印。 Where Person is a class to which object belongs and 2f92e0f4 is hashCode of the Object.其中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;
   }
}

Now if you try to Use the object of Person then it will print the name现在,如果您尝试使用Person的对象,那么它将打印名称

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

If you look at the Object class (Parent class of all classes in Java) the toString() method implementation is如果您查看 Object 类(Java 中所有类的父类),则 toString() 方法的实现是

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

whenever you print any object in Java then toString() will be call.每当您在 Java 中打印任何对象时,都会调用 toString()。 Now it's up to you if you override toString() then your method will call other Object class method call.现在由您决定是否覆盖 toString() 那么您的方法将调用其他 Object 类方法调用。

I managed to get this done using Jackson in Spring 5. Depending on the object it might not work in all cases.我设法在 Spring 5 中使用Jackson完成了这项工作。根据对象的不同,它可能并非在所有情况下都有效。

import com.fasterxml.jackson.databind.ObjectMapper;
    
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(yourObject));

the output would look like输出看起来像

{
  "id" : 1,
  "fieldOne" : "string"
}

Here are more examples using Jackson 这里有更多使用杰克逊的例子

If you use GSON instead It might look like如果您改用GSON它可能看起来像

Gson gson = new Gson();
System.out.println(gson.toJson(yourObject));

For a "deep" toString() there is an alternative to the JSON based answers (Jackson, GSON, etc.): ReflectionToStringBuilder from the Apache Commons Lang 3 library, with RecursiveToStringStyle or MultilineRecursiveToStringStyle .对于“深度” toString() ,有一个基于 JSON 的答案(Jackson、GSON 等)的替代方法:来自Apache Commons Lang 3库的ReflectionToStringBuilder ,带有RecursiveToStringStyleMultilineRecursiveToStringStyle Code example:代码示例:

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

Output examples:输出示例:

// 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
  ]
]

Using Lombok @Data annotation on class will provide getter, setter, toString and hashcode.在类上使用 Lombok @Data 注解将提供 getter、setter、toString 和 hashcode。 Using Lombok is better as it handles boilerplate code.使用 Lombok 更好,因为它可以处理样板代码。

If you are using project Lombok you could use the @ToString annotation and generate a standard toString() method without adding boilerplate.如果您使用的是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)
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]];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何创建一个在运行时接受选项的Java项目(即-p或-f) - How do I create a java project that takes options at runtime (i.e. -p or -f) 的Java:f21.Person@373ee92 - Java: f21.Person@373ee92 Java Streams:对于N - 1个元素执行f(),对N执行g(),即对最后一个元素使用不同的函数 - Java Streams: Do f() for N - 1 elements and g() for N. i.e. different function for the last element Java 中的自定义异常处理,我如何只在异常 object 中打印出我的参数而不调用外部 class? - Custom exception handling in Java, how do I only print out my argument in exception object without calling the a outside class? 错误:[[“ c154ab40-1aaf-11e7-92ae-000c298f510d”,“ 3044c8f0-1ab0-11e7-92ae-000c298f510d”]] - error: [[“c154ab40-1aaf-11e7-92ae-000c298f510d”, “3044c8f0-1ab0-11e7-92ae-000c298f510d”]] %f如何在java中工作 - how %f works in java java将对象转换为列表<SomeType> - java cast Object to List<SomeType> 如何在不使用math.round或%3f之类的方法的情况下对数字进行四舍五入? - how do i round/trucate a number without using methods like math.round or %3f? 为什么在使用 Java DSL 时,我必须在入站 webflux 网关上使用.fluxTransform(f -&gt; f)? - Why do I have to use .fluxTransform(f -> f) on an inbound webflux gateways when using Java DSL? Java:如何从List <T>转换为Map <f1(T),List(f2(T))>而无需迭代 - Java: how to transform from List<T> to Map<f1(T), List(f2(T))> without iterating
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM