亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

java解惑你知多少(一)

系統 1783 0

溫馨提示:如需《java解惑你知多少》的朋友,請到第八節附錄下載,那里我提供了Word格式化的文檔,讀起來可能方便一些,如果你喜歡,請對我的工作給于支持,謝謝~!

?

另外,特此聲明:本系列內容來源于《JAVA解惑》一書,不是本人所獨創,此系列內容應該說是該書的一個精簡版,但內容含蓋90%左右,摘錄于此只是便于與大家共同分享,激起大家對Java基礎的興趣!我也是一位Java老菜鳥,搞了好幾年的Java了,現在回頭看這本書時,頗有感受——基礎才是永恒!不過如果大家有時間的話,還是去看看這本書,如果沒有太多的時間,可能直接看看我整理的這個精簡版本!

?

數值表達式

1.?奇偶判斷

不要使用 i % 2 == 1 來判斷是否是奇數,因為i為負奇數時不成立,請使用 i % 2 != 0 來判斷是否是奇數,或使用

高效式 (i & 1) != 0來判斷。

?

2.?小數精確計算

Java代碼 ? ? 收藏代碼
  1. System.out.println( 2.00 ?- 1.10 ); //0.8999999999999999 ??

?
上面的計算出的結果不是 0.9,而是一連串的小數。問題在于1.1這個數字不能被精確表示為一個double,因此它被表

示為最接近它的double值,該程序從2中減去的就是這個值,但這個計算的結果并不是最接近0.9的double值。


一般地說,問題在于并不是所有的小數都可以用二進制浮點數精確表示。


二進制浮點對于貨幣計算是非常不適合的,因為它不可能將1.0表示成10的其他任何負次冪。

?

解決問題的第一種方式是使用貨幣的最小單位(分)來表示:

Java代碼 ? ? 收藏代碼
  1. System.out.println( 200 - 110 ); //90 ??

?

第二種方式是使用BigDecimal,但一定要用BigDecimal(String)構造器,而千萬不要用BigDecimal(double)來構造(

也不能將float或double型轉換成String再來使用 BigDecimal(String) 來構造,因為在將float或double轉換成String

時精度已丟失)。例如new BigDecimal(0.1),它將返回一個BigDecimal,也即

0.1000000000000000055511151231257827021181583404541015625 ,正確使用BigDecimal,程序就可以打印出我們所期

望的結果0.9:

Java代碼 ? ? 收藏代碼
  1. System.out.println( new ?BigDecimal( "2.0" ).subtract( new ?BigDecimal( "1.10" ))); //?0.9 ??

?

另外,如果要比較兩個浮點數的大小,要使用BigDecimal的compareTo方法。

?

如果你還想更深入了解下,請參考《 Java中的浮點數剖析 》!

3.?int整數相乘溢出

我們計算一天中的微秒數:

Java代碼 ? ? 收藏代碼
  1. long ?microsPerDay?=? 24 ?*? 60 ?*? 60 ?*? 1000 ?*? 1000 ; //?正確結果應為:86400000000 ??
  2. System.out.println(microsPerDay); //?實際上為:500654080 ??

問題在于計算過程中溢出了。這個計算式完全是以int運算來執行的,并且只有在運算完成之后,其結果才被提升為

long,而此時已經太遲:計算已經溢出。

?

解決方法使計算表達式的第一個因子明確為long型,這樣可以強制表達式中所有的后續計算都用long運算來完成,這

樣結果就不會溢出:

Java代碼 ? ? 收藏代碼
  1. long ?microsPerDay?=?24L?*? 60 ?*? 60 ?*? 1000 ?*? 1000 ;??

?

4.?負的十六進制與八進制字面常量

“數字字面常量”的類型都是int型,而不管他們是幾進制,所以“2147483648”、“0x180000000(十六進制,共33

位,所以超過了整數的取值范圍)”字面常量是錯誤的,編譯時會報超過int的取值范圍了,所以要確定以long來表示

“2147483648L”、“0x180000000L”。

?

十進制字面常量只有一個特性,即所有的十進制字面常量都是正數,如果想寫一個負的十進制,則需要在正的十進制

字面常量前加上“-”即可。

?

十六進制或八進制字面常量可就不一定是正數或負數,是正還是負,則要根據當前情況看:如果十六進制和八進制字

面常量的最高位被設置成了1,那么它們就是負數:

