類型轉換是 Java 程式執行期最頻繁、最隱蔽、最易出 Bug 的操作之一。本文系統梳理**基本型拓寬/窄化、包裝類拆箱裝箱、Object 多態轉型、字串⇄數字、集合泛型轉型**五大場景,並給出**編譯期/運行期檢查機制、精度損失量化、最佳實踐模式、避坑清單**。
byte → short → int → long → float → double
char ↗
i2l, i2d)。int→long、long→float 可能損失精度 (float 只有 23 位尾數),但**不會溢出**。byte + short 先雙雙提升為 int 再相加,結果型別 int。
double → float → long → int → short → byte
(targetType) value。(byte) 256 == 0, (byte) -129 == 127。(int) 3.9 == 3, (int) -3.9 == -3。(short) 70000 == 4464。| 轉換 | 是否精確 | 最大相對誤差 | 典型風險場景 |
|---|---|---|---|
long → float | ❌ | ~0.00001% (23-bit 尾數) | 大額金額單位轉換 (分→元) |
long → double | ✅ (≤ 2^53) | 0 | 安全範圍內精確 |
int → float | ❌ (> 2^24) | ~0.00001% | 大整數 ID 浮點存儲 |
double → long | ❌ (截斷小數) | N/A | 價格計算、利息結算 |
Integer i = 100; // 裝箱 → Integer.valueOf(100)
int n = i; // 拆箱 → i.intValue()
i++; // 拆箱 → i.intValue() + 1 → 裝箱 → Integer.valueOf(...)
Integer a = 100; Integer b = 100; // [-128, 127] 快取池
System.out.println(a == b); // true (同一物件)
Integer c = 200; Integer d = 200; // 超出快取範圍
System.out.println(c == d); // false (不同物件)
System.out.println(c.equals(d)); // true (值相等)
Byte/Short/Integer/Long 預設 [-128, 127],可用 -XX:AutoBoxCacheMax=2000 調大 Integer 快取。.equals(),禁用 ==**。
Integer obj = null;
int n = obj; // NPE! 拆箱調用 obj.intValue()
int n = Optional.ofNullable(obj).orElse(0); 或 obj != null ? obj : 0。
Object obj = "hello"; // String → Object
Number num = Integer.valueOf(10); // Integer → Number
List list = new ArrayList<>(); // ArrayList → List
Object obj = "hello";
// String s = (String) obj; // 風險:若 obj 為 Integer 拋 ClassCastException
// 安全模式
if (obj instanceof String s) { // JDK 16+ Pattern Matching
System.out.println(s.length());
}
// 傳統寫法
if (obj instanceof String) {
String s = (String) obj;
...
}
// Integer → String 無繼承關係
// String s = (String) Integer.valueOf(10); // Compile Error: inconvertible types
| 方向 | 推薦 API | 備註 |
|---|---|---|
| String → int | Integer.parseInt(str) | 返回基本型 int,無物件分配 |
| String → Integer | Integer.valueOf(str) | 返回包裝類,複用快取池 |
| int → String | String.valueOf(i) / Integer.toString(i) | String.valueOf 內部調用 Integer.toString |
| String → long/double | Long.parseLong / Double.parseDouble | 同理 |
| 進制轉換 | Integer.parseInt(str, 16) / Integer.toHexString(i) | 基數 2~36 |
⚠️ **禁用**:
new Integer(str)(JDK 9+ 棄用)、Integer.getInteger("key")(讀系統屬性、非解析)。
// 錯誤:List
public final class TypeConverts {
private TypeConverts() {}
/** 安全轉換 Object → int (null→0, 非數字→0, 異常→defaultVal) */
public static int toInt(Object obj, int defaultVal) {
if (obj == null) return defaultVal;
if (obj instanceof Number) return ((Number) obj).intValue();
if (obj instanceof String) {
try { return Integer.parseInt((String) obj); }
catch (NumberFormatException ignored) {}
}
return defaultVal;
}
/** 安全轉換 Object → Long */
public static long toLong(Object obj, long defaultVal) {
if (obj == null) return defaultVal;
if (obj instanceof Number) return ((Number) obj).longValue();
if (obj instanceof String) {
try { return Long.parseLong((String) obj); }
catch (NumberFormatException ignored) {}
}
return defaultVal;
}
/** 安全轉換 Object → Double (保留精度) */
public static double toDouble(Object obj, double defaultVal) {
if (obj == null) return defaultVal;
if (obj instanceof Number) return ((Number) obj).doubleValue();
if (obj instanceof String) {
try { return Double.parseDouble((String) obj); }
catch (NumberFormatException ignored) {}
}
return defaultVal;
}
/** 安全轉換 Object → String (null→"") */
public static String toStr(Object obj) {
return obj == null ? "" : obj.toString();
}
/** 安全轉換 Object → Boolean */
public static boolean toBool(Object obj, boolean defaultVal) {
if (obj == null) return defaultVal;
if (obj instanceof Boolean) return (Boolean) obj;
if (obj instanceof String) return Boolean.parseBoolean((String) obj);
if (obj instanceof Number) return ((Number) obj).intValue() != 0;
return defaultVal;
}
}
BigDecimal 或 **長整數存分**。.equals(),基本型用 ==。instanceof 守衛 (JDK 16+ 用 Pattern Matching)。NumberFormatException,提供預設值。List 不能賦值給 List。Long sum = 0L; for(...) sum += i; 每次分配 Long → 用基本型累加最後裝箱。💡 核心原則:基本型優先、包裝類慎用、轉型必守衛、字串解析必捕獲、金額用 BigDecimal。