如何在不获取“SomeType@2f92e0f4”的情况下打印我的 Java 对象?
Posted
技术标签:
【中文标题】如何在不获取“SomeType@2f92e0f4”的情况下打印我的 Java 对象?【英文标题】:How do I print my Java object without getting "SomeType@2f92e0f4"? 【发布时间】:2015-03-19 08:59:18 【问题描述】:我有一个类定义如下:
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
这个输出是什么意思?如何更改此输出以使其包含我的人名?以及如何打印我的对象集合?
注意:这是关于此主题的规范问答。
【问题讨论】:
您可以使用GSON 库将对象转换为json,反之亦然。对调试非常有用。 另见***.com/questions/27647567/… 【参考方案1】:背景
所有 Java 对象都有一个 toString()
方法,当您尝试打印对象时会调用该方法。
System.out.println(myObject); // invokes myObject.toString()
此方法在Object
类(所有Java 对象的超类)中定义。 Object.toString()
方法返回一个看起来相当难看的字符串,由类名、@
符号和对象的十六进制 hashcode 组成。代码如下:
// Code of Object.toString()
public String toString()
return getClass().getName() + "@" + Integer.toHexString(hashCode());
因此,com.foo.MyType@2f92e0f4
这样的结果可以解释为:
com.foo.MyType
- 类的名称,即包com.foo
中的类为MyType
。
@
- 将字符串连接在一起
2f92e0f4
对象的哈希码。
数组类的名称看起来有点不同,这在Class.getName()
的Javadocs 中有很好的解释。例如,[Ljava.lang.String
表示:
[
- 一维数组(与 [[
或 [[[
等相对)
L
- 数组包含一个类或接口
java.lang.String
- 数组中对象的类型
自定义输出
要在调用 System.out.println(myObject)
时打印不同的内容,您必须在自己的类中使用 override toString()
方法。这是一个简单的例子:
public class Person
private String name;
// constructors and other methods omitted
@Override
public String toString()
return name;
现在如果我们打印Person
,我们会看到他们的名字而不是com.foo.Person@12345678
。
请记住,toString()
只是将对象转换为字符串的一种方式。通常,此输出应以清晰简洁的方式完整描述您的对象。对于我们的Person
类,更好的toString()
可能是:
@Override
public String toString()
return getClass().getSimpleName() + "[name=" + name + "]";
哪个会打印,例如,Person[name=Henry]
。这对于调试/测试来说是非常有用的数据。
如果您只想关注对象的一个方面或包含大量的格式,您可能会更好地定义一个单独的方法,例如String toElegantReport() ...
.
自动生成输出
许多IDEs 支持基于类中的字段自动生成toString()
方法。例如,请参阅 Eclipse 和 IntelliJ 的文档。
几个流行的 Java 库也提供此功能。一些例子包括:
ToStringBuilder
来自Apache Commons Lang
MoreObjects.ToStringHelper
来自Google Guava
来自Project Lombok的@ToString
注解
打印对象组
所以你已经为你的班级创建了一个很好的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()
,如上所述。
【讨论】:
【参考方案2】:我认为 apache 提供了一个更好的 util 类,它提供了一个获取字符串的函数
ReflectionToStringBuilder.toString(object)
【讨论】:
这样做的好处是不需要编辑类,这有时是不可能的。但是,我怎样才能递归地打印嵌套对象呢? 完美!这正是我们所需要的。谢谢! @lukas84 ReflectionToStringBuilder.toString(input, new RecursiveToStringStyle());这也将打印嵌套对象【参考方案3】:默认情况下,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);
【讨论】:
这是一个恰当而简短的答案,但要澄清为什么 OP 将[Lcom.foo.Person;@28a418fc
作为输出:这也是 toString()
方法的输出,但在在运行时为Person[]
类型而不是Person
生成的类(请参阅***.com/a/8546532/1542343)。【参考方案4】:
在 Eclipse 中,
去你的课,
右键->源码->生成toString()
;
它将覆盖toString()
方法并打印该类的对象。
【讨论】:
【参考方案5】:我更喜欢使用一个实用函数,它使用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);
【讨论】:
【参考方案6】:在 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 的字符串方法)。
【讨论】:
【参考方案7】:默认情况下,Java 中的每个 Object 都有 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
Array 类型及其哈希码。
如果要打印人名,有很多方法。
您可以编写自己的函数来迭代每个人并打印
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);
可能还有其他方法。希望这可以帮助。 :)
【讨论】:
【参考方案8】:如果您直接打印 Person 的任何对象,它将 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());
【讨论】:
【参考方案9】:如果您查看 Object 类(Java 中所有类的父类),则 toString() 方法的实现是
public String toString()
return getClass().getName() + "@" + Integer.toHexString(hashCode());
每当您在 Java 中打印任何对象时,都会调用 toString()。现在由你决定是否覆盖 toString() 那么你的方法将调用其他 Object 类方法调用。
【讨论】:
【参考方案10】:对于“深度”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
]
]
【讨论】:
【参考方案11】:我在 Spring 5 中使用 Jackson 设法完成了这项工作。根据对象的不同,它可能并非在所有情况下都有效。
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(yourObject));
输出看起来像
"id" : 1,
"fieldOne" : "string"
Here 是更多使用 Jackson
的示例如果你改用 GSON 它可能看起来像
Gson gson = new Gson();
System.out.println(gson.toJson(yourObject));
【讨论】:
Gson gson = new Gson(); System.out.println(gson.toJson(yourObject));
你不需要使用 toString()【参考方案12】:
在类上使用 Lombok @Data 注解将提供 getter、setter、toString 和 hashcode。使用 Lombok 更好,因为它可以处理样板代码。
【讨论】:
【参考方案13】:如果您正在使用项目 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)
【讨论】:
以上是关于如何在不获取“SomeType@2f92e0f4”的情况下打印我的 Java 对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 iOS 中的 UITableViewDelegate 方法的情况下获取选择的 UITableViewCell