首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 入門必懂的三大核心觀念:引用本質、== vs equals、String 不變性

     編輯:Java 相關知識

前言

這三個問題是區分「會寫 Java 語法」與「理解 Java 物件模型」的分水嶺。若自以為超越初學者卻答不上來,請勇敢回歸基礎,重新建立正確心智模型。

觀念一:聲明的是什麼?

String s = "Hello world!";

錯誤認知:「聲明了一個內容為 Hello world 的 String 物件。」

正確認知:聲明了一個名為 s、型別為 String 的參考變數(reference variable),它指向一個內容為 "Hello world!" 的 String 物件。

關鍵證據:參考複製不產生新物件

String s = "Hello";
String string = s;  // 只是複製參考值(記憶體地址)
// 此時 s 和 string 指向同一個物件
// 堆上只有「一個」"Hello" 字串物件

Java 無指標運算,參考變數本質是「受管制的指標」,只能指向特定型別物件或 null。

觀念二:== 與 equals() 差在哪?

== 比較的是「參考值」(記憶體地址)

int a = 10, b = 10;
a == b  // true,基本型別比值

String a = new String("foo");
String b = new String("foo");
a == b  // false!兩個 new 產生兩個不同物件,地址不同

equals() 比較的是「邏輯內容」

// Object 預設實作
boolean equals(Object o) { return this == o; }  // 同 ==

// String 覆寫:逐字元比對
// Integer、Date 等也覆寫為值比較

自定義類別的責任

class Monster {
    private String content;
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Monster)) return false;
        Monster m = (Monster) o;
        return Objects.equals(content, m.content);  // 由類別設計者定義「相等」
    }
    // 覆寫 equals 必須同步覆寫 hashCode()!
    @Override public int hashCode() { return Objects.hash(content); }
}

鐵律:若打算放入 HashSet/HashMap/HashTable,必須正確覆寫 equals() 與 hashCode(),否則會出現「明明相等卻找不到」的詭異 Bug。

觀念三:String 到底變了沒?

String s = "Hello";
s = s + " world!";

答案:原物件沒變,s 換指向新物件。

記憶體實際發生的事

  1. "Hello" 在字串常量池/堆建立物件 A,s → A
  2. s + " world!" 觸發 StringBuilder 內部建構新字串,產生物件 B("Hello world!")
  3. s 重新指向 B,物件 A 仍存在(若無其他參考,後續 GC 回收)

效能啟示:頻繁拼接用 StringBuilder

// 差:每次迴圈產生新 String,產生大量暫存物件
String s = "";
for (int i = 0; i < 10000; i++) s += i;

// 好:單一 StringBuilder,最終 toString()
StringBuilder sb = new StringBuilder(50000);  // 預估容量避免擴容
for (int i = 0; i < 10000; i++) sb.append(i);
String result = sb.toString();

常量池優化:字面值自動共享

// 好:所有實例共用同一個 "Initial Value" 物件
s = "Initial Value";

// 差:每次 new 強制建立新物件,浪費記憶體且無意義
s = new String("Initial Value");

字串字面值("...")內容相同則指向同一物件;new String() 永遠建新物件。

為什麼 String 設計為不可變?

  • 線程安全:不可變物件天然可共享,無同步開銷。
  • 常量池共享:相同內容只存一份,節省記憶體。
  • HashCode 快取:hashCode() 只需算一次,Map 鍵值查找極快。
  • 安全性:網路路徑、資料庫連線字串等敏感資訊不可被竄改。

代價:每次修改需建新物件。Java 提供 StringBuilder(非同步)與 StringBuffer(同步)作為可變對應版本。

總結

觀念核心口訣
宣告宣告的是參考,不是物件
== vs equals== 比地址,equals 比內容(由類別定義)
String 不變變的是參考指向,不是物件本體;常用字面值、拼接用 StringBuilder

徹底搞懂這三點,Java 物件模型、集合框架、多線程同步的基石就穩固了。

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