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

Java 強制型別轉換完整指南:引用型別轉型規則與 ClassCastException 避坑

     編輯:Java 相關知識

兩大分類

  1. 基本型別轉換:自動擴大 (widening) 與強制縮小 (narrowing),如 int → long / double → int。
  2. 引用型別轉換 (本文重點):繼承體系中的向上/向下轉型。

向上轉型 — 安全、自動、隱式


Animal animal = new Dog(); // 子類型 → 父類型
Object obj = "Hello";      // 介面/父類別引用指向子類別物件
  • 編譯器自動處理,永不拋出例外。
  • 引用型別變為父類型,**物件本身不變** (仍是 Dog 實例)。
  • 只能透過父類型引用呼叫父類別定義的方法/欄位 (除非多型調用覆寫方法)。

向下轉型 — 風險、強制、需執行時檢查


Animal animal = new Dog();
Dog dog = (Dog) animal; // 必須強制轉型
  • 編譯器僅檢查**繼承關係是否存在** (Animal 是 Dog 父類別 → 通過)。
  • **執行時**檢查物件**真實型別**是否為目標型別或其子類別。
  • 若真實型別不匹配 → 拋出 ClassCastException。

ClassCastException 經典場景


// 場景 1:物件真實型別為父類別
Animal animal = new Animal(); // 真實是 Animal
Dog dog = (Dog) animal; // 執行時崩潰:Animal cannot be cast to Dog

// 場景 2:兄弟類別互轉
Cat cat = new Cat();
Dog dog = (Dog) cat; // 編譯錯誤:Cat 與 Dog 無繼承關係 (編譯器直接攔截)

// 場景 3:集合元素取出轉型
List list = new ArrayList<>();
list.add("String");
list.add(123);
Integer num = (Integer) list.get(0); // 執行時崩潰:String cannot be cast to Integer


安全轉型模式

1. instanceof 守衛 (Java 14+ Pattern Matching)


// Java 14+ 模式匹配
if (animal instanceof Dog dog) {
    dog.bark(); // 自動轉型並賦值
}

// Java 14 前
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();
}

2. 多型設計避免轉型 (最佳實踐)


// 不好:到處 instanceof 轉型
if (animal instanceof Dog) ((Dog)animal).bark();
else if (animal instanceof Cat) ((Cat)animal).meow();

// 好:定義抽象方法,子類別實作
abstract class Animal { abstract void makeSound(); }
class Dog extends Animal { void makeSound() { bark(); } }
class Cat extends Animal { void makeSound() { meow(); } }

// 使用
animal.makeSound(); // 多型分派,零轉型

3. 介面型別編程


List list = new ArrayList<>(); // 介面引用
// 僅使用 List 方法,無需轉型為 ArrayList

泛型與類型擦除的轉型陷阱


List strings = new ArrayList<>();
strings.add("hello");

// 編譯時警告:unchecked cast
List objects = (List) strings; // 執行時不會崩潰 (類型擦除),但極度危險!
objects.add(123); // 污染了 strings 列表
String s = strings.get(1); // 執行時 ClassCastException:Integer cannot be cast to String

鐵律:絕不轉型泛型集合。使用 List<?>、List<? extends T>、List<? super T> 通配符表達協變/逆變。

陣列轉型特殊規則

  • 陣列是**協變**的:Dog[] dogs = new Dog[3]; Animal[] animals = dogs; (合法)。
  • 但寫入時執行時檢查:animals[0] = new Cat(); → ArrayStoreException。
  • 陣列向下轉型需強制:Dog[] dogs2 = (Dog[]) animals; (若 animals 真實為 Dog[] 則成功)。
  • **建議用 List<T> 取代陣列** 避免協變陷阱。

效能考量

  • 向上轉型:零成本 (編譯期)。
  • 向下轉型:執行時型別檢查 (JVM 查詢物件頭 Class 指標),極快 (納秒級),但熱路徑大量轉型可考慮多型重構。
  • instanceof 檢查同樣極快,JIT 會優化。

總結:轉型決策樹

  1. 是否有繼承/實作關係?否 → 編譯錯誤。
  2. 子類別引用賦值給父類別變數?→ 自動向上轉型 (安全)。
  3. 父類別引用賦值給子類別變數?→ 必須強制向下轉型。
  4. 能否用 instanceof 守衛?→ 是 → 安全轉型。
  5. 能否重構為多型調用?→ 是 → 消除轉型 (最佳)。
  6. 是否涉及泛型集合轉型?→ 禁止,改用通配符。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved