[toc]
數(shù)據(jù)類型的出現(xiàn)是為了把數(shù)據(jù)分成所需內(nèi)存大小不同的數(shù)據(jù)山涡,合理、有效利用內(nèi)存绎狭。數(shù)據(jù)類型在計算機語言里面关带,是對內(nèi)存位置的一個抽象表達(dá)方式侥涵。
數(shù)據(jù)類型
在JAVA語言種將數(shù)據(jù)類型分為兩類:基本數(shù)據(jù)類型
和引用數(shù)據(jù)類型
-
基本類型
:簡單數(shù)據(jù)類型是不能簡化的、內(nèi)置的數(shù)據(jù)類型豫缨、由編程語言本身定義独令,它表示了真實的數(shù)字、字符和整數(shù)好芭。 -
引用數(shù)據(jù)類型
:Java語言的引用數(shù)據(jù)類型包括類燃箭、接口和數(shù)組類型,還有一種特殊的null類型舍败。引用數(shù)據(jù)類型是對一個對象的引用招狸,對象有兩種:數(shù)組和實例(面向?qū)ο蟮幕局R點敬拓,這篇文章主要以基本數(shù)據(jù)類型為主)
基本數(shù)據(jù)類型
基本數(shù)據(jù)類型分為4類,分別為整型裙戏、浮點型乘凸、字符型和布爾型
整型
1字節(jié)=8位
4種整型量都是有符號的,符號占一位(byte的取值范圍本該是2的8次方累榜,其他類似)营勤。
Java整數(shù)常量默認(rèn)是int類型
下表可以清楚的看出每個取值范圍
內(nèi)可以使用的數(shù)據(jù)類型
(這里沒有把負(fù)數(shù)部分畫出來)
取值范圍 | 0~127 | 128 ~ 32767 | 32768 ~ 2147483647 | 2147483648 ~ 9223372...... |
---|---|---|---|---|
數(shù)據(jù)類型 | byte、short壹罚、int葛作、long | short、int猖凛、long | int赂蠢、long | long |
- byte、short可以使用在其取值范圍內(nèi)的整數(shù)常量辨泳,系統(tǒng)自動把這些整數(shù)常量當(dāng)成byte或short類型處理虱岂。使用超出范圍的整數(shù)常量會報錯。
byte b = 127;
byte b2 = 128;//報錯:Required:byte Found:int(默認(rèn)是int類型)
- 如果把一個超出int取值范圍的整數(shù)常量賦值給long類型菠红,會報錯第岖;強制使用long類型需要在整數(shù)常量后加L(或l)
- 如果把一個int范圍內(nèi)的整數(shù)常量賦值給long類型,不會報錯途乃,是因為發(fā)生了自動類型轉(zhuǎn)換(下面會具體說明)
int num1 = 2147483647;
long l1 = 2147483647;//正常绍傲,發(fā)生了自動類型轉(zhuǎn)換
int num2 = 2147483648;//報錯: Integer number too
large
long l2 = 2147483648;//報錯: Integer number too
large
long l3 = 2147483648L;//正常
整數(shù)常量的四種表示方式
- 二進制:0b或0B開頭(java7開始支持)
- 八進制:0開頭
- 十進制:不做過多說明
- 十六進制:0x或0X開頭
int num1=013;//八進制
int num2=0x13;//十六進制
重點說明二進制表示方式
所有數(shù)字在計算機底層都是以二進制形式表示的扔傅,原碼是直接將一個數(shù)值換算成二進制數(shù)耍共。計算機是以補碼形式保存所有的整數(shù)。正數(shù)的補碼和原碼完全相同猎塞,負(fù)數(shù)的補碼是原碼的反碼加1试读;反碼是對原碼按位取反,最高位符號位不變荠耽。
- 二進制整數(shù)的最高位是符號位钩骇,1表示負(fù)數(shù),0表示正數(shù)
- java整數(shù)常量默認(rèn)是int類型,所以二進制整數(shù)默認(rèn)占32位铝量,定義一個不足位的二進制整數(shù)時倘屹,會自動高位補齊(補0),第32位是符號位
- 系統(tǒng)對byte慢叨、short類型的使用與十進制一致
- 使用long類型需要在末尾加L(或l)纽匙,表示占64位,第64位是符號位
關(guān)于進制間的轉(zhuǎn)換請看
進制間的轉(zhuǎn)換 這篇文章
浮點型
- float(單精度浮點型):第1位是符號位拍谐,接下來8位表示指數(shù)烛缔,其余23位表示尾數(shù)
- double(雙精度浮點型):第1位符號位馏段,接下來11位表示指數(shù),其余52位表示尾數(shù)
浮點數(shù)的兩種表示方式
-
十進制數(shù)形式践瓷,float浮點數(shù)后加F(或f)院喜,double浮點數(shù)后加D(或d),浮點數(shù)必須包含一個小數(shù)點,
如
float f=5.1200_001f;//可以使用_分隔,方便校對數(shù)位
科學(xué)計數(shù)法形式晕翠,只有浮點型的數(shù)值可以使用科學(xué)計數(shù)法形式表示喷舀。如:5.12E2(5.12??10^2)
字符型
- java語言使用16位的Unicode字符集(關(guān)于字符編碼問題請看阮一峰的字符編碼筆記)作為編碼方式
- char類型的取值范圍是0~2^16(65536),是無符號的整數(shù)(正數(shù)),可以被用作整數(shù)類型的值來使用,同樣系統(tǒng)也會把整數(shù)類型的值當(dāng)成char類型處理
字符型常量的三種表示方式
- 直接通過單個字符來指定,如 'a','0'
- 通過轉(zhuǎn)義字符表示特殊字符型常量
常用轉(zhuǎn)義字符
- 直接使用Unicode值表示字符型常量,范圍'\u0000'-'\uFFFF',其中前256個('\u0000'-'\u00FF')字符和ASCII碼表中的字符安完成重合
布爾型
用于表示邏輯上的”真“或”假“
基本類型的類型轉(zhuǎn)換
自動類型轉(zhuǎn)換
取值范圍小的類型賦值給取值范圍大的類型淋肾,系統(tǒng)自動進行類型轉(zhuǎn)換元咙,如圖所示,可以根據(jù)箭頭指向發(fā)生自動轉(zhuǎn)換
強制類型轉(zhuǎn)換
強制類型轉(zhuǎn)換可能會丟失精度巫员,所以需要使用()進行類型轉(zhuǎn)換庶香。
32位int型最高位0表示正數(shù),轉(zhuǎn)換為byte類型简识,高位精度丟失赶掖,第8位為byte最高位,1表示負(fù)數(shù)七扰,因此正數(shù)的int型因丟失精度變成了負(fù)數(shù)的byte型奢赂。
表達(dá)式類型的自動提升
當(dāng)一個算術(shù)表達(dá)式中包含多個基本類型的值時,整個算術(shù)表達(dá)式的數(shù)據(jù)類型將發(fā)生自動提升
- byte颈走、short膳灶、char自動提升為int類型
- 整個表達(dá)式的數(shù)據(jù)類型自動提升到與表達(dá)式中最高等級操作數(shù)的數(shù)據(jù)類型
- 與字符串拼接規(guī)則:字符串在+號的左邊,表示字符串拼接,如果字符串在+號的右邊要具體看左邊的情況
System.out.println("Hello" + 'a' + 7);//Helloa7
System.out.println('a' + 7 + "Hello");//104Hello
包裝類
為什么還需要包裝類
Java中的int類型在內(nèi)存中只占用4個字節(jié)立由,而一個Object對象本身最少占用8個字節(jié)轧钓,另外還需要4個字節(jié)來引用它。除此之外CPU對基本類型的處理更加高效锐膜。
既然如此為什么還需要包裝類?
Java是面向?qū)ο蟮木幊陶Z言毕箍,但這8種基本數(shù)據(jù)類型并不支持面試對象的特性。所以 Java 需要一個這樣的包裝類來使其面向?qū)ο蟮耐暾?這樣一來基本類型具有了對象的特性道盏,例如:實現(xiàn)可空類型而柑,完成字符串像基本類型的轉(zhuǎn)換,另外Java 集合中只能放入包裝類型荷逞,不支持基本類型媒咳。
//可為空
Integer integer=null;
//字符串轉(zhuǎn)換為int型
int num=Integer.valueOf("123");
//java集合只能放入Integer類型,無法放入int類型
ArrayList<Integer> arrayList=new ArrayList<>();
緩沖池——減少內(nèi)存開銷种远,提高程序性能
Integer integer = Integer.valueOf(127);
int intValue = integer.intValue();
- 通過靜態(tài)方法valueOf將基本類型包裝為Integer類型
- 通過intValue方法將包裝類轉(zhuǎn)換為int類型涩澡。
private final int value;
//intValue方法比較簡單,直接返回value
public int intValue() {
return value;
}
//valueOf方法的內(nèi)部實現(xiàn)
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
可以從valueOf
方法內(nèi)部看到院促,傳入進來的i并不是直接調(diào)用new Integer(i)
來創(chuàng)建對象的筏养,而是通過IntegerCache.cache
緩存中獲取的斧抱。
IntegerCache是Integer的一個內(nèi)部類
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
從上面的代碼中,可以看到IntegerCache類中聲明了Integer cache[]
數(shù)組來緩存Integer
對象的渐溶,并且IntegerCache.low
和IntegerCache.high
常量確定了cache
的范圍從-128~127辉浦,也就是說不在這個范圍內(nèi)的值,會直接通過new Integer(i)
來創(chuàng)建對象茎辐。
Integer num1 = 127;
Integer num2 = 127;
System.out.println(num1 == num2);//引用的同一個對象所以輸出為 true
Integer num1 = 128;
Integer num2 = 128;
System.out.println(num1 == num2);//超出了緩存范圍輸出false
Integer integer1 = new Integer(127);
Integer integer2 = new Integer(127);
System.out.println(integer1 == integer2);//直接new的對象宪郊,未走緩存輸出false
在int和Integer類型之間轉(zhuǎn)換其實不需要如此的麻煩,從java5開始為我們提供了裝箱和拆箱的操作拖陆,簡化轉(zhuǎn)換過程弛槐。
自動裝箱、拆箱——只是一種語法糖
Integer a= 123; // 裝箱
int b = a; // 拆箱
裝箱和拆箱可以看成一種java語法糖依啰,javac編譯器會自動把裝箱轉(zhuǎn)換為Integer.valueOf(),把拆箱轉(zhuǎn)換為Integer.intValue()乎串,因此我們在使用裝箱時依然可以使用Integer
的緩存。
成員變量value的不可變性
包裝類的成員變量value
都使用了final
關(guān)鍵字修飾速警,這表明它們是不可變類型(常量)叹誉。
對于成員變量value
只需要明白3點就可以了
- 它的訪問修飾符是
pirvate
,所以外部無法修改它 - 使用了
final
關(guān)鍵字修飾闷旧,內(nèi)部一旦賦值便無法再改變 - 基本數(shù)據(jù)類型的不可變性滿足上面兩點就可以了长豁,不像引用類型,被final修改后忙灼,引用本身不可變匠襟,但具體的實例是可以通過引用改變的。這點在
String
類型中詳細(xì)說明(String
是通過copyOf()
方法來保證不可變的)
之所以設(shè)計成不可變的的目的是為了保證基本的信息安全
和并發(fā)環(huán)境下的線程安全
其他基本類型的包裝類
- Boolean,緩存了true/false對應(yīng)實例
- Short该园,緩存范圍與Integer一致
- Byte酸舍,全部緩存
- Character,緩存范圍'\u0000' ~ '\u007F'
- Double和Float類型沒有使用緩存池
運算
將運算符和操作數(shù)連接在一起就形成了表達(dá)式
這里只對兩種運算做簡要說明(其實主要是為了記錄下)
- 邏輯運算符
//注釋
& :邏輯與 &&:短路與
| :邏輯或 ||:短路或
爬范! :邏輯非 ^:邏輯異或
- 位運算符(直接對二進制進行運算)