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 value,int 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。