Java數(shù)據(jù)類型主要包括兩種:基本類型 和 封裝類型
1. 基本類型
1.1 分類
Java的基本數(shù)據(jù)類型總共有8種徙赢,包括三大類:數(shù)值型狡赐,字符型钦幔,布爾型鲤氢,
- 數(shù)值型
- 整數(shù)類型:byte铜异、short、int咆蒿、long
- 浮點(diǎn)類型:float沃测、double
- 字符型:char
- 布爾型:boolean
1.2 大小和范圍
計(jì)算機(jī)內(nèi)存的最小存儲(chǔ)單元是字節(jié)(byte)食茎,一個(gè)字節(jié)就是一個(gè)8位二進(jìn)制數(shù)别渔,即8個(gè)bit哎媚。它的二進(jìn)制表示范圍從00000000 - 11111111,換算成十進(jìn)制是0 - 255稻据,換算成十六進(jìn)制是00 - ff捻悯。
類型 | 占用存儲(chǔ)空間 | 大小/范圍 | 默認(rèn)值 |
---|---|---|---|
byte | 1字節(jié) | -27 ~ 27-1 (-128 - 127) | (byte)0 |
short | 2字節(jié) | -215 ~ 215-1 (-32768 - 32767) | (short)0 |
int | 4字節(jié) | -231 ~ 231-1 (-2147483648 - 2147483647) | 0 |
long | 8字節(jié) | -263 ~ 263-1 | 0L |
float | 4字節(jié) | -2128 ~ +2128 (-3.40E+38 ~ +3.40E+38) | 0.0f |
double | 8字節(jié) | -21024 ~ +21024(-1.79E+308 ~ +1.79E+308) | 0.0d |
char | 2字節(jié) | 0 ~ 65535 | \u0000(空今缚,'') |
boolean | 1字節(jié) | true, false | false |
1.3 浮點(diǎn)型精度
float和double的浮點(diǎn)數(shù)在計(jì)算機(jī)上的存儲(chǔ)都遵循IEEE規(guī)范,在內(nèi)存中是按科學(xué)計(jì)數(shù)法來存儲(chǔ)的候齿。float是單精度浮點(diǎn)數(shù)慌盯,占4個(gè)字節(jié)(byte)亚皂,即32位(bit,比特)国瓮;double是雙精度浮點(diǎn)數(shù)乃摹,占8個(gè)字節(jié)(byte)峡懈,即64位(bit,比特)肪康。
-
單精度數(shù)據(jù)存儲(chǔ)格式撩穿,1位符號(hào)食寡,8位指數(shù)位抵皱,23位小數(shù)位辩蛋;
單精度數(shù)據(jù)存儲(chǔ)格式.png -
雙精度數(shù)據(jù)存儲(chǔ)格式伤为,1位符號(hào)据途,11位指數(shù)位颖医,52位小數(shù)位熔萧;
雙精度數(shù)據(jù)存儲(chǔ)格式.png - float和double的范圍是由指數(shù)的位數(shù)來決定的哪痰,精度是由小數(shù)的位數(shù)來決定的晌杰。
- float:指數(shù)位為2^8=128肋演,所以取值范圍為 -2128 ~ +2128;小數(shù)位為2^23 = 8388608蜕乡,共7位层玲,意味著最多能有7位有效數(shù)字,但絕對(duì)能保證的為6位畔派,也即float的精度為6~7位有效數(shù)字线椰;
- double:指數(shù)位為2^11=1024憨愉,所以取值范圍為 -21024 ~ +21024卿捎;小數(shù)位為2^52 = 4503599627370496娇澎,一共16位趟庄,同理戚啥,double的精度為15~16位。
1.4 java基本類型轉(zhuǎn)換
Java是強(qiáng)類型的編程語言锉试,其數(shù)據(jù)類型在定義時(shí)就已經(jīng)確定了猫十,因此不能隨意轉(zhuǎn)換成其他的數(shù)據(jù)類型,但是Java允許將一種類型賦值給另一種類型呆盖。
- 在Java中拖云,boolean類型與其他7種類型的數(shù)據(jù)都不能進(jìn)行轉(zhuǎn)換,但對(duì)于其他7種數(shù)據(jù)類型应又,它們之間都可以進(jìn)行轉(zhuǎn)換宙项,只是可能會(huì)存在精度損失或其他一些變化。轉(zhuǎn)換分為自動(dòng)轉(zhuǎn)換和強(qiáng)制轉(zhuǎn)換:
- 自動(dòng)類型轉(zhuǎn)換(隱式):無需任何操作
- 強(qiáng)制類型轉(zhuǎn)換(顯式):需使用轉(zhuǎn)換操作符
- 自動(dòng)類型轉(zhuǎn)換需要滿足如下兩個(gè)條件:
- 轉(zhuǎn)換前的數(shù)據(jù)類型與轉(zhuǎn)換后的數(shù)據(jù)類型兼容尤筐;
- 轉(zhuǎn)換后的數(shù)據(jù)類型的表示范圍比轉(zhuǎn)換前的類型大。
- 6種數(shù)值類型作如下排序:
double > float > long > int > short > byte
那么從小轉(zhuǎn)換到大洞就,那么可以直接轉(zhuǎn)換盆繁,而從大到小,或char或其他6種數(shù)據(jù)類型轉(zhuǎn)換旬蟋,則必須使用強(qiáng)制轉(zhuǎn)換油昂,且可能會(huì)發(fā)生精度損失。
2. 封裝類型
2.1 8種基本類型和封裝類型的對(duì)應(yīng)
基本類型 | byte | int | short | float | double | long | char | boolean |
---|---|---|---|---|---|---|---|---|
封裝類型 | Byte | Integer | Short | Float | Double | Long | Character | Boolean |
封裝類型與基本類型相比,有如下區(qū)別:
- 1.從參數(shù)傳遞上來說冕碟,基本類型只能按值傳遞拦惋,而每個(gè)封裝類都是按引用傳遞的;
- 2.從存儲(chǔ)的位置上來說鸣哀,基本類型是存儲(chǔ)在棧中的架忌,而所有的對(duì)象都是在堆上創(chuàng)建和存儲(chǔ)的,所以基本類型的存取速度要快于在堆中的封裝類型的實(shí)例對(duì)象我衬;JDK5.0開始可以自動(dòng)封包了 叹放,也就是基本數(shù)據(jù)可以自動(dòng)封裝成封裝類,基本數(shù)據(jù)類型的好處就是速度快(不涉及到對(duì)象的構(gòu)造和回收),封裝類的目的主要是更好的處理數(shù)據(jù)之間的轉(zhuǎn)換挠羔,方法很多井仰,用起來也方便。
- 3.基本類型的優(yōu)勢(shì)是:數(shù)據(jù)存儲(chǔ)相對(duì)簡單破加,運(yùn)算效率比較高俱恶;
- 4.封裝類型的優(yōu)勢(shì)是:類型轉(zhuǎn)換的api更好用了,比如Integer.parseInt(*)等的范舀,每個(gè)封裝類型都提供了parseXXX方法和toString方法合是。而且在集合當(dāng)中,也只能使用封裝類型锭环。封裝類型滿足了Java中一切皆對(duì)象的原則聪全。
2.2 封裝類的自動(dòng)裝箱和拆箱
- 自動(dòng)裝箱和拆箱測試
寫個(gè)簡單測試類,包含以下main方法
在cmd中用命令編譯和反編譯public static void main(String[] args) { Integer n = 50; // 自動(dòng)裝箱 int n1 = n; // 自動(dòng)拆箱 System.out.println(n1); }
編譯:javac Test3.java
反編譯:javap -c Test3.class
結(jié)果如下:
反編譯結(jié)果.png
可以看出辅辩,自動(dòng)裝箱使用了Integer.valueOf()
方法难礼,而拆箱過程執(zhí)行了n.intValue()
2.3 封裝類的緩存機(jī)制
- 緩存機(jī)制
以Integer類為例,上面說道Integer自動(dòng)裝箱使用了Integer.valueOf()
方法玫锋,我們查看一下此方法的源碼:
valueOf方法源碼.png
方法中IntegerCache設(shè)計(jì)到封裝類的緩存蛾茉,默認(rèn)情況下,IntegerCache.low=-128撩鹿,IntegerCache.high=127谦炬。即在執(zhí)行Integer.valueOf(num)方法時(shí),會(huì)先判斷num的大小三痰,如果小于-128或者大于127吧寺,就創(chuàng)建一個(gè)Integer對(duì)象,否則就從IntegerCache中來獲取散劫。
查看IntegerCache
源碼稚机,可以看到取值范圍的大小,IntegerCache
源碼如下:
IntegerCache源碼.png
可以看出IntegerCache是一個(gè)靜態(tài)內(nèi)部類获搏,它包含low赖条、high和數(shù)組cache失乾。第一次使用Integer的時(shí)候創(chuàng)建值在-128到java.lang.Integer.IntegerCache.high
范圍內(nèi)的所有的Integer對(duì)象將其放入到cache數(shù)組中。其中java.lang.Integer.IntegerCache.high
默認(rèn)是127纬乍,可以在jvm啟動(dòng)時(shí)配置:- 若配置的值小于127碱茁,則取127,配置的值不管用
- 若配置的值在127 ~ 231-1(int型最大值)之間仿贬,
java.lang.Integer.IntegerCache.high
取配置的值 - 若配置大于231-1纽竣,則取231-1,配置的值也不管用
這是Integer緩存數(shù)據(jù)的機(jī)制茧泪。這也是為了減輕封裝類型相比于基本類型的性能消耗蜓氨。
- 類似Integer有緩存機(jī)制的類:Integer、Short队伟、Byte穴吹、Character、Long
- 浮點(diǎn)類型無緩存機(jī)制嗜侮,因浮點(diǎn)類型如Float和Double卻在任意區(qū)間都有無數(shù)個(gè)值
- Boolean內(nèi)部已經(jīng)提前創(chuàng)建好兩個(gè)對(duì)象港令,因?yàn)樗挥袃煞N情況
類型 | 默認(rèn)緩存范圍 |
---|---|
Integer | [-128,127] |
Short | [-128,127] |
Long | [-128,127) |
Character | [0,127] |
- 緩存機(jī)制相關(guān)小例子
public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1 == i2); //true
System.out.println(i3 == i4); //false
}
}
執(zhí)行結(jié)果大家可能出乎意料,原因是什么呢锈颗,結(jié)合Integer緩存機(jī)制的說明顷霹,可以明白這個(gè)過程如下:
- i1和i2會(huì)進(jìn)行自動(dòng)裝箱,執(zhí)行了valueOf方法击吱,它們的值落在[-128,128)泼返,所以它們?nèi)〉降腎ntegerCache.cache中的是同一個(gè)對(duì)象,所以它們是相等的姨拥;
- i3和i4也會(huì)進(jìn)行自動(dòng)裝箱,執(zhí)行valueOf方法時(shí)渠鸽,它們的值都大于128叫乌,所以會(huì)執(zhí)行new Integer(200),也即它們分別創(chuàng)建了兩個(gè)不同的對(duì)象徽缚,所以它們肯定不相等
需要注意的幾點(diǎn):
- 當(dāng)一個(gè)基本數(shù)據(jù)類型與封裝類型進(jìn)行==憨奸、+、-凿试、*排宰、/運(yùn)算時(shí),會(huì)將封裝類進(jìn)行拆箱那婉,對(duì)基本數(shù)據(jù)類型進(jìn)行運(yùn)算板甘;
- 拆箱完成運(yùn)算之后,如果返回的結(jié)果需要是封裝類型详炬,則需要進(jìn)行自動(dòng)裝箱盐类,返回封裝對(duì)象;
- equals(Object o)方法每個(gè)封裝類中都略有不同,但它必須滿足兩個(gè)條件才為true: 類型相同和內(nèi)容相同
Integer num1 = 100;
int num2 = 100;
Long num3 = 200l;
System.out.println(num1 + num2); // 200
System.out.println(num3 == (num1 + num2)); // true
System.out.println(num3.equals(num1 + num2)); // false在跳,因類型不同