型別轉換是 Java 程式設計的基礎核心概念。Java 型別系統分為基本型別與參考型別兩大類,轉換規則各有不同。本文系統整理 Java 型別轉換的完整規則,包含基本型別的擴展/縮小轉換、參考型別的向上/向下轉型、以及字串與各型別的雙向轉換。
| 分類 | 型別 | 位元數 | 預設值 | 範圍 |
|---|---|---|---|---|
| 整數 | byte | 8 | 0 | -128 ~ 127 |
| short | 16 | 0 | -32,768 ~ 32,767 | |
| int | 32 | 0 | -2^31 ~ 2^31-1 | |
| long | 64 | 0L | -2^63 ~ 2^63-1 | |
| 浮點數 | float | 32 | 0.0f | ~±3.4E38 (7 位有效數字) |
| double | 64 | 0.0d | ~±1.7E308 (15 位有效數字) | |
| 字元 | char | 16 | '\u0000' | 0 ~ 65,535 (Unicode) |
| 布林 | boolean | 1 (JVM 實作相關) | false | true/false |
注意:boolean 不參與任何數值型別轉換。
Cloneable 與 Serializable)java.lang.Object從較小範圍型別自動轉換為較大範圍型別,不會遺失精度 (除 int→float、long→float 可能損失精度):
byte → short → int → long → float → double
char → int → long → float → double
發生時機:指派運算、方法呼叫傳參、算術運算子操作數提升。
int a = 100;
long b = a + 100; // a+100 先提升為 int,結果再擴展為 long
double d = 3.14f; // float → double
從較大範圍強制轉換為較小範圍,可能遺失精度或溢位,必須使用轉型運算子 (targetType):
double → float → long → int → short → byte
char ← int
int a = 200;
byte b = (byte) a; // 強制轉換:200 超出 byte 範圍,結果為 -56 (截斷高位元組)
long l = 9223372036854775807L;
int i = (int) l; // 溢位截斷
當 + 運算子一邊為 String,另一邊基本型別會自動轉為 String:
System.out.println("結果:" + 100); // "結果:100"
System.out.println("PI:" + 3.14159); // "PI:3.14159"
System.out.println("狀態:" + true); // "狀態:true"
實際上等同於 String.valueOf(基本型別值)。
子類別實例指派給父類別參考變數,無需轉型運算子,編譯期通過,執行期安全:
class Base {}
class Child extends Base {}
Base base = new Child(); // 向上轉型:Child 是 Base 的子類型
Object obj = "Hello"; // String 是 Object 子類型
向上轉型後,參考變數只能存取父類別定義的成員 (除非覆寫方法,動態繫結仍呼叫子類別實作)。
父類別參考轉為子類別參考,必須使用轉型運算子,執行期會檢查實際物件型別:
Base base = new Child();
Child child = (Child) base; // 合法:base 實際指向 Child 實例
Base base2 = new Base();
Child child2 = (Child) base2; // 編譯通過,執行期拋出 ClassCastException
if (base instanceof Child) {
Child child = (Child) base; // 保證安全
child.childMethod();
}
Java 14+ 支援 Pattern Matching for instanceof:
if (base instanceof Child child) {
child.childMethod(); // 直接使用 child 變數
}
無繼承關係的類別 (如 String 與 Integer) 絕對無法互相轉型,編譯期即報錯。
所有物件繼承 Object.toString(),預設輸出 類別名@雜湊碼。自訂類別應覆寫 toString() 提供有意義輸出:
class Person {
String name; int age;
@Override public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
Person p = new Person(); p.name = "王小明"; p.age = 25;
System.out.println(p); // 自動呼叫 toString()
String s = "用戶:" + new Person(); // 等同 "用戶:" + person.toString()
int i = Integer.parseInt("123");
double d = Double.parseDouble("3.14");
boolean b = Boolean.parseBoolean("true");
需視具體格式使用對應解析器:JSON (Jackson/Gson)、XML (JAXB)、日期時間 (DateTimeFormatter)、自訂格式 (正則/Scanner)。
Java 5+ 支援基本型別與對應包裝類別自動互轉:
| 基本型別 | 包裝類別 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
Integer i = 100; // 自動裝箱:Integer.valueOf(100)
int j = i; // 自動拆箱:i.intValue()
i = null; // 危險:拆箱時會拋出 NullPointerException
效能提醒:頻繁裝箱/拆箱會建立大量臨時物件,效能敏感路徑建議使用基本型別。
| 陷阱 | 說明 | 解決方案 |
|---|---|---|
| 整數除法截斷 | int a = 5/2; // 結果 2 | 至少一邊轉為浮點數:5/2.0 |
| 浮點數比較 | 0.1+0.2 == 0.3 // false | 使用 Math.abs(a-b) < epsilon 或 BigDecimal |
| 拆箱空指針 | Integer i = null; int j = i; // NPE | 拆箱前檢查 null,或使用 Optional |
| 字串數字比較 | "100" > "20" // true (字典序) | 轉為數值再比較 |
| 物件相等性 | new String("a") == new String("a") // false | 使用 .equals() 比較內容 |
Java 型別轉換遵循「擴展隱含、縮小明確、物件向上隱含、向下需檢查」原則。掌握基本型別轉換精度損失規則、參考型別轉型執行期檢查機制、String 雙向轉換慣用模式,能寫出更健壯、可維護的程式碼。