如何在没有得到“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]];