1. 程式人生 > >Java基礎之資料比較Integer、Short、int、short

Java基礎之資料比較Integer、Short、int、short

基礎很重要,基礎很重要,基礎很重要。重要的事情說三遍。

今天聊一聊Java的資料比較,這個範圍比較大,基礎型別的比較、引用型別的比較。

前提:

1、Java和c#都提供自動裝箱和自動拆箱操作,何為自動裝箱,簡單點說就是將值型別轉換成為引用型別,自動拆箱就是將引用型別轉換成為值型別。並且我們還經常被教導,要避免自動的裝箱和拆箱操作,因為這個會影響效能。

2、比較常用的運算子是==,equals。

下面分幾類來說明資料的比較,

引用型別之間的比較:Integer與Integer之間的比較、Boolean與Boolean之間的比較、Integer與Boolean之間的比較

值型別之間的比較:int與int之間的比較、int與bool之間的比較

值型別與引用型別之間的比較:Integer與int之間的比較、Boolean與bool之間的比較

開工

引用型別之間的比較--Integer與Integer之間的比較

簡單說明一下,Integer是引用型別,代表的是整形數字

上程式碼

public static void main(String[] args) throws Exception {
        Integer integer = new Integer(0);
        Integer mInteger = Integer.valueOf(0);
        Integer sInteger = 0;

        System.out.println(integer == mInteger);//false
        System.out.println(integer == sInteger);//false
        System.out.println(mInteger == sInteger);//true

        System.out.println(memoryAddress(integer));
        System.out.println(memoryAddress(mInteger));
        System.out.println(memoryAddress(sInteger));

    }

    private static int memoryAddress(Object object) {
        // 記憶體地址會有所不同
        return System.identityHashCode(object);
    }

執行結果:

分析:

1、執行結果和我們預想的不太一樣,引用型別是在堆上存放的,每個引用的地址應該都不相同。但是mInteger == sInteger  執行結果為true,並且mInteger ,sInteger的記憶體地址是相同的。

2、要分析這個原因,我們需要了解Java設計者為了效能而進行的一些努力,檢視Java原始碼,可以看到Integer的valueof方法裡面包含了一個快取:其中IntegerCache.low =-127,IntegerCache.high=128

@HotSpotIntrinsicCandidate
  public static Integer valueOf(int i) {
      if (i >= IntegerCache.low && i <= IntegerCache.high)
          return IntegerCache.cache[i + (-IntegerCache.low)];
      return new Integer(i);
  }

對於使用Integer.valueof()方法,如果數值是-127至128,那麼會使用快取物件,否則會new一個物件。

3、Integer sInteger = 0;  發生了什麼呢?自動裝箱,等價於Integer sInteger=Integer.valueOf(0)。通過這個,我們就可以得出比較等於true的原因了,都是從快取中讀取的物件,難怪記憶體地址會一致。

引用型別比較--Integer與Integer引用型別比較  使用equals

上程式碼:

public static void main(String[] args) throws Exception {
        Integer integer = new Integer(0);
        Integer mInteger = Integer.valueOf(0);
        Integer sInteger = 0;

        System.out.println(integer == mInteger);// false
        System.out.println(integer == sInteger);// false
        System.out.println(mInteger == sInteger);// true

        System.out.println(memoryAddress(integer));
        System.out.println(memoryAddress(mInteger));
        System.out.println(memoryAddress(sInteger));

        System.out.println(integer.equals(mInteger));//true
        System.out.println(integer.equals(sInteger));//true
        System.out.println(mInteger.equals(sInteger));//true

    }

    private static int memoryAddress(Object object) {
        // 記憶體地址會有所不同
        return System.identityHashCode(object);
    }

分析:使用equals比較,只要數值相同,那麼比較結果就是相同。檢視Java原始碼:

public boolean equals(Object obj) {
      if (obj instanceof Integer) {
          return value == ((Integer)obj).intValue();
      }
      return false;
  }

可以看到Integer的equals比較,其實比較的就是數值。

值型別之間的比較:int與int

上程式碼

int  m=0;
          int i=0;
          int s=0;
          System.out.println(m==i);//true
          //值型別是沒有equals方法
          //System.out.println(m.equals(i));

分析:對於int 的比較,無需多言,本來就是數值比較。

Integer與int的比較

Integer integer = new Integer(0);
        Integer mInteger = Integer.valueOf(0);
        Integer sInteger = 0;// 等價於Integer。valueof
        int i = 0;
        System.out.println(integer == i);//true
        System.out.println(mInteger == i);//true
        System.out.println(sInteger == i);//true
        System.out.println(integer.equals(i));//true
        System.out.println(mInteger.equals(i));//true
        System.out.println(sInteger.equals(i));//true

分析:

1、Integer型別與int型別通過==比較,Integer會自動拆箱,轉換成int數值進行比較

2、equals方法更是讀取對應的int數值進行比較。

因此引用型別與值型別之間的比較,使用equals與==都可以。

簡單總結:

1、引用型別之間的比較,由於存在-127至128之間的快取物件,因此使用== 進行比較存在風險。優先使用equals進行比較

2、引用型別與值型別進行比較,由於會自動拆箱,因此使用==和equals都可以正確得到結果

3、建議在實際編碼過程中,對數值的比較使用equals

深入總結:

不僅僅Integer,其他的基本型別也都存在快取,下面給出一個簡單圖表進行說明

基本型別 裝箱型別 取值範圍 是否快取 快取範圍
byte Byte -128~127 -128~127
short Short -2^15 ~ (2^15 - 1) -128~127
int Integer -2^31 ~ (2^31 - 1) -128~127

long

Long -2^63 ~ (2^63 - 1) -128~127
float Float --  
double Double

--

 
boolean Boolean true、false true、false
char Character \u0000 ~ \uffff \u0000 ~ \uffff

Java博大精深,要想深入,基礎必須要好,才能避免bug。

我們程式設計師的職責就是少寫bug,這才是我們一直學習的動力。