JDK1.8源碼(二)——java.lang.Integer 類


  上一篇博客我們介紹了 java.lang 包下的 Object 類,那么本篇博客接着介紹該包下的另一個類 Integer。在前面 淺談 Integer 類 博客中我們主要介紹了 Integer 類 和 int 基本數據類型的關系,本篇博客是從源碼層次詳細介紹 Integer 的實現。

1、Integer 的聲明

public final class Integer extends Number implements Comparable<Integer>{}

  Integer 是用 final 聲明的常量類,不能被任何類所繼承。並且 Integer 類繼承了 Number 類和實現了 Comparable 接口。 Number 類是一個抽象類,8中基本數據類型的包裝類除了Character 和 Boolean 沒有繼承該類外,剩下的都繼承了 Number 類,該類的方法用於各種數據類型的轉換。Comparable 接口就一個  compareTo 方法,用於元素之間的大小比較,下面會對這些方法詳細展開介紹。

2、Integer 的主要屬性

  

  

  int 類型在 Java 中是占據 4 個字節,所以其可以表示大小的范圍是 -2 31——2 31 -1即 -2147483648——2147483647,我們在用 int 表示數值時一定不要超出這個范圍了。

3、構造方法 Integer(int)    Integer(String)

  對於第一個構造方法 Integer(int),源碼如下,這沒什么好說的。

1     public Integer(int var1) {
2         this.value = var1;
3     }
View Code

  對於第二個構造方法 Integer(String) 就是將我們輸入的字符串數據轉換成整型數據。

  首先我們必須要知道能轉換成整數的字符串必須分為兩個部分:第一位必須是"+"或者"-",剩下的必須是 0-9 和 a-z 字符

 1 public Integer(String s) throws NumberFormatException {
 2     this.value = parseInt(s, 10);//首先調用parseInt(s,10)方法,其中s表示我們需要轉換的字符串,10表示以十進制輸出,默認也是10進制
 3 }
 4 
 5 public static int parseInt(String s, int radix) throws NumberFormatException{
 6     //如果轉換的字符串如果為null,直接拋出空指針異常
 7     if (s == null) {
 8         throw new NumberFormatException("null");
 9     }
10     //如果轉換的radix(默認是10)<2 則拋出數字格式異常,因為進制最小是 2 進制
11     if (radix < Character.MIN_RADIX) {
12         throw new NumberFormatException("radix " + radix +
13                                         " less than Character.MIN_RADIX");
14     }
15     //如果轉換的radix(默認是10)>36 則拋出數字格式異常,因為0到9一共10位,a到z一共26位,所以一共36位
16     //也就是最高只能有36進制數
17     if (radix > Character.MAX_RADIX) {
18         throw new NumberFormatException("radix " + radix +
19                                         " greater than Character.MAX_RADIX");
20     }
21     int result = 0;
22     boolean negative = false;
23     int i = 0, len = s.length();//len是待轉換字符串的長度
24     int limit = -Integer.MAX_VALUE;//limit = -2147483647
25     int multmin;
26     int digit;
27     //如果待轉換字符串長度大於 0 
28     if (len > 0) {
29         char firstChar = s.charAt(0);//獲取待轉換字符串的第一個字符
30         //這里主要用來判斷第一個字符是"+"或者"-",因為這兩個字符的 ASCII碼都小於字符'0'
31         if (firstChar < '0') {  
32             if (firstChar == '-') {//如果第一個字符是'-'
33                 negative = true;
34                 limit = Integer.MIN_VALUE;
35             } else if (firstChar != '+')//如果第一個字符是不是 '+',直接拋出異常
36                 throw NumberFormatException.forInputString(s);
37 
38             if (len == 1) //待轉換字符長度是1,不能是單獨的"+"或者"-",否則拋出異常 
39                 throw NumberFormatException.forInputString(s);
40             i++;
41         }
42         multmin = limit / radix;
43         //通過不斷循環,將字符串除掉第一個字符之后,根據進制不斷相乘在相加得到一個正整數
44         //比如 parseInt("2abc",16) = 2*16的3次方+10*16的2次方+11*16+12*1 
45         //parseInt("123",10) = 1*10的2次方+2*10+3*1 
46         while (i < len) {
47             digit = Character.digit(s.charAt(i++),radix);
48             if (digit < 0) {
49                 throw NumberFormatException.forInputString(s);
50             }
51             if (result < multmin) {
52                 throw NumberFormatException.forInputString(s);
53             }
54             result *= radix;
55             if (result < limit + digit) {
56                 throw NumberFormatException.forInputString(s);
57             }
58             result -= digit;
59         }
60     } else {//如果待轉換字符串長度小於等於0,直接拋出異常
61         throw NumberFormatException.forInputString(s);
62     }
63     //根據第一個字符得到的正負號,在結果前面加上符號
64     return negative ? result : -result;
65 }
View Code

 4、toString()  toString(int i)   toString(int i, int radix)

  這三個方法重載,能返回一個整型數據所表示的字符串形式,其中最后一個方法 toString(int,int) 第二個參數是表示的進制數。

