提问人:Duncan Jones 提问时间:3/19/2015 最后编辑:OneCricketeerDuncan Jones 更新时间:3/30/2023 访问量:566308
如何在不获得“SomeType@2f92e0f4”的情况下打印我的 Java 对象?
How do I print my Java object without getting "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
此输出是什么意思?如何更改此输出,使其包含我的人名?如何打印我的对象集合?
注意:这是关于这个主题的规范问答。
答:
背景
所有 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
对象的哈希码。
数组类的名称看起来有点不同,这在 Class.getName()
的 Javadocs 中得到了很好的解释。例如,表示:[Ljava.lang.String
[
- 一维数组(与 OR 等相反)[[
[[[
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 都支持根据类中的字段自动生成方法。例如,请参阅 Eclipse 和 IntelliJ 的文档。toString()
一些流行的 Java 库也提供了此功能。一些例子包括:
打印对象组
所以你已经为你的班级创造了一个好东西。如果将该类放入数组或集合中会发生什么?toString()
阵 列
如果你有一个对象数组,你可以调用 Arrays.toString()
来生成数组内容的简单表示形式。例如,考虑以下对象数组:Person
Person[] people = { new Person("Fred"), new Person("Mike") };
System.out.println(Arrays.toString(people));
// Prints: [Fred, Mike]
注意:这是对 Arrays 类中调用的静态方法的调用,这与我们上面讨论的内容不同。toString()
如果你有一个多维数组,你可以使用 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 中的每个类中都有该方法,如果将该类的某个对象传递给 ,则调用该方法。默认情况下,此调用返回该对象的className@hashcode。toString()
System.out.println()
{
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);
}
}
评论
[Lcom.foo.Person;@28a418fc
toString()
Person[]
Person
我认为apache提供了一个更好的util类,它提供了一个获取字符串的函数
ReflectionToStringBuilder.toString(object)
评论
在 Eclipse 中,
去你的班级,
右键单击->source->生成toString()
;
它将重写该方法并打印该类的对象。toString()
如果您直接打印 Person 的任何对象,它将发送到代码。ClassName@HashCode
在你的情况下正在打印.其中 是对象所属的类,是对象的 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());
}
}
在 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 +
'}';
}
}
正如你所看到的,它通过连接类的几个属性来生成一个字符串,对于基元,它将打印它们的值,对于引用类型,它将使用它们的类类型(在本例中为 Test2 的字符串方法)。
如果你看一下 Object 类(Java 中所有类的父类),toString() 方法的实现是
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
每当您在 Java 中打印任何对象时,都会调用 toString()。现在,如果您重写 toString(),则由您决定,然后您的方法将调用其他 Object 类方法调用。
默认情况下,Java 中的每个 Object 都有输出ObjectType@HashCode的方法。toString()
如果你想要更有意义的信息,那么你需要在你的类中重写方法。toString()
public class Person {
private String name;
// constructor and getter/setter omitted
// overridding toString() to print name
public String toString(){
return name;
}
}
现在,当您打印 person 对象时,使用它将打印 person 的名称,而不是类名和哈希码。System.out.prtinln(personObj);
在第二种情况下,当您尝试打印数组时,它会打印 Array 类型及其哈希码。[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);
可能还有其他方法。希望这会有所帮助。:)
我更喜欢使用实用程序函数,该函数使用 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);
}
}
我设法在 Spring 5 中使用 Jackson 完成了这项工作。根据对象的不同,它可能并非在所有情况下都有效。
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(yourObject));
输出如下所示:
{
"id" : 1,
"fieldOne" : "string"
}
以下是使用 Jackson 的更多示例。
如果改用 GSON,它可能如下所示:
Gson gson = new Gson();
System.out.println(gson.toJson(yourObject));
评论
Gson gson = new Gson(); System.out.println(gson.toJson(yourObject));
你不需要使用 toString()
对于“深度”,还有基于 JSON 的答案(Jackson、GSON 等)的替代方案:来自 Apache Commons Lang 3 库的 ReflectionToStringBuilder,带有 RecursiveToStringStyle 或 MultilineRecursiveToStringStyle。代码示例:toString()
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
]
]
如果您使用的是 Lombok 项目,则可以使用注释并生成标准方法,而无需添加样板。@ToString
toString()
import lombok.ToString;
@ToString
public class LoginDto {
private String user;
private String pass;
}
...
System.out.println(loginDto.toString());
// LoginDto([email protected], pass=xxxxx)
在类上使用 Lombok @Data 注解将提供 getter、setter、toString 和 hashcode。使用 Lombok 更好,因为它可以处理样板代码。
评论
如果你不想覆盖该方法,你可以使用它,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 方法,它会非常方便。
评论