为什么需要重写 toString()?
Object 类是所有 Java 类的父类,它提供了一个默认的 toString() 实现,当你直接打印一个对象时,System.out.println(myObject);,JVM 内部会调用 myObject.toString() 方法。

默认的 toString() 输出是什么?
它会返回一个看起来像这样的字符串:
类名@对象的哈希码(十六进制格式)
示例:
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("张三", 30);
System.out.println(person); // 这里会自动调用 person.toString()
}
}
输出结果:
Person@15db9742
这个输出 Person@15db9742 除了告诉我们对象的类型是 Person 之外,没有任何实际意义,我们无法从这个字符串中得知 person 对象的具体信息,比如它的名字和年龄。
重写 toString() 的主要目的就是提供一个有意义的、可读的字符串表示形式,方便我们进行调试、日志记录和开发。
如何手动重写 toString()?
重写 toString() 非常简单,只需在你的类中添加一个符合以下签名的方法即可:
@Override
public String toString() {
// 在这里返回一个描述该对象的字符串
return "自定义的字符串内容";
}
重写上面的 Person 类:
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person[name=" + this.name + ", age=" + this.age + "]";
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("张三", 30);
System.out.println(person);
}
}
输出结果:
Person[name=张三, age=30]
输出结果清晰明了,一眼就能看出这个 Person 对象的所有关键信息。
重写 toString() 的最佳实践
仅仅实现功能是不够的,遵循最佳实践能让你的代码更专业、更易维护。
1 使用 @Override 注解
这强烈推荐!@Override 注解告诉编译器:“我正在重写一个父类的方法”,如果你拼写错误,或者方法签名不匹配,编译器会立刻报错,从而避免了因拼写错误而创建了一个新的、与重写无关的方法。
2 格式要清晰、一致
一个好的 toString() 输出应该像一个固定的“模板”,方便开发者(包括未来的你)快速理解对象的结构。
- 包含类名:通常以类名开头,
Person[...]。 - 使用方括号
[]或花括号 :这是一种约定俗成的做法,用来包裹内容。 - 键值对:对于多个属性,使用
key=value的形式,并用逗号 分隔。Person[name=张三, age=30, city=北京]
- 处理
null值:如果对象的属性可能为null,最好在toString中处理,避免输出null字符串,或者用特殊的标记(如"null"或"<null>")表示。Person[name=张三, address=null]可以改为Person[name=张三, address=<null>]。
3 性能考虑
toString() 方法在调试日志中被频繁调用,所以性能也很重要,避免在 toString() 中进行耗时操作,
- 访问网络
- 读写文件
- 复杂的数据库查询
toString() 应该是轻量级的。
4 包含所有重要信息
确保 toString() 的输出包含了所有对外部调试有用的信息,如果一个属性是 transient(不会被序列化)的,你可能需要考虑是否应该在 toString() 中包含它,这取决于你的设计意图。
使用 IDE 自动生成 toString()
手动编写虽然简单,但当类有很多属性时,会变得繁琐且容易出错,现代 IDE(如 IntelliJ IDEA 和 Eclipse)都提供了强大的自动生成功能。
以 IntelliJ IDEA 为例:
- 在类编辑器中,右键点击。
- 选择 Generate (或按快捷键
Alt + Insert)。 - 从弹出的菜单中选择 toString()。
- IDE 会列出类的所有成员变量,你可以选择需要包含在
toString输出中的变量。 - 点击 OK。
IDEA 会自动生成一个格式良好、包含 @Override 注解的 toString() 方法。
自动生成的代码示例:
import java.util.Objects;
class Person {
private String name;
private int age;
// 假设还有其他属性...
private String city;
// ... 构造方法和其他代码 ...
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", city='" + city + '\'' +
'}';
}
}
注意,现代 IDE(如 IDEA)在自动生成 toString() 时,通常会导入 java.util.Objects 类,并使用 Objects.toStringHelper() 或类似的内部机制来构建字符串,这比简单的字符串拼接更安全(能正确处理 null 值)。
进阶:使用 StringBuilder(手动优化)
如果你不想依赖 IDE,并且希望手动获得比字符串拼接()更好的性能,可以使用 StringBuilder。
为什么用 StringBuilder?
在循环或大量字符串拼接时,使用 会创建多个中间的 String 对象,因为 String 是不可变的,这会导致性能下降和内存浪费。StringBuilder 是可变的,它在一个缓冲区中构建字符串,效率更高。
示例:
class Person {
private String name;
private int age;
private String city;
// ... 构造方法 ...
@Override
public String toString() {
return new StringBuilder()
.append("Person{")
.append("name='").append(name).append('\'')
.append(", age=").append(age)
.append(", city='").append(city).append('\'')
.append('}')
.toString();
}
}
虽然对于简单的 toString 现代 Java 编译器对 的优化已经很好了,StringBuilder 的性能差异可能微乎其微,但养成使用 StringBuilder 的习惯对于复杂的字符串操作是非常有益的。
| 项目 | 说明 |
|---|---|
| 为什么重写 | 提供一个有意义的、可读的字符串表示,方便调试和日志记录。 |
| 如何重写 | 在类中定义 public String toString() 方法,并返回自定义字符串。 |
| 最佳实践 | 使用 @Override 注解;保持格式清晰一致(如 ClassName[key=value]);避免耗时操作。 |
| 自动生成 | 强烈推荐使用 IDE(如 IntelliJ IDEA)的自动生成功能,快速、准确、规范。 |
| 性能考虑 | 对于简单 toString, 拼接足够;对于复杂场景,优先考虑 StringBuilder。 |
掌握 toString() 的重写是每个 Java 开发者的基本功,它能让你的代码在调试和日志输出时更加友好和专业。