Java代碼 ? ? 收藏代碼
  1. System.out.println( 0x80 ); //128? ??
  2. //0x81看作是int型,最高位(第32位)為0,所以是正數 ??
  3. System.out.println( 0x81 ); //129? ??
  4. System.out.println( 0x8001 ); //32769 ??
  5. System.out.println( 0x70000001 ); //1879048193? ??
  6. //字面量0x80000001為int型,最高位(第32位)為1,所以是負數 ??
  7. System.out.println( 0x80000001 ); //-2147483647 ??
  8. //字面量0x80000001L強制轉為long型,最高位(第64位)為0,所以是正數 ??
  9. System.out.println(0x80000001L); //2147483649 ??
  10. //最小int型 ??
  11. System.out.println( 0x80000000 ); //-2147483648 ??
  12. //只要超過32位,就需要在字面常量后加L強轉long,否則編譯時出錯 ??
  13. System.out.println(0x8000000000000000L); //-9223372036854775808 ??

從上面可以看出,十六進制的字面常量表示的是int型,如果超過32位,則需要在后面加“L”,否則編譯過不過。如

果為32,則為負int正數,超過32位,則為long型,但需明確指定為long。

?

Java代碼 ? ? 收藏代碼
  1. System.out.println(Long.toHexString(0x100000000L?+? 0xcafebabe )); //?cafebabe ??

結果為什么不是0x1cafebabe?該程序執行的加法是一個混合類型的計算:左操作數是long型,而右操作數是int類型

。為了執行該計算,Java將int類型的數值用拓寬原生類型轉換提升為long類型,然后對兩個long類型數值相加。因為

int是有符號的整數類型,所以這個轉換執行的是符號擴展。


這個加法的右操作數0xcafebabe為32位,將被提升為long類型的數值0xffffffffcafebabeL,之后這個數值加上了左操

作0x100000000L。當視為int類型時,經過符號擴展之后的右操作數的高32位是-1,而左操作數的第32位是1,兩個數

值相加得到了0:
? 0x 0xffffffffcafebabeL
+0x 0000000100000000L
-----------------------------
?0x 00000000cafebabeL

如果要得到正確的結果0x1cafebabe,則需在第二個操作數組后加上“L”明確看作是正的long型即可,此時相加時拓

展符號位就為0:

Java代碼 ? ? 收藏代碼
  1. System.out.println(Long.toHexString(0x100000000L?+?0xcafebabeL)); //?1cafebabe ??

?

5.?窄數字類型提升至寬類型時使用符號位擴展還是零擴展

Java代碼 ? ? 收藏代碼
  1. System.out.println(( int )( char )( byte )- 1 ); //?65535 ??

結果為什么是65535而不是-1?

?

窄的整型轉換成較寬的整型時符號擴展規則:如果最初的數值類型是有符號的,那么就執行符號擴展(即如果符號位

為1,則擴展為1,如果為零,則擴展為0);如果它是char,那么不管它將要被提升成什么類型,都執行零擴展。

?

了解上面的規則后,我們再來看看迷題:因為byte是有符號的類型,所以在將byte數值-1(二進制為:11111111)提

升到char時,會發生符號位擴展,又符號位為1,所以就補8個1,最后為16個1;然后從char到int的提升時,由于是

char型提升到其他類型,所以采用零擴展而不是符號擴展,結果int數值就成了65535。

?

如果將一個char數值c轉型為一個寬度更寬的類型時,只是以零來擴展,但如果清晰表達以零擴展的意圖,則可以考慮

使用一個位掩碼:

Java代碼 ? ? 收藏代碼
  1. int ?i?=?c?&? 0xffff ; //實質上等同于:int?i?=?c?; ??

?

如果將一個char數值c轉型為一個寬度更寬的整型,并且希望有符號擴展,那么就先將char轉型為一個short,它與

char上個具有同樣的寬度,但是它是有符號的:

Java代碼 ? ? 收藏代碼
  1. int ?i?=?( short )c;??

?

如果將一個byte數值b轉型為一個char,并且不希望有符號擴展,那么必須使用一個位掩碼來限制它:

Java代碼 ? ? 收藏代碼
  1. char ?c?=?( char )(b?&? 0xff ); //?char?c?=?(char)?b;為有符號擴展 ??

?
6.?((byte)0x90 == 0x90)?

答案是不等的,盡管外表看起來是成立的,但是它卻等于false。為了比較byte數值(byte)0x90和int數值0x90,Java

通過拓寬原生類型將byte提升為int,然后比較這兩個int數值。因為byte是一個有符號類型,所以這個轉換執行的是

符號擴展,將負的byte數值提升為了在數字上相等的int值(10010000?111111111111111111111111 10010000)。在本例中,該轉換將(byte)0x90提升為int數值-112,它不等于int數值的0x90,即+144。


