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

Java 基礎進階實戰:原碼反碼補碼、枚舉、變量遮蔽、浮點數精度與 BigDecimal

     編輯:Java 綜合教學

Java 基礎進階實戰:原碼反碼補碼、枚舉、變量遮蔽、浮點數精度與 BigDecimal

本文匯總 8 個經典 Java 基礎課堂練習,涵蓋計算機數制表示、枚舉類型本質、變量作用域遮蔽、數據類型轉換精度損失、浮點數運算陷阱、BigDecimal 精確計算、字符串拼接優先級、除零異常處理。每題附帶代碼、運行結果與深度解析,助你夯實基本功。

一、原碼、反碼、補碼:計算機為什麼用補碼?

核心概念

  • 機器數:帶符號位的二進制表示(最高位 0 正、1 負)。
  • 真值:機器數代表的實際數值(如 10000011 真值為 -3)。
  • 原碼:符號位 + 絕對值二進制(+1: 00000001,-1: 10000001)。
  • 反碼:正數不變,負數符號位不變,其餘位取反(-1: 11111110)。
  • 補碼:正數不變,負數在反碼基礎上 +1(-1: 11111111)。

為什麼採用補碼?

  1. 原碼直接參與運算,減法結果錯誤(1-1=-2)。
  2. 反碼解決運算問題,但出現「+0」與「-0」兩種編碼,浪費一個碼位。
  3. 補碼修復 +0/-0 問題,多表示一個最小值(8位:-128~127),統一符號位參與運算,硬件電路最簡單(只有加法器)。

Java 結論:int 32 位補碼表示範圍 [-2^31, 2^31-1],所有位運算 (<<, >>, >>>, &, |, ^) 均基於補碼。

二、枚舉類型深度解析

代碼

enum Size { SMALL, MEDIUM, LARGE }
public class EnumTest {
    public static void main(String[] args) {
        Size s = Size.SMALL;
        Size t = Size.LARGE;
        System.out.println(s == t);                    // false
        System.out.println(s.getClass().isPrimitive()); // false
        Size u = Size.valueOf("SMALL");
        System.out.println(s == u);                    // true
        for (Size v : Size.values()) System.out.println(v);
    }
}

運行結果

false
false
true
SMALL
MEDIUM
LARGE

核心結論

  • 枚舉是引用類型,非基本類型,每個常量是單例對象。
  • == 與 equals() 效果相同,均比較引用地址。
  • valueOf(String) 返回同名常量單例,values() 返回所有常量數組。
  • 編譯後實際生成 final class Size extends Enum<Size>,不可繼承。

三、變量遮蔽原則驗證

代碼

public class My1 {
    private static int value = 1;  // 類變量(全局)
    public static void main(String[] args) {
        int value = 2;             // 局部變量
        System.out.println(value); // 輸出 2
    }
}

結論

  • 局部變量遮蔽同名類變量:方法內定義優先,生命周期隨方法結束。
  • 若方法內無同名變量,則使用類變量(靜態字段)。
  • 最佳實踐:避免同名,類變量用 this.value 或 My1.value 顯式訪問。

四、數據類型自動/強制轉換精度損失圖解

類型轉換關係圖

  • 實線 (實心箭頭):自動類型提升,無精度損失(低精度→高精度,如 int→long→float→double)。
  • 虛線 (虛線箭頭):強制類型轉換,可能精度損失/溢出(高精度→低精度,如 double→long→int)。
  • 特例:float f = 1.0f; 必須加 f,否則 1.0 默認 double 編譯錯誤。

五、浮點數運算陷阱:0.05 + 0.01 ≠ 0.06

代碼與輸出

System.out.println(0.05 + 0.01); // 0.060000000000000005
System.out.println(1.0 - 0.42);  // 0.5800000000000001

根本原因

  • 十進制小數無法精確轉為二進制浮點數(IEEE 754 格式:符號位+指數位+尾數位)。
  • 0.05 二進制是無限循環小數,存儲時截斷產生誤差,運算放大誤差。
  • 金融/商業計算嚴禁使用 float/double。

六、BigDecimal 精確計算:構造器選擇決定成敗

代碼對比

BigDecimal f1 = new BigDecimal("0.05");   // 字符串構造 - 精確
BigDecimal f2 = BigDecimal.valueOf(0.01); // valueOf(double) - 精確
BigDecimal f3 = new BigDecimal(0.05);     // double構造 - 攜帶誤差!

System.out.println(f1.add(f2)); // 0.06 ✓
System.out.println(f3.add(f2)); // 0.06000000000000000471... ✗

鐵律

構建 BigDecimal 必須使用字符串構造器或 valueOf(double),絕不使用 new BigDecimal(double)。

七、字符串拼接與加法運算優先級陷阱

代碼

int X=100, Y=200;
System.out.println("X+Y=" + X + Y); // "X+Y=100200" (字符串拼接)
System.out.println(X + Y + "=X+Y"); // "300=X+Y"    (先算數學加法)

規則

  • 左到右執行,遇到字符串即切換拼接模式。
  • 第一例:`"X+Y="` 是字符串,後續 `+` 全變拼接。
  • 第二例:`X+Y` 先算數學加法得 300,再與字符串拼接。

八、除零異常與特殊浮點數值

運算結果判斷方法
非 0 / 0.0Infinity (正/負)Double.isInfinite(d)
0.0 / 0.0NaN (Not a Number)Double.isNaN(d)
整數 / 0ArithmeticExceptiontry-catch 捕獲

代碼驗證

double a=0, b=50, c=-50;
System.out.println(a/a); // NaN
System.out.println(b/a); // Infinity
System.out.println(c/a); // -Infinity

總結速查卡

✅ 最佳實踐

  • 金額計算只用 BigDecimal(String)
  • 枚舉比較用 == 或 equals()
  • 避免變量遮蔽,命名加前綴
  • 除零檢查:分母!=0 或捕獲異常

❌ 常見坑點

  • new BigDecimal(double) 帶入誤差
  • float/double 比較用 ==
  • 字符串拼接順序導致邏輯錯誤
  • 整數除零拋異常未捕獲

這 8 個練習覆蓋了 Java 基礎中最易混淆、最易出錯的核心知識點。建議將代碼全部敲一遍,觀察輸出,並嘗試修改參數驗證邊界條件,真正內化為肌肉記憶。

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