如何在没有得到“SomeType @ 2f92e0f4”的情况下打印我的Java对象?

我有一个类定义如下:

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

这个输出是什么意思? 如何改变这个输出,使其包含我的人的名字? 如何打印我的对象的集合?

注意 :这是针对这个问题的规范问答。

背景

所有Java对象都有一个toString()方法,当您尝试打印对象时会调用该方法。

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

该方法在Object类(所有Java对象的超类)中定义。 Object.toString()方法返回一个相当丑陋的外观string,由类名, @符号和hex对象的哈希码组成。 这个代码如下所示:

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

com.foo.MyType@2f92e0f4等结果可以解释为:

  • com.foo.MyType – 类的名称,即类com.foo MyType
  • @ – 将string连接在一起
  • 2f92e0f4对象的哈希码。

数组类的名字看起来有点不同,这在Class.getName()的Javadocs中有很好的解释。 例如, [Ljava.lang.String意思是:

  • [ – 一维数组(与[[[[[ etc.]
  • L – 数组包含一个类或接口
  • java.lang.String – 数组中的对象的types

自定义输出

要在调用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()只是将对象转换为string的一种方法。 通常这个输出应该以一个清晰和简明的方式完整地描述你的对象。 我们的Person类更好的toString()可能是:

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

哪个会打印,例如Person[name=Henry] 。 这是一个非常有用的debugging/testing数据。

如果您只想关注对象的某个方面或者包含大量的爵士格式,则最好定义一个单独的方法,例如String toElegantReport() {...}


自动生成输出

许多IDE支持基于类中的字段自动生成toString()方法。 例如,请参阅Eclipse和IntelliJ的文档。

几个stream行的Java库也提供这个function。 一些例子包括:

  • 来自Apache Commons Lang的 ToStringBuilder

  • 来自Google Guava的 MoreObjects.ToStringHelper

  • 来自Project Lombok的 @ToString注解


打印对象组

所以你为你的类创build了一个很好的toString() 。 如果将该类放入数组或集合中会发生什么?

数组

如果你有一个对象数组,你可以调用Arrays.toString()来产生一个数组内容的简单表示。 例如,考虑这个Person对象的数组:

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

注意:这是对Arrays类中一个名为toString()静态方法的调用,这与我们上面讨论的不同。

如果你有一个multidimensional array ,你可以使用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() ,如上所述。

java中的每个类都有默认的toString()方法,如果你传递了一个类的某个对象, System.out.println()就会调用它。 当您尝试打印某个类的对象时, System.out.println()方法将调用该类的toString() ,该类将返回该对象的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); } } 

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

 ReflectionToStringBuilder.toString(object) 

在Eclipse中,转到您的类,右键单击 – >源 – >生成toString() ;

它将覆盖toString()方法并将打印该类的对象。

如果你直接打印Person的任何对象它将ClassName@HashCode到代码中。

在你的情况下, com.foo.Person@2f92e0f4正在打印。 其中Person是对象所属的类, 2f92e0f4是Object的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()); } } 

在intellij中,你可以通过按alt + inset自动生成toString方法,然后selecttoString()这里是一个testing类的输出:

 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,对于它将打印它们的值的基元,对于引用types,它将使用它们的类types(在这种情况下是Test2的string方法)。

如果您查看Object类(Java中所有类的父类),则实现toString()方法

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

每当你在Java中打印任何对象时,都会调用toString()。 现在,如果您重写toString(),那么您的方法将调用其他Object类的方法调用。

 Arrays.deepToString(arrayOfObject) 

以上function打印不同原始对象的数组。

 [[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]];