Integer源码解析

Posted LinkinPark8林肯

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
	



以上是关于Integer源码解析的主要内容,如果未能解决你的问题,请参考以下文章

JDK:java.lang.Integer源码解析

Integer的highestOneBit方法源码解析

Integer.parseInt不同jdk源码解析

JDK1.8源码解析——Integer.bitCount

JDK1.8源码解析——Integer.bitCount

JDK1.8源码解析——Integer.bitCount