給大家分享我收藏的幾個(gè)不錯(cuò)的 github 項(xiàng)目,內(nèi)容都還是不錯(cuò)的,如果覺得有幫助,可以順便給個(gè) star。
- 計(jì)算機(jī)專業(yè)學(xué)生必須要啃的書籍推薦: https://github.com/hello-go-maker/cs-books
- Java 實(shí)戰(zhàn)項(xiàng)目推薦: https://github.com/hello-go-maker/Java-project
- 推薦一些很不錯(cuò)的計(jì)算機(jī)學(xué)習(xí)教程,包括:數(shù)據(jù)結(jié)構(gòu)、算法、計(jì)算機(jī)網(wǎng)絡(luò)、操作系統(tǒng)、Java(spring、springmvc、springboot、springcloud),也包括多個(gè)企業(yè)級(jí)實(shí)戰(zhàn)項(xiàng)目: https://github.com/hello-go-maker/cs-learn-source
- 【Java面試+Java后端技術(shù)學(xué)習(xí)指南】:一份通向理想互聯(lián)網(wǎng)公司的面試指南,包括 Java,技術(shù)面試必備基礎(chǔ)知識(shí)、Leetcode、計(jì)算機(jī)操作系統(tǒng)、計(jì)算機(jī)網(wǎng)絡(luò)、系統(tǒng)設(shè)計(jì)、分布式、數(shù)據(jù)庫(MySQL、Redis)、Java 項(xiàng)目實(shí)戰(zhàn)等: https://github.com/hello-java-maker/JavaInterview
一、基本類型的簡(jiǎn)介
基本類型的兩條準(zhǔn)則:
- Java中,如果對(duì)整數(shù)不指定類型,默認(rèn)時(shí)int類型,對(duì)小數(shù)不指定類型,默認(rèn)是double類型。
- 基本類型由小到大,可以自動(dòng)轉(zhuǎn)換,但是由大到小,則需要強(qiáng)制類型轉(zhuǎn)換。
所占的字節(jié)數(shù):
byte: 1個(gè)字節(jié);
char: 2個(gè)字節(jié);
short: 2個(gè)字節(jié);
int: 4個(gè)字節(jié);
long: 8個(gè)字節(jié);
float: 4個(gè)字節(jié);(6位小數(shù),指數(shù)是:10-38~1038; 范圍:)
double: 8個(gè)字節(jié);
char:Java中用 "\u四位十六進(jìn)制的數(shù)字 (即使在注釋中出現(xiàn)\u,后面如果
跟的不是4個(gè)16進(jìn)制的數(shù)字,也會(huì)報(bào)錯(cuò))"表示將字符轉(zhuǎn)換成對(duì)應(yīng)的unicode編 碼;也可以用字符來賦值如: char c="\u0000" ,char的默認(rèn)初始化值,unicode的null字符
基本類型的后綴:
long : l 或 L
float: f 或 F;
double: d 或 D
二、類型轉(zhuǎn)換
正如前面所說的,類型由大到小,是必需強(qiáng)制轉(zhuǎn)換。但這并不意味著需要用戶手動(dòng)強(qiáng)制轉(zhuǎn)換 —— 也就是 隱式轉(zhuǎn)換。隱式轉(zhuǎn)換 說的透徹點(diǎn)就是由編譯器來進(jìn)行強(qiáng)制轉(zhuǎn)換,不需要用戶再去寫強(qiáng)制轉(zhuǎn)換的代碼。下面的前兩個(gè)小點(diǎn)所說的便是特殊的隱式類型轉(zhuǎn)換。
本小節(jié)所討論的類型轉(zhuǎn)換是不包括 類型由小到大的轉(zhuǎn)換,討論的是其他比較容易讓人迷惑的類型轉(zhuǎn)換
1. int類型的字面常量轉(zhuǎn)換成比int類型低的變量類型
所謂的字面常量就是值的本身,如 5、7、“aa”等等。我們先看個(gè)例子:
public static void main(String[] args) {
int a = 8; //8是字面常量
byte b = 9; //9是字面常量
char c = 9+5;//常量表達(dá)式
short s = (short) (c+10); //變量表達(dá)式,需要顯式強(qiáng)制轉(zhuǎn)換
}
上面的代碼是經(jīng)過編譯的,是正確的。b是byte類型,但b=9不需要顯式地手動(dòng)強(qiáng)制轉(zhuǎn)換,這是因?yàn)?是字面常量,是由JVM自動(dòng)完成。
??我們?cè)賮砜匆幌?code>c=9+5,c是char類型,9+5得到結(jié)果是int類型,但也不需要顯式地手動(dòng)強(qiáng)制轉(zhuǎn)換。這是因?yàn)?9+5是常量表達(dá)式,所以在編譯期間已經(jīng)由編譯器計(jì)算出結(jié)果了,即經(jīng)過編譯后,相當(dāng)于 c=14,也是字面常量,所以可以隱式轉(zhuǎn)換。同理,short s = (short) (c+10); 子所以不能隱式轉(zhuǎn)換,就是因?yàn)楸磉_(dá)式不是常量表達(dá)式,包含了變量,只能在運(yùn)行期間完成,所以就要手動(dòng)強(qiáng)制轉(zhuǎn)換。
整形字面常量隱式轉(zhuǎn)換的限制:
- 整形字面常量的大小超出目標(biāo)類型所能表示的范圍時(shí),要手動(dòng)強(qiáng)制類型轉(zhuǎn)換。
byte b = 128;//編譯錯(cuò)誤,128超出byte類型所能表示的范圍
byte c = (byte)128;//編譯通過
- 對(duì)于傳參數(shù)時(shí),必須要顯式地進(jìn)行強(qiáng)制類型轉(zhuǎn)換,明確轉(zhuǎn)換的類型
編譯器子所以這樣要求,其實(shí)為了避免 方法重載出現(xiàn)的隱式轉(zhuǎn)換 與 小類型自動(dòng)轉(zhuǎn)大類型 發(fā)生沖突。
public static void main(String[] args) {
shortMethod(8);//編譯錯(cuò)誤
shortMethod((short)8); //編譯通過
longMethod(8);//編譯通過,因?yàn)檫@是小類型變成大類型,是不需要強(qiáng)制類型轉(zhuǎn)換的
}
public static void shortMethod(short c){
System.out.println(c);
}
public static void longMethod(short l){
System.out.println(l);
}
- char類型的特殊情況 :下面再細(xì)講
2. 復(fù)合運(yùn)算符的隱式轉(zhuǎn)換
復(fù)合運(yùn)算符(+=、-=、=、/=、%=)是可以將右邊表達(dá)式的類型自動(dòng)強(qiáng)制轉(zhuǎn)換成左邊的類型*
public static void main(String[] args) {
int a = 8;
short s = 5;
s += a;
s += a+5;
}
s+=a、s+=a+5;的表達(dá)式計(jì)算結(jié)果都是int類型,但都不需要手動(dòng)強(qiáng)制轉(zhuǎn)換。其實(shí),如果是反編譯這段代碼的class文件,你會(huì)發(fā)現(xiàn)s+=a;,其實(shí)是被編譯器處理成了
s=(short)(s+a)
也就是說對(duì)于所有的復(fù)合運(yùn)算的隱式類型轉(zhuǎn)換,其實(shí)是編譯器自動(dòng)添加類型轉(zhuǎn)換的代碼。
所以,相對(duì)于整形字面常量的隱式轉(zhuǎn)換,復(fù)合運(yùn)算符的隱式轉(zhuǎn)換則沒有任何限制因?yàn)榍罢咧荒茉诰幾g器期間發(fā)生,后者則是編譯器實(shí)實(shí)在在的補(bǔ)全了類型轉(zhuǎn)換的代碼。
3. 特殊的char類型
char類型在基本類中是一個(gè)比較特殊的存在。這種特殊性在于char類型是一個(gè)無符號(hào)類型,所以char類型與其他基本類型不是子集與父集間的關(guān)系(其他類型都是有符號(hào)的類型)。也就是說,char類型與byte、short之間的轉(zhuǎn)換都需要顯式的強(qiáng)制類型轉(zhuǎn)換(小類型自動(dòng)轉(zhuǎn)換成大類型失?。?。
同時(shí),由于char類型是一個(gè)無符號(hào)類型,所以對(duì)于整形字面常量的隱式轉(zhuǎn)換的限制,不僅包括字面常量數(shù)值的大小不能超出2個(gè)字節(jié),還包括字面常量數(shù)值不能為負(fù)數(shù)
byte b = 2;
char c = 2;//編譯通過
c = 100000000000;//編譯不通過,超出char類型的范圍
char d = -2//字面常量為負(fù)數(shù),編譯不通過
d = (char)-100;//編譯通過
char f = (char)b; //編譯通過,必須顯式的強(qiáng)制類型轉(zhuǎn)換
f = b;//編譯不通過,不能隱式轉(zhuǎn)換
int i = c;//編譯通過,可以不需要強(qiáng)制類型轉(zhuǎn)換
short s = (short) c;//編譯通過,必須顯式地強(qiáng)制類型轉(zhuǎn)換
char類型是無符號(hào)的類型,這種無符號(hào)也體現(xiàn)在在其轉(zhuǎn)換成int類型時(shí),也就是說,char類型在擴(kuò)展時(shí),也是按無符號(hào)的方式擴(kuò)展,擴(kuò)展位填0。我們來看一個(gè)例子:
public static void main(String[] args) {
short s = -5;
char c = (char)s;
System.out.println(c==s); //false
System.out.println("(int)c = "+(int)c); //轉(zhuǎn)換成int類型,值為65531
System.out.println("(short)c = "+(short)c); //-5
System.out.println("(int)s = "+(int)s);//-5
}
運(yùn)行結(jié)果:
false
(int)c?=?65531
(short)c?=?-5
(int)s?=?-5
從上面的結(jié)果發(fā)現(xiàn),char類型的c 與 short類s其實(shí)存儲(chǔ)字節(jié)碼內(nèi)容是一樣的,但由于前者是無符號(hào),所以擴(kuò)展成int類型的結(jié)果是 65531,而不是 -5。運(yùn)算符==比較的就是他們擴(kuò)展成int類型的值,所以為fasle。
對(duì)char類型的類型轉(zhuǎn)換,可以總結(jié)成以下幾點(diǎn):
- char類型與byte、short的相互轉(zhuǎn)換,都需要顯式地強(qiáng)類型制轉(zhuǎn)換。
- 對(duì)于數(shù)值是負(fù)數(shù)的,都需要進(jìn)行顯式地強(qiáng)制類型轉(zhuǎn)換,特別是在整形字面常量的隱式轉(zhuǎn)換中。
- char類型轉(zhuǎn)換成int、long類型是符合 小類型轉(zhuǎn)大類型的規(guī)則,即無需要強(qiáng)制類型轉(zhuǎn)換。
4. 運(yùn)算結(jié)果的類型
在Java中,一個(gè)運(yùn)算結(jié)果的類型是與表達(dá)式中類型最高的相等,如:
char cc = 5;
float dd = 0.6f+cc;//最高類型是float,運(yùn)算結(jié)果是float
float ee = (float) (0.6d+cc);//最高類型是double,運(yùn)算結(jié)果也是double
int aa = 5+cc;//最高類型是int,運(yùn)算結(jié)果也為int
但是,對(duì)于最高類型是byte、short、char的運(yùn)算來說,則運(yùn)行結(jié)果卻不是最高類型,而是int類型??聪旅娴睦樱琧、d運(yùn)算的最高類型都是char,但運(yùn)算結(jié)果卻是int,所以需要強(qiáng)制類型轉(zhuǎn)換。
byte b = 2;
char a = 5;
char c = (char) (a+b);//byte+char,運(yùn)算結(jié)果的類型為int,需要強(qiáng)制類型轉(zhuǎn)換
int e = a+b;//編譯通過,不需要強(qiáng)制類型轉(zhuǎn)換,可以證明是int
char d = (char) (a+c);//char+char,
short s1 = 5;
short s2 = 6;
short s3 =(short)s1+s2;
綜上所述,java的運(yùn)算結(jié)果的類型有兩個(gè)性質(zhì):
- 運(yùn)算結(jié)果的類型必須是int類型或int類型以上。
- 最高類型低于int類型的,運(yùn)算結(jié)果都為int類型。否則,運(yùn)算結(jié)果與表達(dá)式中最高類型一致。
三、浮點(diǎn)數(shù)類型
1. 浮點(diǎn)類型的介紹
我們都知道,long類型轉(zhuǎn)換成float類型是不需要強(qiáng)制類型轉(zhuǎn)換的,也就是說相對(duì)于flaot類型,long類型是小類型,存儲(chǔ)的范圍要更小。然而flaot只占了4個(gè)字節(jié),而long卻占了8個(gè)字節(jié),long類型的存儲(chǔ)空間要比float類型大。這究竟是怎么一回事,我們接下來將細(xì)細(xì)分析。
浮點(diǎn)數(shù)使用 IEEE(電氣和電子工程師協(xié)會(huì))格式。 浮點(diǎn)數(shù)類型使用 符號(hào)位、指數(shù)、有效位數(shù)(尾數(shù))來表示。要注意一下,尾數(shù)的最高
在java中,float 和 double 的結(jié)構(gòu)如下:
|類 型|符 號(hào) 位|指 數(shù) 域|有效位域|
|-|-|-|
|float|1位|8位|23位|
|double|1位 |11位|52位|
符號(hào)位: 0為正,1為負(fù);
指數(shù)域: 無符號(hào)的,float的偏移量為127(即float的指數(shù)范圍是-126~127,),double
有效位域: 無符號(hào)的;
2. 浮點(diǎn)類型的兩個(gè)需要注意的地方
1)存儲(chǔ)的小數(shù)的數(shù)值可能是模糊值
public static void main(String[] args) {
double d1 = 0.1;
double d2 = 0.2;
System.out.println(d1+d2 == 0.3);
System.out.println(d1+d2);
}
運(yùn)行結(jié)果:
false
0.30000000000000004
上述的運(yùn)算結(jié)果并不是錯(cuò)誤。這是因?yàn)闊o法用二進(jìn)制來準(zhǔn)確地存儲(chǔ)的0.3,這是一個(gè)無限循環(huán)的值,與10進(jìn)制的1/3很相似。不只是0.3,很多小數(shù)都是無法準(zhǔn)確地用浮點(diǎn)型表示,其實(shí)這是由 小數(shù)的十進(jìn)制轉(zhuǎn)成二進(jìn)制的算法所決定的,十進(jìn)制的小數(shù)要不斷乘2,知道最后的結(jié)果為整數(shù)才是最后的二進(jìn)制值,但這有可能怎么也得不到整數(shù),所以最后得到的結(jié)果可能是一個(gè) 無限值 ,浮點(diǎn)型就無法表示了
但是對(duì)于 整數(shù) 來說,在浮點(diǎn)數(shù)的有效范圍內(nèi),則都是精確的。同樣,也是由于轉(zhuǎn)換算法:十進(jìn)制的整數(shù)轉(zhuǎn)成二進(jìn)制的算法是不斷對(duì)2求余數(shù),所以 不會(huì)存在無限值的情況;
2)浮點(diǎn)數(shù)的有效位及精度
浮點(diǎn)型所能表示的有效位是有限的,所以哪怕是整數(shù),只要超出有效位數(shù),也只能存儲(chǔ)相似值,也就是該數(shù)值的最低有效位將會(huì)丟失,從而造精度丟失。
??float類型的二進(jìn)制有效位是24位,對(duì)應(yīng)十進(jìn)制的7 ~ 8位數(shù)字;double類型的二進(jìn)制53位,對(duì)應(yīng)十進(jìn)制的10 ~ 11位數(shù)字。
double、float類型 所能表示的范圍比int、long類型表示的范圍要廣,也浮點(diǎn)類型屬于大類型。但是,并不能完美地表整形,浮點(diǎn)類型的精度丟失會(huì)造成一些問題。
public static void main(String[] args) {
int a = 3000000;
int b = 30000000;
float f1 = a;
float f2 = b;
System.out.println("3000000==3000001 "+(f1==f1+1));
System.out.println("30000000==30000001 "+(f2==f2+1));
System.out.println("3000000的有效二進(jìn)制位數(shù):"+ Integer.toBinaryString(a).length());
System.out.println("30000000的有效二進(jìn)制位數(shù):"+ Integer.toBinaryString(b).length());
}
運(yùn)行結(jié)果:
3000000 == 3000001 ?false
30000000 == 30000001 ?true
3000000的有效二進(jìn)制位數(shù):?22
30000000的有效二進(jìn)制位數(shù):?25
上面的例子很好體現(xiàn)了精度丟失所帶來的后果:30000000==30000001 的比較居然為true了。而造成這種結(jié)果的原因就是 30000000的有效二進(jìn)制位數(shù)是25位,超出了float所能表示的有效位24位,最后一位就被舍去,所以就造成在剛加的1也被舍去,因此30000000的加一操作前后的浮點(diǎn)型表示是一樣的。
當(dāng)然,并不是超出浮點(diǎn)型的有效位就不能精確表示,其實(shí),主要看的是最高有效位與最低非0有效位之間的 “間隙”,如果間隙的在浮點(diǎn)型的有效位數(shù)內(nèi),自然可以精確表示,因?yàn)樯崛サ牡陀行欢际?,自然就無所謂了。如果上面的例子的浮點(diǎn)型用的是double就不會(huì)丟失精度了,因?yàn)閐ouble的精度是52位。
3)解決浮點(diǎn)型精度丟失的問題
浮點(diǎn)型帶來精度丟失的問題是很讓人頭痛的,所以一般情況下,在程序中是不會(huì)使用float、double來存儲(chǔ)比較大的數(shù)據(jù)。而商業(yè)計(jì)算往往要求結(jié)果精確?!禘ffactive Java》書中有一句話:
float和double類型的主要設(shè)計(jì)目標(biāo)是為了科學(xué)計(jì)算和工程計(jì)算
JDK為此提供了兩個(gè)高精度的大數(shù)操作類給我們:BigInteger、BigDecimal。
作者:jinggod
出處:http://www.cnblogs.com/jinggod/p/8424583.html
最后,給大家分享我收藏的幾個(gè)不錯(cuò)的 github 項(xiàng)目,內(nèi)容都還是不錯(cuò)的,如果覺得有幫助,可以順便給個(gè) star。
- 計(jì)算機(jī)專業(yè)學(xué)生必須要啃的書籍推薦: https://github.com/hello-go-maker/cs-books
- Java 實(shí)戰(zhàn)項(xiàng)目推薦: https://github.com/hello-go-maker/Java-project
- 推薦一些很不錯(cuò)的計(jì)算機(jī)學(xué)習(xí)教程,包括:數(shù)據(jù)結(jié)構(gòu)、算法、計(jì)算機(jī)網(wǎng)絡(luò)、操作系統(tǒng)、Java(spring、springmvc、springboot、springcloud),也包括多個(gè)企業(yè)級(jí)實(shí)戰(zhàn)項(xiàng)目: https://github.com/hello-go-maker/cs-learn-source
- Java面試+Java后端技術(shù)學(xué)習(xí)指南】:一份通向理想互聯(lián)網(wǎng)公司的面試指南,包括 Java,技術(shù)面試必備基礎(chǔ)知識(shí)、Leetcode、計(jì)算機(jī)操作系統(tǒng)、計(jì)算機(jī)網(wǎng)絡(luò)、系統(tǒng)設(shè)計(jì)、分布式、數(shù)據(jù)庫(MySQL、Redis)、Java 項(xiàng)目實(shí)戰(zhàn)等: https://github.com/hello-java-maker/JavaInterview