public String toString() {
    return toString(value);
}

public static String toString(int i) {
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}
View Code

  toString(int) 方法內部調用了 stringSize() 和 getChars() 方法,stringSize() 它是用來計算參數 i 的位數也就是轉成字符串之后的字符串的長度,內部結合一個已經初始化好的int類型的數組sizeTable來完成這個計算。

    final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };

    // Requires positive x
    static int stringSize(int x) {
        for (int i=0; ; i++)
            if (x <= sizeTable[i])
                return i+1;
    }
View Code

  實現的形式很巧妙。注意負數包含符號位,所以對於負數的位數是 stringSize(-i) + 1。

  再看 getChars 方法:

 1    static void getChars(int i, int index, char[] buf) {
 2         int q, r;
 3         int charPos = index;
 4         char sign = 0;
 5 
 6         if (i < 0) {
 7             sign = '-';
 8             i = -i;
 9         }
10 
11         // Generate two digits per iteration
12         while (i >= 65536) {
13             q = i / 100;
14         // really: r = i - (q * 100);
15             r = i - ((q << 6) + (q << 5) + (q << 2));
16             i = q;
17             buf [--charPos] = DigitOnes[r];
18             buf [--charPos] = DigitTens[r];
19         }
20 
21         // Fall thru to fast mode for smaller numbers
22         // assert(i <= 65536, i);
23         for (;;) {
24             q = (i * 52429) >>> (16+3);
25             r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
26             buf [--charPos] = digits [r];
27             i = q;
28             if (i == 0) break;
29         }
30         if (sign != 0) {
31             buf [--charPos] = sign;
32         }
33     }
View Code

  i:被初始化的數字,

  index:這個數字的長度(包含了負數的符號“-”),

  buf:字符串的容器-一個char型數組。

  第一個if判斷,如果i<0,sign記下它的符號“-”,同時將i轉成整數。下面所有的操作也就只針對整數了,最后在判斷sign如果不等於零將 sign 你的值放在char數組的首位buf [--charPos] = sign;。  

5、自動拆箱和裝箱

  自動拆箱和自動裝箱是 JDK1.5 以后才有的功能,也就是java當中眾多的語法糖之一,它的執行是在編譯期,會根據代碼的語法,在生成class文件的時候,決定是否進行拆箱和裝箱動作。

  ①、自動裝箱

  我們知道一般創建一個類的對象需要通過 new 關鍵字,比如:

Object obj = new Object();

  但是實際上,對於 Integer 類,我們卻可以直接這樣使用:

Integer a = 128;

  為什么可以這樣,通過反編譯工具,我們可以看到,生成的class文件是:

Integer a = Integer.valueOf(128);

  我們可以看看 valueOf() 方法

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

  其實最后返回的也是通過new Integer() 產生的對象,但是這里要注意前面的一段代碼,當i的值 -128 <= i <= 127 返回的是緩存類中的對象,並沒有重新創建一個新的對象,這在通過 equals 進行比較的時候我們要注意。

  這就是基本數據類型的自動裝箱,128是基本數據類型,然后被解析成Integer類。

  ②、自動拆箱

  我們將 Integer 類表示的數據賦值給基本數據類型int,就執行了自動拆箱。

1 Integer a = new Integer(128);
2 int m = a;

  反編譯生成的class文件:

1 Integer a = new Integer(128);
2 int m = a.intValue();

  簡單來講:自動裝箱就是Integer.valueOf(int i);自動拆箱就是 i.intValue();關於拆箱和裝箱的詳細介紹可以看我這篇博客

6、equals(Object obj)方法

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

  這個方法很簡單,先通過 instanceof 關鍵字判斷兩個比較對象的關系,然后將對象強轉為 Integer,在通過自動拆箱,轉換成兩個基本數據類 int,然后通過 == 比較。

7、hashCode() 方法

1     public int hashCode() {
2         return value;
3     }

  Integer 類的hashCode 方法也比較簡單,直接返回其 int 類型的數據。

8、parseInt(String s) 和  parseInt(String s, int radix) 方法

  前面通過 toString(int i) 可以將整型數據轉換成字符串類型輸出,這里通過 parseInt(String s) 能將字符串轉換成整型輸出。

  這兩個方法我們在介紹 構造函數 Integer(String s) 時已經詳細講解了。

9、compareTo(Integer anotherInteger) 和 compare(int x, int y) 方法

1     public int compareTo(Integer anotherInteger) {
2         return compare(this.value, anotherInteger.value);
3     }
View Code

  compareTo 方法內部直接調用 compare 方法:

1     public static int compare(int x, int y) {
2         return (x < y) ? -1 : ((x == y) ? 0 : 1);
3     }
View Code

  如果 x < y 返回 -1

  如果 x == y 返回 0

  如果 x > y 返回 1

1 System.out.println(Integer.compare(1, 2));//-1
2 System.out.println(Integer.compare(1, 1));//0
3 System.out.println(Integer.compare(1, 0));//1
View Code

  那么基本上 Integer 類的主要方法就介紹這么多了,后面如果有比較重要的,會再進行更新。

 

參考文檔:https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM