程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> 達內金牌講師唐亮Java語言細節(下)

達內金牌講師唐亮Java語言細節(下)

編輯:JAVA編程入門知識
8,拓寬數值類型會造成精度丟失嗎?
  Java語言的8種基本數據類型中7種都可以看作是數值類型,我們知道對於數值類型的轉換有一個規律:從窄范圍轉化成寬范圍能夠自動類型轉換,反之則必須強制轉換。請看下圖:P=I85C
  byte-->short-->int-->long-->float-->double%<
  char-->int"G
  我們把順箭頭方向的轉化叫做拓寬類型,逆箭頭方向的轉化叫做窄化類型。一般我們認為因為順箭頭方向的轉化不會有數據和精度的丟失,所以Java語言答應自動轉化,而逆箭頭方向的轉化可能會造成數據和精度的丟失,所以Java語言要求程序員在程序中明確這種轉化,也就是強制轉換。那麼拓寬類型就一定不會造成數據和精度丟失嗎?請看下面代碼:hc/N@
  int i=2000000000;n
  int num=0;?H=
  for(float f=i;f   num++;.}Q}1
  }&copy;達內IT技術論壇—中國人學Java、學C++、學C#/.Net、學軟件、學IT的地方 -- 達內科技論壇  ^n{P]W
  System.out.println(num);=u
  請考察以上代碼輸出多少?C/q+
  假如你回答50 ,那麼請運行一下,結果會讓你大吃一驚!沒錯,輸出結果是0,難道這個循環根本就沒有執行哪怕一次?確實如此,假如你還不死心,我帶你你看一個更詫異的現象,運行以下代碼,看輸出什麼?~
  int i=2000000000;9
  float f1=i;yW
  float f2=i+50;g
  System.out.println(f1==f2);d
  哈哈,你快要不相信你的眼睛了,結果竟然是true;難道f1和f2是相等的嗎?是的,就是這樣,這也就能解釋為什麼上一段代碼輸出的結果是0,而不是50了。那為什麼會這樣呢?要害原因在於你將int值自動提升為float時發生了數據精度的丟失,i的初始值是2000000000,這個值非常接近Integer.MAX_value,因此需要用31位來精確表示,而float只能提供24位數據的精度(另外8位是存儲位權,見IEEE745浮點數存儲規則)。所以在這種自動轉化的過程中,系統會將31位數據的前24位保留下來,而捨棄掉最右邊的7位,所以不管是2000000000還是2000000050,捨棄掉最右邊7位後得到的值是一樣的。這就是為什麼f1==f2的原因了。IwY'q
  類似的這種數值拓寬類型的過程中會造成精度丟失的還有兩種情況,那就是long轉化成float和long轉化成double,所以在使用的時候一定要小心。
  
  9,i=i+1和i+=1完全等價嗎?
  可能有很多程序員認為i+=1只是i=i+1的簡寫方式,其實不然,它們一個使用簡單賦值運算,一個使用復合賦值運算,而簡單賦值運算和復合賦值運算的最大差別就在於:復合賦值運算符會自動地將運算結果轉型為其左操作數的類型。看看以下的兩種寫法,你就知道它們的差別在哪兒了:1wa
  (1) byte i=5;Zvt^o
  i+=1;`d.
  (2) byte i=5;F1p
  i=i+1;J&
  第一種寫法編譯沒問題,而第二種寫法卻編譯通不過。原因就在於,當使用復合賦值運算符進行操作時,即使右邊算出的結果是int類型,系統也會將其值轉化為左邊的byte類型,而使用簡單賦值運算時沒有這樣的優待,系統會認為將i+1的值賦給i是將int類型賦給byte,所以要求強制轉換。理解了這一點後,我們再來看一個例子:@4DiYK
  byte b=120;e-
  b+=20;6(dTP
  System.out.println("b="+b);+e6_+
  說到這裡你應該明白了,上例中輸出b的值不是140,而是-116。因為120+20的值已經超出了一個byte表示的范圍,而當我們使用復合賦值運算時系統會自動作類型的轉化,將140強轉成byte,所以得到是-116。由此可見,在使用復合賦值運算符時還得小心,因為這種類型轉換是在不知不覺中進行的,所以得到的結果就有可能和你的預想不一樣。
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved