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

Java 類型轉換完全指南:自動拓寬、強制窄化、包裝拆箱與 Object 多態轉型實戰

     編輯:Java 程式設計入門

前言

類型轉換是 Java 程式執行期最頻繁、最隱蔽、最易出 Bug 的操作之一。本文系統梳理**基本型拓寬/窄化、包裝類拆箱裝箱、Object 多態轉型、字串⇄數字、集合泛型轉型**五大場景,並給出**編譯期/運行期檢查機制、精度損失量化、最佳實踐模式、避坑清單**。

一、基本型轉換:拓寬 vs 窄化

1. 自動拓寬 (Widening) —— 安全、無損失


byte  → short → int  → long  → float → double
             char ↗
  • **編譯器自動插入**轉型指令 (如 i2l, i2d)。
  • **精度**:int→long、long→float 可能損失精度 (float 只有 23 位尾數),但**不會溢出**。
  • **運算提升**:byte + short 先雙雙提升為 int 再相加,結果型別 int。

2. 強制窄化 (Narrowing) —— 風險、需強轉


double → float → long → int → short → byte
  • **語法**:(targetType) value。
  • **截斷規則**:高位直接切捨 (補碼截斷)。(byte) 256 == 0, (byte) -129 == 127。
  • **浮點→整數**:向零截斷。(int) 3.9 == 3, (int) -3.9 == -3。
  • **溢出行為**:無異常,模 2^n 環狀。(short) 70000 == 4464。

3. 精度損失量化表

轉換是否精確最大相對誤差典型風險場景
long → float❌~0.00001% (23-bit 尾數)大額金額單位轉換 (分→元)
long → double✅ (≤ 2^53)0安全範圍內精確
int → float❌ (> 2^24)~0.00001%大整數 ID 浮點存儲
double → long❌ (截斷小數)N/A價格計算、利息結算

二、包裝類與基本型:裝箱/拆箱陷阱

1. 自動裝箱/拆箱語法糖


Integer i = 100;        // 裝箱 → Integer.valueOf(100)
int n = i;              // 拆箱 → i.intValue()
i++;                    // 拆箱 → i.intValue() + 1 → 裝箱 → Integer.valueOf(...)

2. 快取池與 == 陷阱


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(),禁用 ==**。

3. 空指針陷阱


Integer obj = null;
int n = obj; // NPE! 拆箱調用 obj.intValue()
  • **防禦**:int n = Optional.ofNullable(obj).orElse(0); 或 obj != null ? obj : 0。

三、Object 多態轉型:向上/向下/橫向

1. 向上轉型 (Upcasting) —— 隱式、安全


Object obj = "hello";      // String → Object
Number num = Integer.valueOf(10); // Integer → Number
List list = new ArrayList<>(); // ArrayList → List
  • **編譯期通過**,**運行期無開銷**,只是引用型別變寬。

2. 向下轉型 (Downcasting) —— 顯式、需 instanceof 守衛


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;
    ...
}

3. 橫向轉型 (Cross-cast) —— 不可能、編譯錯誤


// Integer → String 無繼承關係
// String s = (String) Integer.valueOf(10); // Compile Error: inconvertible types

四、字串 ⇄ 數字:標準庫最佳實踐

方向推薦 API備註
String → intInteger.parseInt(str)返回基本型 int,無物件分配
String → IntegerInteger.valueOf(str)返回包裝類,複用快取池
int → StringString.valueOf(i) / Integer.toString(i)String.valueOf 內部調用 Integer.toString
String → long/doubleLong.parseLong / Double.parseDouble同理
進制轉換Integer.parseInt(str, 16) / Integer.toHexString(i)基數 2~36

⚠️ **禁用**:new Integer(str) (JDK 9+ 棄用)、Integer.getInteger("key") (讀系統屬性、非解析)。

五、集合泛型轉型:Pecs 與類型擦除


// 錯誤:List ≠ List 父子關係
List strs = new ArrayList<>();
// List objs = strs; // Compile Error

// 正確:通配符
List objs = strs; // 只讀
List consumers = new ArrayList(); // 只寫


六、生產級轉型工具類


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;
    }
}

七、避坑清單

  1. 金額計算禁用 float/double:用 BigDecimal 或 **長整數存分**。
  2. 包裝類比值用 .equals(),基本型用 ==。
  3. 向下轉型必加 instanceof 守衛 (JDK 16+ 用 Pattern Matching)。
  4. 字串解析數字捕獲 NumberFormatException,提供預設值。
  5. 集合泛型無協變:List 不能賦值給 List。
  6. 避免在循環中裝箱:Long sum = 0L; for(...) sum += i; 每次分配 Long → 用基本型累加最後裝箱。
  7. 💡 核心原則:基本型優先、包裝類慎用、轉型必守衛、字串解析必捕獲、金額用 BigDecimal。

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