==與equal的區別

1、java中的數據類型

  • 基本類型:如:int、short、long、float、double、boolean
  • 引用類型
  • null類型:這是一個非常特殊的類型

2、基本類型之間的比較

大家都知道基本之間的類型比較不能用equal,而是用==,那麼用==是怎麼比較大小的呢?我們就來探一個究竟。

在計算機中,所有儲存的東西都是用二進制來表示的,例如:01010101010101,那麼基本類型在計算機中肯定是用二進制表示的吧,但是數據儲存是有一定格式的,不同的類型數據的格式是不一樣的,下面介紹幾種數據類型的儲存格式。

  • boolean 類型

在java中,boolean是用一字節表示的,由於boolean 只有兩個值,即0和1,用二進制表示就是爲00000000和00000001

  • int類型

在java中,int是用32位來儲存的,而且是有符號的。下面就說一個例子:

比如說:100 在java中,表示爲:00000000000000000000000001100100  而-100在java中,表示爲:11111111111111111111111110011100

如果不知道把100和-100怎麼轉成這樣二進制的話,那你就得先百度一下了,先學學這個知識了,因爲我這裏是總結==而不是進制之間的轉換,在這裏就細說了。

現在我們已經把他們都轉化爲二進制了,這個時候可以開始比較了,在內存中,他們會一位一位地比較,很顯然,他們不相等。整數之間的比較非常簡單,接下來是float類型的比較了。

  • float類型

先明確float類型在計算機中是怎麼被存儲起來的,下面是介紹(下面這段介紹性文字是引用另外一位高人的):

根據國際標準IEEE 754,任意一個二進制浮點數V可以表示成下面的形式:

  V = (-1)^s×M×2^E
  (1)(-1)^s表示符號位,當s=0,V爲正數;當s=1,V爲負數。
  (2)M表示有效數字,大於等於1,小於2。
  (3)2^E表示指數位。
  舉例來說,十進制的5.0,寫成二進制是101.0,相當於1.01×2^2。那麼,按照上面V的格式,可以得出s=0,M=1.01,E=2。
  十進制的-5.0,寫成二進制是-101.0,相當於-1.01×2^2。那麼,s=1,M=1.01,E=2。
  IEEE 754規定,對於32位的浮點數,最高的1位是符號位s,接着的8位是指數E,剩下的23位爲有效數字M。
 
  對於64位的浮點數,最高的1位是符號位S,接着的11位是指數E,剩下的52位爲有效數字M。
 

5.
  IEEE 754對有效數字M和指數E,還有一些特別規定。
  前面說過,1≤M<2,也就是說,M可以寫成1.xxxxxx的形式,其中xxxxxx表示小數部分。IEEE 754規定,在計算機內部保存M時,默認這個數的第一位總是1,因此可以被捨去,只保存後面的xxxxxx部分。比如保存1.01的時候,只保存01,等到讀取的時候,再把第一位的1加上去。這樣做的目的,是節省1位有效數字。以32位浮點數爲例,留給M只有23位,將第一位的1捨去以後,等於可以保存24位有效數字。
  至於指數E,情況就比較複雜。
  首先,E爲一個無符號整數(unsigned int)。這意味着,如果E爲8位,它的取值範圍爲0~255;如果E爲11位,它的取值範圍爲0~2047。但是,我們知道,科學計數法中的E是可以出現負數的,所以IEEE 754規定,E的真實值必須再減去一箇中間數,對於8位的E,這個中間數是127;對於11位的E,這個中間數是1023。
  比如,2^10的E是10,所以保存成32位浮點數時,必須保存成10+127=137,即10001001。
  然後,指數E還可以再分成三種情況:
  (1)E不全爲0或不全爲1。這時,浮點數就採用上面的規則表示,即指數E的計算值減去127(或1023),得到真實值,再將有效數字M前加上第一位的1。
  (2)E全爲0。這時,浮點數的指數E等於1-127(或者1-1023),有效數字M不再加上第一位的1,而是還原爲0.xxxxxx的小數。這樣做是爲了表示±0,以及接近於0的很小的數字。
  (3)E全爲1。這時,如果有效數字M全爲0,表示±無窮大(正負取決於符號位s);如果有效數字M不全爲0,表示這個數不是一個數(NaN)。

說完原理以後,接下來我就舉一例子

1.00000000和1.000000001

