Integer源碼解析


這篇博客我來整理下以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);
	}

}


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