這篇博客我來整理下以Integer爲例整理下包裝類的源碼。首先來看一段代碼:
public class LinkinPark
{
public static void main(String[] args)
{
Integer a = 1;
Integer b = 1;
// 下行代碼輸出true
System.out.println(a == b);
Integer c = 128;
Integer d = 128;
// 下行代碼輸出false
System.out.println(c == d);
}
}
上面的結果輸出估計大家都很明白,前面的包裝類那篇博客中我也已經整理到了,Integer類中使用了享元模式,然後用了一個緩存,用來緩存-128到127的數字。
現在我們來從頭到尾研究下Integer類的源碼。
1),Integer類繼承Number類,關於Number類我後面會專門整理,實現了comparable接口。
public final class Integer extends Number implements Comparable<Integer>
{
/**
* 最小值:-2147483648
*/
@Native
public static final int MIN_VALUE = 0x80000000;
/**
* 最大值:2147483647
* 不好記住腫麼辦?2開頭的10位數字
*/
@Native
public static final int MAX_VALUE = 0x7fffffff;
/**
* 包裝類中的基本類型的值
*/
private final int value;
public Integer(int value)
{
this.value = value;
}
public Integer(String s) throws NumberFormatException
{
this.value = parseInt(s, 10);
}
/**
* 使用第二個參數指定的基數,將字符串參數解析爲有符號的整數。
*
* @param s 包含要解析的整數表示形式的 String
* @param radix 解析 s 時使用的基數,一般爲10,用來轉換數字
* @return 使用指定基數的字符串參數表示的整數
* @throws NumberFormatException
*/
public static int parseInt(String s, int radix) throws NumberFormatException
{
if (s == null)
{
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX)
{
throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX)
{
throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0)
{
char firstChar = s.charAt(0);
if (firstChar < '0')
{ // Possible leading "+" or "-"
if (firstChar == '-')
{
negative = true;
limit = Integer.MIN_VALUE;
}
else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len)
{
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++), radix);
if (digit < 0)
{
throw NumberFormatException.forInputString(s);
}
if (result < multmin)
{
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit)
{
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
}
else
{
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
// 以下提供幾個轉換值的方法
public byte byteValue()
{
return (byte) value;
}
public short shortValue()
{
return (short) value;
}
public int intValue()
{
return value;
}
public long longValue()
{
return (long) value;
}
public float floatValue()
{
return (float) value;
}
public double doubleValue()
{
return (double) value;
}
@Override
public int hashCode()
{
return Integer.hashCode(value);
}
public boolean equals(Object obj)
{
if (obj instanceof Integer)
{
return value == ((Integer) obj).intValue();
}
return false;
}
public static int compare(int x, int y)
{
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
public static int sum(int a, int b)
{
return a + b;
}
public static int max(int a, int b)
{
return Math.max(a, b);
}
public static int min(int a, int b)
{
return Math.min(a, b);
}
}
以上代碼比較簡單,我就不多做贅述啦。這裏重點來看下Integer類使用的緩存,源碼如下:
public final class Integer extends Number implements Comparable<Integer>
{
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache
{
static final int low = -128;
static final int high;
static final Integer cache[];
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;
}
private IntegerCache()
{
}
}
public static Integer valueOf(int i)
{
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
}
分析一下上面的代碼,在Integer的內部封裝一個私有的靜態內部類,然後在內部類中定義一個靜態cache數組,初始化數組將一定範圍的整數放到cache數組中,然後在調valueOf
方法的時候首先判斷範圍然後從緩存數組中去抓取數據,源碼還是比較簡單的。
緩存是一種非常優秀的設計模式,在Java,JavaEE平臺的很多地方都會通過緩存來提高系統的運行性能。簡單的說,如果你需要一臺電腦,那麼你就去買了一臺電腦,但你不可
能一直使用這臺電腦,你總會離開這臺電腦。在你離開電腦的這段時間內,你如何做?你會不會立即把電腦扔掉?當然不會,你會把電腦放在房間,等下次又需要電腦時直接開機
使用,而不是再去購買一臺。假設電腦是內存中的對象,而你的房間是內存,如果房間足夠大,則可以把所有的曾經用過的各種東西都緩存起來,但這不可能,房間的空間是有限
制的,因此有些東西你用過一次就扔掉了,你只會把一些購買成本大,需要頻繁使用的東西保存下來,類似的,Java也會把一些創建成本大,需要頻繁使用的對象緩存起來,從而
提高程序的運行性能。
前面貼出的代碼中緩存那塊其實也可以不使用靜態內部類,直接使用一個靜態數組就OK的,如下代碼我自己模擬了一個LinkinInteger,實現了同樣的功能。
public final class LinkinInteger
{
private final int value;
public LinkinInteger(int value)
{
this.value = value;
}
private static final int low = -128;
private static final int high = 127;
private static final LinkinInteger[] cache = new LinkinInteger[-(low) + high + 1];
static
{
for (int i = 0; i < cache.length; i++)
{
cache[i] = new LinkinInteger(i + low);
}
}
public static LinkinInteger valueOf(int i)
{
if (i >= low && i <= high)
{
return cache[i + (-low)];
}
return new LinkinInteger(i);
}
public static void main(String[] args)
{
// 下面3行代碼沒有使用緩存,所以輸出false
LinkinInteger a = new LinkinInteger(1);
LinkinInteger b = new LinkinInteger(1);
System.out.println(a == b);
// 下面3行代碼使用了緩存,所以輸出true
LinkinInteger c = LinkinInteger.valueOf(1);
LinkinInteger d = LinkinInteger.valueOf(1);
System.out.println(c == d);
}
}