按照上面的規則,1.00000000轉化爲 V = (-1)^s×M×2^E這種形式:1.0*2^0,轉化爲二進制就是:0 01111111 00000000000000000000000

而1.000000001轉化爲V = (-1)^s×M×2^E這種形式:1.0*2^0,轉化爲二進制就是:0 01111111 00000000000000000000000

按照這種情況對比,可以得出1.00000000與1.000000001是相等的,對他們就是相等的。但是如果是64bit的時候就是不是相等的,這個你可以試一試。

  • double類型

double類型的比較跟float類型的比較其實是一樣的,只不過是把精度提高了,用的是64位,比如說:1.00000000和1.000000001的比較

1.00000000轉化爲二進制爲0 01111111    0000000000000000000000000000000000000000000000000000

而1.000000001轉化爲二進制爲0 01111111111 0000000000000000000000000000010001001011100000101111

很顯然這兩個數字是不相等的。

在float類型的比較,我們會用Float.floatToIntbit(float value)這個函數來比較兩個浮點數的大小,那麼用Float.floatToInbit(float value)與用==來比較兩個浮點數有什麼不同呢?Float.floatToInbit(float value)的原理是怎麼樣的呢?

先介紹Float.floatToInbit(float value)的原理:

官方文檔是這樣說的:Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "single format" bit layout

舉個例子來說吧:

比如說:float a=1.00000000;  Float.floatToIntbit(a)=1065353216,這是怎麼來的呢?原來是這樣的,把1.00000000按照V = (-1)^s×M×2^E這個規則轉成二進制就是:0 01111111 00000000000000000000000,接着把這個二進制轉化爲整數就是:1065353216了。

用Float.floatToIntbit(float value)跟用==來比較兩個浮點數的大小有什麼不同呢?

對與一般的浮點數,用兩種方法都一樣。主要不同的地方就是比較特殊的數,

NaN、-0.0 、 0.0

用==來比較就是 NaN==NaN是false     -0.0==0.0是true

用Float.floatToIntbit()來比較就是  Float.floatToIntbit(NaN)==Float.floatToIntbit(NaN)是true,而Float.floatToIntbit(0.0)==Float.floatToIntbit(-0.0)是false這個得解釋一下,爲什麼會出現這樣的差別呢?

什麼是NaN:她是指not a number,不是一個數,比如說1.0/0.0是多少呢,我們定義這樣的數爲NaN。對於oo來說,這就是我們定義的一個對象,所以Float.floatToIntbit(NaN)==Float.floatToIntbit(NaN)就是true了,在這個函數裏面NaN是對應一個整數的,查看jdk源碼或者jdk文檔就知道了。從數學的角度來說:NaN==NaN是false,因爲不是一個數怎麼能跟不是一個數相等呢?0.0和-0.0的問題是比較好解析的,從數學的角度來說-0.0與0.0是相等的,但是 Float.floatToIntbit(-0.0)根據上面的規則就是2147483648  而Float.floatToIntbit(0.0)是0,所以很顯然不相等。詳情請看這裏

那麼我們在編程中,一般用哪一個來進行比較呢?是用==好呢?還是用Float.floatToIntbit()這個好呢?這個就要看具體情況了,我現在也不知道用他們的一般規則

double之間的比較這裏就不重複了,原理跟float一樣。

3、對象之間的比較

我們在做面試題目的時候經常會碰到下面這樣的情形

String a="hello"; 

String b="hello"; 

String c=new String("hello");

System.out.println(a==b);//true

System.out.println(a==c);//false

System.out.println(a.equal(c))//true

爲什麼會出現這樣的結果呢?

分析:這三個引用指向的的對象的內容都是相同的,從邏輯上面來說都是相等的。但是確實出現了上面的這種結果。那是因爲==比的是對象的地址,對於同一個常量來說,它的內存地址都是一樣的,而c是指向新開除來內存,所以a==c是false,而a.equal(b)比的是對象的內容,與對象所在的地址無關,所以a.equal(c)是true。

4、null類型之間的比較,

可以按照eclipse裏面自動生成的equal函數的比較方式。任何其他類型跟null比較都是不等的,null。equal(null)是無意義的。

總結:

1、基本類型之間的比較一般是用==,但是注意float和double類型的精度問題以及NaN、正無窮大、負無窮大、-0.0、0.0的比較問題

2、引用類型的比較一般是用equal,尤其是字符串,因爲==是指對象地址之間的比較,而對象地址之間的比較一般是無意義的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章