解決辦法:使用一個屏蔽碼來消除符號擴展的影響,從而將byte轉型為int。

Java代碼 ? ? 收藏代碼
  1. (( byte ) 0x90 ?&? 0xff )==? 0x90 ??

?

7.?三元表達式(?:)

Java代碼 ? ? 收藏代碼
  1. char ?x?=? 'X' ;??
  2. int ?i?=? 0 ;??
  3. System.out.println( true ???x?:? 0 ); //?X ??
  4. System.out.println( false ???i?:?x); //?88 ??

?條件表達式結果類型的規則:
(1)?如果第二個和第三個操作數具有相同的類型,那么它就是條件表達式的類型。
(2)?如果一個操作的類型是T,T表示byte、short或char,而另一個操作數是一個int類型的“字面常量”,并且

它的值可以用類型T表示,那條件表達式的類型就是T。
(3)?否則,將對操作數類型進行提升,而條件表達式的類型就是第二個和第三個操作被提升之后的類型。

?

現來使用以上規則解上面的迷題,第一個表達式符合第二條規則:一個操作數的類型是char,另一個的類型是字面常

量為0的int型,但0可以表示成char,所以最終返回類型以char類型為準;第二個表達式符合第三條規則:因為i為int

型變量,而x又為char型變量,所以會先將x提升至int型,所以最后的結果類型為int型,但如果將i定義成final時,

則返回結果類型為char,則此時符合第二條規則,因為final類型的變量在編譯時就使用“字面常量0”來替換三元表

達式了:

Java代碼 ? ? 收藏代碼
  1. final ? int ?i?=? 0 ;??
  2. System.out.println( false ???i?:?x); //?X ??

?

在JDK1.4版本或之前,條件操作符 ?: 中,當第二個和延續三個操作數是引用類型時,條件操作符要求它們其中一個

必須是另一個的子類型,那怕它們有同一個父類也不行:

Java代碼 ? ? 收藏代碼
  1. public ? class ?T?{??
  2. ? public ? static ? void ?main(String[]?args)?{??
  3. ??System.out.println(f());??
  4. ?}??
  5. ? public ? static ?T?f()?{??
  6. ?? //?!!1.4不能編譯,但1.5可以 ??
  7. ?? //?!!return?true?new?T1():new?T2(); ??
  8. ?? return ? true ???(T)? new ?T1()?:? new ?T2(); //?T1 ??
  9. ?}??
  10. }??
  11. ??
  12. class ?T1? extends ?T?{??
  13. ? public ?String?toString()?{??
  14. ?? return ? "T1" ;??
  15. ?}??
  16. }??
  17. ??
  18. class ?T2? extends ?T?{??
  19. ? public ?String?toString()?{??
  20. ?? return ? "T2" ;??
  21. ?}??
  22. }??

?

在5.0或以上版本中,條件操作符在延續二個和第三個操作數是引用類型時總是合法的。其結果類型是這兩種類型的最

小公共超類。公共超類總是存在的,因為Object是每一個對象類型的超類型,上面的最小公共超類是T,所以能編譯。

java解惑你知多少(一)


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲男人的天堂久久无 | 一级女性全黄生活片免费 | 国产永久在线观看 | 日韩高清欧美精品亚洲 | 性做久久久久久久久男女 | 午夜精品久久久久久久99 | 久久一日本道色综合久久m 久久一色本道亚洲 | 国产午夜亚洲精品第一区 | 国产乱子伦一区二区三区 | 夜夜躁日日躁狠狠久久 | 国产永久免费高清动作片www | 日本高清专区一区二无线 | 亚洲一级生活片 | 国产精品区一区二区免费 | 一级成人毛片免费观看欧美 | 日本欧美高清视频 | avav网站| 久久免费观看视频 | 亚洲综合激情五月色播 | 亚欧在线免费观看 | 免费区欧美一级毛片 | 免费观看成人羞羞视频网站观看 | 国产激情一区二区三区四区 | 久久久精品影院 | 欧美三级中文字幕 | 久久综合伊人 | 欧美一级aa天码毛片 | 91av久久| 精品视频网 | 久久久久在线观看 | 国产日韩久久 | 久久精品视频9 | 亚洲精品无人区一区二区三区 | 国产亚洲欧美在在线人成 | 国产在热线精品视频国产一二 | 国产呦系列呦交 | 一区二区三区在线观看视频 | www九色| 久久久高清国产999尤物 | 99色吧| 久久成人国产精品二三区 |