1. 程式人生 > >Integer源碼分析

Integer源碼分析

prim nbsp ray 比較 type 動態 float 解釋 not

類定義


public final class Integer extends Number implements Comparable<Integer>

從類定義中我們可以知道以下幾點:

  • Integer類不能被繼承
  • Integer類實現了Comparable接口,所以可以用compareTo進行比較並且Integer對象只能和Integer類型的對象進行比較,不能和其他類型比較
  • Integer繼承了Number類,所以該類可以調用longValue、floatValue、doubleValue等系列方法返回對應的類型的值。

屬性


一、私有屬性

Integer類中定義了以下幾個私有屬性:

private final int value;
private static final long serialVersionUID = 1360826667806852920L;

  • serialVersionUID和序列化有關
  • value屬性就是Integer對象中真正保存int值的。

當我們使用new Integer(10)創建一個Integer對象的時候,就會用以下形式給value賦值。

public Integer(int value) {
    this.value = value;
}

這裏我們討論一下Interger對象的可變性。從value的定義形式中可以看出value被定義成final類型。也就說明,一旦一個Integer對象被初始化之後,就無法再改變value的值。那麽這裏就深入討論一下以下代碼的邏輯:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i = new Integer(10);
        i = 5;
    }
}

在以上代碼中,首先調用構造函數new一個Integer對象,給私有屬性value賦值,這時value=10,接下來使用i=5的形式試圖改變i的值。有一點開發經驗的同學都知道,這個時候如果使用變量i,那麽它的值一定是5,那麽i=5這個賦值操作到底做了什麽呢?到底是如何改變i的值的呢?是改變了原有對象i中value的值還是重新創建了一個新的Integer對象呢?

我們將上面的代碼進行反編譯,反編譯之後的代碼如下:

public class IntegerTest
{

    public IntegerTest()
    {
    }

    public static void main(String args[])
    {
        Integer i = new Integer(10);
        i = Integer.valueOf(5);
    }
}

通過看反編譯之後的代碼我們發現,編譯器會把i=5轉成i = Integer.valueOf(5);這裏先直接給出結論,i=5操作並沒有改變使用Integer i = new Integer(10);創建出來的i中的value屬性的值。要麽是直接返回一個已有對象,要麽新建一個對象。這裏的具體實現細節在後面講解valueOf方法的時候給出。

二、公共屬性

//值為 (-(2的31次方)) 的常量,它表示 int 類型能夠表示的最小值。
public static final int   MIN_VALUE = 0x80000000;
//值為 ((2的31次方)-1) 的常量,它表示 int 類型能夠表示的最大值。
public static final int   MAX_VALUE = 0x7fffffff;   
//表示基本類型 int 的 Class 實例。
public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
//用來以二進制補碼形式表示 int 值的比特位數。
public static final int SIZE = 32;
//用來以二進制補碼形式表示 int 值的字節數。1.8以後才有
public static final int BYTES = SIZE / Byte.SIZE;

以上屬性可直接使用,因為他們已經定義成publis static fianl能用的時候盡量使用他們,這樣不僅能使代碼有很好的可讀性,也能提高性能節省資源。

方法


構造方法

Integer提供了兩個構造方法:

//構造一個新分配的 Integer 對象,它表示指定的 int 值。
public Integer(int value) {
    this.value = value;
}

//構造一個新分配的 Integer 對象,它表示 String 參數所指示的 int 值。
public Integer(String s) throws NumberFormatException {
    this.value = parseInt(s, 10);
}

從構造方法中我們可以知道,初始化一個Integer對象的時候只能創建一個十進制的整數。

Integer valueOf(int i)方法

前面說到Integer中私有屬性value的時候提到

Integer i = new Integer(10);
i = 5;

其中i=5操作時,編譯器會轉成i = Integer.valueOf(5);執行。那麽這裏就解釋一下valueOf(int i)方法是如何給變量賦值的。

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

以上是valueOf方法的實現細節。通常情況下,IntegerCache.low=-128,IntegerCache.high=127(除非顯示聲明java.lang.Integer.IntegerCache.high的值),Integer中有一段動態代碼塊,該部分內容會在Integer類被加載的時候就執行。

static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

也就是說,當Integer被加載時,就新建了-128到127的所有數字並存放在Integer數組cache中。

再回到valueOf代碼,可以得出結論。當調用valueOf方法(包括後面會提到的重載的參數類型包含String的valueOf方法)時,如果參數的值在-127到128之間,則直接從緩存中返回一個已經存在的對象。如果參數的值不在這個範圍內,則new一個Integer對象返回。

所以,當把一個int變量轉成Integer的時候(或者新建一個Integer的時候),建議使用valueOf方法來代替構造函數。或者直接使用Integer i = 100;編譯器會轉成Integer s = Integer.valueOf(100);

String轉成Integer(int)的方法

Integer getInteger(String nm)
Integer getInteger(String nm, int val)
Integer getInteger(String nm, Integer val)
Integer decode(String nm)
Integer valueOf(String s)
Integer valueOf(String s, int radix)
int parseUnsignedInt(String s)
int parseUnsignedInt(String s, int radix)
int parseInt(String s)
int parseInt(String s, int radix)

以上所有方法都能實現將String類型的值轉成Integer(int)類型(如果 String 不包含可解析整數將拋出NumberFormatException)

可以說,所有將String轉成Integer的方法都是基於parseInt方法實現的。簡單看一下以上部分方法的調用棧。

getInteger(String nm) ---> getInteger(nm, null);--->Integer.decode()--->Integer.valueOf()--->parseInt()

getInteger

確定具有指定名稱的系統屬性的整數值。 第一個參數被視為系統屬性的名稱。通過 System.getProperty(java.lang.String) 方法可以訪問系統屬性。然後,將該屬性的字符串值解釋為一個整數值,並返回表示該值的 Integer 對象。使用 getProperty 的定義可以找到可能出現的數字格式的詳細信息。其中參數nm應該在System的props中可以找到。這個方法在日常編碼中很好是用到。在代碼中可以用以下形式使用該方法:

Properties props = System.getProperties();
props.put("test.key","10000");
Integer i = Integer.getInteger("test.key");
System.out.println(i);
//輸出 10000

總結


  • 將int轉換Integet時 使用valueOf(int i)方法代替new Integer() 或者使用Integer i = 100

來自:http://www.hollischuang.com/archives/1058

Integer源碼分析