Java基本數據類型深入解析

java中基本數據類型一共有8種:

  • 整數類型4種:byte、short、int、long
  • 浮點數類型2種:float、double
  • 字符類型1種:char
  • 布爾類型1種:boolean

基本數據類型是學習編程語言時首先接觸的知識點,看似簡單,但是其中有很多容易被忽略的細節,有很多摸不着頭腦的bug往往出在最簡單的基礎部分,下面對基本數據類型進行一下深入解析,爲以後的代碼之路排排雷。


第一部分:整數類型深入解析

首先給出整數類型所佔字節大小和它們的數據範圍:
byte:8位,最大存儲數據量是255,存放的數據範圍是-128~127之間。

short:16位,最大數據存儲量是65536,數據範圍是-32768~32767之間。

int:32位,最大數據存儲容量是2的32次方減1,數據範圍是負的2的31次方到正的2的31次方減1。

long:64位,最大數據存儲容量是2的64次方減1,數據範圍爲負的2的63次方到正的2的63次方減1。

  • 問題1:整型數據爲什麼有這麼多種,直接使用範圍最大的long不就可以了,何必那麼麻煩去選擇不同的整型類型?
    答:java語言所使用的領域很廣泛,當應用在內存較小的設備上時,爲了性能的提升,勢必要對內存的佔用錙銖必較,long類型雖然表示的範圍大,但是一個long類型的整型數內存相比於其他三種類型佔用內存最大,在對內存設計有要求時需要慎重選擇數據類型。

  • 問題2:總是記不住它們的表示範圍怎麼辦?
    答:不需要死記硬背,使用java中自帶的包裝類能夠直接得出:
    byte的最小值:Byte.MIN_VALUE 最大值:Byte.MAX_VALUE
    short最小值:Short.MIN_VALUE 最大值:Short.MAX_VALUE
    int的最小值:Integer.MIN_VALUE 最大值:Integer.MAX_VALUE
    long的最小值:Long.MIN_VALUE 最大值:Long.MAX_VALUE


第二部分:浮點數類型深入解析

float:32位,負數取值範圍爲 -3.4028235E+38 ~ -1.4E-45,
正數取值範圍爲 1.4E-45 ~ 3.4028235E+38,直接賦值時必須在數字後加上f或F。

double:64位,負值取值範圍 -1.7976931348623157E+308 ~ -4.9E-324,
正值取值範圍爲 4.9E-324 ~ 1.7976931348623157E+308,賦值時可以加d或D也可以不加。

關於浮點數的細節很多,但我們首先必須明確浮點數的定義:

浮點數是一種對於實數的近似值數值表現。也就是說,浮點數不同於整型數,它並不能準確表示一個實數。

