首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java String 輸出地址值 vs 內容值:toString() 重寫機制深度解析

     編輯:程式設計綜合問答

Java 初學者常見困惑:System.out.println(obj) 時,有的對象輸出內容(如 String、包裝類),有的輸出類似 com.example.User@15db9742 的「地址值」。本文從 JVM 規範、Object 基類、toString() 契約、最佳實踐四個維度徹底講透輸出差異本質。

核心機制:println 最終調用 toString()

// PrintStream.println(Object x) 簡化源碼
public void println(Object x) {
    String s = String.valueOf(x);  // 關鍵行
    synchronized (this) {
        print(s);
        newLine();
    }
}

// String.valueOf(Object obj)
public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();  // 核心:調用對象的 toString()
}

結論:println(obj) 輸出什麼,完全取決於對象類別的 toString() 實現。

Object 默認 toString() 實現

// java.lang.Object 源碼
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
// 例如:com.example.User@15db9742
// 其中 hashCode() 默認返回對象頭標識(常被誤稱為「內存地址」)
  • 未重寫 toString() 的類,輸出「全限定類名@十六進制哈希碼」。
  • 這不是內存地址,是 hashCode() 返回值(默認基於對象頭標識計算,與地址相關但不等於地址)。

常見類 toString() 實現對比

類別是否重寫 toString()輸出示例說明
String✅ 是"hello"直接返回字符串內容
Integer/Long 等包裝類✅ 是"123"返回數值的字符串形式
數組❌ 否[I@15db9742繼承 Object 默認實現,[I 表示 int[]
ArrayList/HashMap 等集合✅ 是[a, b, c] / {k1=v1, k2=v2}AbstractCollection 重寫,遞歸調用元素 toString()
自定義類 User❌ 否(默認)com.example.User@15db9742需手動重寫
自定義類 User✅ 是User{name='張三', age=25}推薦格式

標準重寫 toString() 模板

手寫版(簡單類)

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

IDE 自動生成

  • IntelliJ IDEA:Alt+Insert → toString() → 勾選字段 → OK。
  • Eclipse:Source → Generate toString()...。

Apache Commons Lang / Lombok 註解版(推薦生產)

// Lombok
@Data // 含 @ToString
public class User {
    private String name;
    private int age;
    private String email;
}

// 或精確控制
@ToString(includeFieldNames = true, callSuper = true)
public class User { ... }

// Apache Commons Lang
@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

toString() 契約與最佳實踐

  1. 可讀性優先:輸出應清晰表達對象狀態,便於日誌調試。
  2. 包含關鍵標識字段:ID、name、狀態等業務主鍵。
  3. 避免循環引用:雙向關聯對象(如 Parent-Child)需手動控制,防止棧溢出。
  4. 不暴露敏感信息:密碼、Token、身份證號等應掩碼或排除。
  5. 性能考量:高頻調用場景(如日誌大量打印對象)考慮緩存或簡化輸出。
  6. 配合 equals/hashCode:若重寫 equals(),通常也應重寫 toString() 保持一致性。

調試技巧:不改代碼也能看內容

場景方法
IDE 調試斷點懸停變量 / Variables 面板 / Evaluate Expression 輸入 obj.toString()
日志框架Log4j2/Logback 配置 %ex{full} 或使用 JSON 佈局自動序列化對象
JSON 序列化new ObjectMapper().writeValueAsString(obj) (Jackson) / Gson().toJson(obj)
Apache CommonsToStringBuilder.reflectionToString(obj) 利用反射輸出所有字段

總結

Java 對象輸出「地址值」還是「內容值」,唯一決定因素是該類是否重寫了 toString() 方法。String、包裝類、集合類已重寫,自定義類默認繼承 Object.toString() 輸出類名@哈希碼。養成「寫類必重寫 toString()」的習慣,配合 Lombok @Data 或 IDE 自動生成,能極大提升調試效率與日誌可讀性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved