Skip to content

toString() 方法

toString 是什么?

toString() 返回对象的字符串表示,用于日志输出、调试、打印对象内容。

Object 的默认实现返回一个没用的字符串:

java
Person p = new Person("张三", 25);
System.out.println(p); // Person@15db9742 —— 你能看出什么?

重写后:

java
Person{name='张三', age=25} —— 一目了然

重写 toString

基本模式

java
class Person {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

Lombok 注解

java
@Data // @Data 包含 @ToString
class Person {
    private String name;
    private int age;
}

// 等价于
class Person {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Person(name=" + name + ", age=" + age + ")";
    }
}

排除敏感字段

java
@Data
@ToString(exclude = {"password", "secretKey"})
class User {
    private String username;
    private String password;   // 不打印
    private String secretKey;  // 不打印
}

toString 的使用场景

1. 日志输出

java
class Order {
    private String orderId;
    private double amount;

    @Override
    public String toString() {
        return "Order{orderId='" + orderId + "', amount=" + amount + "}";
    }
}

// 日志中直接打印
Order order = new Order("ORD001", 99.9);
log.info("创建订单: {}", order);
// 输出: 创建订单: Order{orderId='ORD001', amount=99.9}

2. 调试输出

java
// IDE 调试时,对象默认调用 toString
System.out.println(person); // 快速查看对象内容

// 集合的 toString 也有用
List<Person> list = Arrays.asList(p1, p2, p3);
System.out.println(list);
// 输出: [Person{name='张三'}, Person{name='李四'}, Person{name='王五'}]

3. 字符串拼接

java
// 不用 toString
System.out.println("用户信息: " + user.getName() + ", " + user.getAge());

// 用 toString
System.out.println("用户信息: " + user); // 更简洁

常见模式

格式化 toString

java
@Override
public String toString() {
    return String.format("Person{name='%s', age=%d, salary=%.2f}",
        name, age, salary);
}

StringBuilder 拼接

java
@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("Person{");
    sb.append("name='").append(name).append('\'');
    sb.append(", age=").append(age);
    sb.append('}');
    return sb.toString();
}

递归引用(小心 StackOverflow)

java
class Node {
    private String value;
    private Node next;

    @Override
    public String toString() {
        return "Node{value='" + value + "', next=" + next + "}";
        // ❌ 如果链表很长,会 StackOverflowError!
    }
}

// 安全版本:限制深度
@Override
public String toString() {
    return "Node{value='" + value + "'}";
}

集合的 toString

Java 集合已经正确重写了 toString:

java
List<String> list = Arrays.asList("a", "b", "c");
System.out.println(list); // [a, b, c]

Map<String, Integer> map = Map.of("a", 1, "b", 2);
System.out.println(map); // {a=1, b=2}

Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
System.out.println(set); // [1, 2, 3]

自定义对象的集合也能正确显示,但前提是集合里的对象正确重写了 toString。

不重写 toString 的后果

java
class Broken {
    private String name;
    private int value;
}

// 使用
Broken b = new Broken("test", 42);
System.out.println(b);
// 输出: Broken@15db9742 —— 完全不知道内容是什么!

调试时看到这种输出,只能靠 IDE 的变量窗口,或者打断点去看属性值。

总结

场景建议
日常调试重写 toString,一眼看穿对象内容
日志输出重写 toString,避免手动拼接
API 返回谨慎重写,可能暴露内部结构
集合元素必须重写 toString,集合打印才有用

记住:toString 是给自己调试用的,优先保证可读性

基于 VitePress 构建