Java 語言雖然語法簡潔,但其底層機制卻蘊含許多值得深究的細節。本文將系統梳理類初始化順序、String 常量池機制、繼承體系中的方法調用、參數傳遞本質、final/finally/finalize 差異、基本類型特性以及日期時間處理等核心知識點,幫助開發者建立扎實的 Java 核心認知體系。
當實例化一個子類對象時,父子類的靜態成員、實例成員、構造器執行順序遵循嚴格規則。通過一個完整的代碼示例來驗證:
class Parent {
public static StaticVarible staticVarible = new StaticVarible("父類-靜態變量1");
public StaticVarible instVarible = new StaticVarible("父類-成員變量1");
static { System.out.println("父類-靜態塊"); }
{ System.out.println("父類-初始化塊"); }
public static StaticVarible staticVarible2 = new StaticVarible("父類-靜態變量2");
public StaticVarible instVarible2 = new StaticVarible("父類-成員變量2");
public Parent() { System.out.println("父類-構造函數"); }
}
class Child extends Parent {
public static StaticVarible staticVarible = new StaticVarible("子類-靜態變量1");
public StaticVarible instVarible = new StaticVarible("子類-成員變量1");
static { System.out.println("子類-靜態塊"); }
public Child() { System.out.println("子類-構造函數"); }
{ System.out.println("子類-初始化塊"); }
public static StaticVarible staticVarible2 = new StaticVarible("子類-靜態變量2");
public StaticVarible instVarible2 = new StaticVarible("子類-成員變量2");
}
class StaticVarible {
public StaticVarible(String info) { System.out.println(info); }
}
// 測試
Child child = new Child();
輸出順序為:
核心規律:父類靜態成員/塊 → 子類靜態成員/塊 → 父類實例成員/塊 → 父類構造器 → 子類實例成員/塊 → 子類構造器。靜態初始化在類加載階段完成,實例初始化在對象創建時依序執行。
String 作為特殊引用類型,兼具基本類型特性(不可變、常量池優化)與引用類型特徵。
以 String a = "abc"; 為例:
a{'a','b','c'}JVM 為節省內存維護字符串常量池,編譯期可確定的字面量會被緩存。關鍵區別在於編譯期常量與運行期常量:
public class StringTest {
public static final String constValue = "ab"; // 編譯期常量
public static final String staticValue; // 運行期常量
static { staticValue = "ab"; }
public static void main(String[] args) {
String v1 = "ab";
String v2 = "ab"; // true - 常量池緩存
String v3 = new String("ab"); // false - new 創建新對象
String v4 = "abcd";
String v5 = "ab" + "cd"; // true - 編譯期優化
String v6 = v1 + "cd"; // false - 運行期拼接
String v7 = constValue + "cd"; // true - 編譯期常量拼接
String v8 = staticValue + "cd"; // false - 運行期常量拼接
String v9 = v4.intern(); // true - 手動入池
String v10 = new String(new char[]{'a','b','c','d'});
String v11 = v10.intern(); // true - 手動入池
}
}
new String() 總創建新對象,需調用 intern() 手動入池class ParentDef {
public static final String staticValue = "父類靜態變量";
public String value = "父類實例變量";
}
class ChildDef extends ParentDef {
public static final String staticValue = "子類靜態變量";
public String value = "子類實例變量";
}
// 測試
ParentDef v1 = new ParentDef();
ParentDef v2 = new ChildDef();
ChildDef v3 = new ChildDef();
結果:
結論:字段訪問(含靜態/實例)遵循靜態綁定,僅取決於引用聲明類型;唯有實例方法遵循動態綁定(多態)。
Java 唯一支持值傳遞。基本類型傳值副本,引用類型傳引用副本(指向同一堆對象)。
public void change(int value) { value = 10; } // 基本類型:原值不變
public void change(Value value) { value = new Value(); } // 引用類型:重新指向新對象,原對象不變
public void add(Value value) { value.value += 10; } // 修改對象內部狀態:生效
關鍵點:方法內對參數引用的重新賦值不影響外部,但通過引用修改對象內部狀態則生效。
| 關鍵字 | 用途 | 關鍵規則 |
|---|---|---|
| final | 修飾類、方法、變量、參數 | 類不可繼承、方法不可重寫、變量只能賦值一次(聲明時/初始化塊/構造器) |
| finally | 異常處理塊 | 配合 try-catch,無論是否拋出異常/return/break/continue 均執行,用於資源釋放 |
| finalize | Object 方法 | GC 回收前調用,用於釋放非內存資源,不保證執行時機,Java 9+ 已棄用 |
| 類型 | 位數 | 包裝類 | 最小值 | 最大值 |
|---|---|---|---|---|
| byte | 8 | Byte | -128 | 127 |
| short | 16 | Short | -32,768 | 32,767 |
| int | 32 | Integer | -2,147,483,648 | 2,147,483,647 |
| long | 64 | Long | -9.22e18 | 9.22e18 |
| float | 32 | Float | 1.4E-45 | 3.4028235E38 |
| double | 64 | Double | 4.9E-324 | 1.7976931348623157E308 |
| char | 16 | Character | 0 | 65,535 |
| boolean | 1 (JVM實現相關) | Boolean | - | - |
LF注意:Java 8+ 推薦使用 java.time 包,以下為舊 API 要點:
java.util.Date:大多 getXxx() 方法已棄用,僅作時間戳容器java.util.Calendar:獲取日期細節的主力,月份 0-based(0=1月)java.text.SimpleDateFormat:格式化/解析,非線程安全Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH); // 0-11
int day = c.get(Calendar.DATE);
掌握類初始化順序、String 常量池、靜態/動態綁定、值傳遞本質、final 三重奏、基本類型規格與日期處理,構成 Java 核心基礎的「七大支柱」。這些知識不僅是面試高頻考點,更是編寫高效、無 Bug 代碼的基石。建議結合 JVM 規範與源碼深入理解,並在實戰中驗證每個結論。