因此進行浮點運算時,這種運算通常伴隨着因爲無法精確表示而進行的近似或舍入,也就是所謂的精度丟失。例如當你計算double d = (1.2-0.4)/0.1時,計算結果爲7.999999999999999,因此浮點運算不能應用在類似於銀行系統需要精確數值的系統中。浮點數不適合用於精確計算,而適合進行科學計算。

  • 爲什麼浮點數不能準確的表示一個實數?
    我們的計算機是二進制的。浮點數沒有辦法是用二進制進行精確表示。我們的CPU表示浮點數由兩個部分組成:指數和尾數,這樣的表示方法一般都會失去一定的精確度,有些浮點數運算也會產生一定的誤差。如:2.4的二進制表示並非就是精確的2.4。反而最爲接近的二進制表示是 2.3999999999999999。浮點數的值實際上是由一個特定的數學公式計算得到的,符合IEEE 754 標準。(具體解釋可以參考:浮點計算中發生精度丟失的原因

  • 使用java包裝類得到浮點數的數值範圍:
    float的最小值:Float.MIN_VALUE 最大值:Float.MAX_VALUE
    double的最小值:Double.MIN_VALUE 最大值:Double.MAX_VALUE
    當我們System.out.println(Float.MIN_VALUE)和System.out.println(Float.MAX_VALUE)時發現控制檯輸出的分別是1.4E-45和3.4028235E38,也就是實際輸出的是float能表示的最小正數和最大正數,要得到其負數表示範圍在正數前加上負號即可。(個人理解是:根本沒有必要分負數正數兩個部分輸出,因爲只要知道其正數表示範圍,那麼負數範圍也能直接看出)
    System.out.println(Double.MIN_VALUE)、System.out.println(Double.MAX_VALUE)跟float的類似,也是輸出它的最小正數和最大正數。

  • 浮點數據無法進行精確計算,那java通過什麼方法來進行精確計算?(部分參考自使用BigDecimal進行精確運算
    在大多數的商業計算中,一般採用java.math.BigDecimal類來進行精確計算。

在使用BigDecimal類來進行計算的時候,主要分爲以下步驟:

1、用float或者double變量構建BigDecimal對象。

2、通過調用BigDecimal的加,減,乘,除等相應的方法進行算術運算。

3、把BigDecimal對象轉換成float,double,int等類型。

一般來說,1.可以使用BigDecimal的構造方法或者靜態方法的valueOf()方法把基本類型的變量構建成BigDecimal對象,也可以用”“直接構建成BigDecimal對象。

BigDecimal b1 = new BigDecimal(Double.toString(1.2));
BigDecimal b2 = BigDecimal.valueOf(0,4);
BigDecimal b3 = new BigDecimal("0.1");

對於常用的加,減,乘,除,BigDecimal類提供了相應的成員方法。

public BigDecimal add(BigDecimal value);           //加法
public BigDecimal subtract(BigDecimal value);      //減法 
public BigDecimal multiply(BigDecimal value);      //乘法
public BigDecimal divide(BigDecimal valueint scale,int roundingMode);        //除法

這裏需要注意除法divide()中的後兩個參數:scale表示結果保留小數點後的幾位;roundingMode表示的是保留模式是什麼,是四捨五入還是其它的。divide()是一個被重載的方法,你也可以只寫兩個參數divide(BigDecimal value,int roundingMode),默認保存小數點後一位。

進行相應的計算後,我們可能需要將BigDecimal對象轉換成相應的基本數據類型的變量,可以使用floatValue(),doubleValue()等方法。

爲了使用方便,可以自己寫一個工具類來提供加減乘除運算:

public class Arith {
    /**
     * 提供精確加法計算的add方法
     * @param value1 被加數
     * @param value2 加數
     * @return 兩個參數的和
     */
    public static double add(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精確減法運算的sub方法
     * @param value1 被減數
     * @param value2 減數
     * @return 兩個參數的差
     */
    public static double sub(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精確乘法運算的mul方法
     * @param value1 被乘數
     * @param value2 乘數
     * @return 兩個參數的積
     */
    public static double mul(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供精確的除法運算方法div
     * @param value1 被除數
     * @param value2 除數
     * @param scale 精確範圍
     * @return 兩個參數的商
     * @throws IllegalAccessException
     */
    public static double div(double value1,double value2,int scale) throws IllegalAccessException{
        //如果精確範圍小於0,拋出異常信息
        if(scale<0){
            throw new IllegalAccessException("精確度不能小於0");
        }
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.divide(b2, scale).doubleValue();
    }
}

下面使用BigDecimal來計算(1.2-0.4)/0.1:

BigDecimal b1 = BigDecimal.valueOf(1.2);
        BigDecimal b2 = BigDecimal.valueOf(0.4);
        BigDecimal b3 = BigDecimal.valueOf(0.1);

        double d = b1.subtract(b2).divide(b3,BigDecimal.ROUND_HALF_UP).doubleValue();
        System.out.println(d);

輸出結果:8.0

結果沒有任何誤差!


第三部分:其他兩種類型

boolean:只有true和false兩個取值。

char:16位,存儲Unicode碼,用單引號賦值。


總結:

1.在使用整型數據時需要根據內存需求合理選擇數據類型,不需要死記硬背整型數和浮點數的數據表示範圍,直接通過它們對應的包裝類求出:X.MIN_VALUE、X.MAX_VALUE。
2.浮點數不適合用於精確計算,要進行精確計算可以使用BigDecimal。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章