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);
	}

}


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RxJava中的flatMap操作符是一个非常常用的操作符,它可以将一个Observable发射的事件序列转换成多个Observables,然后将这些Observables发射的事件序列合并后再发射出去。 下面是flatMap操作符的解析: ```java public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper) { ObjectHelper.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableFlatMap<>(this, mapper, false, Integer.MAX_VALUE, bufferSize())); } ``` 可以看到,flatMap操作符的实现是通过创建一个ObservableFlatMap对象来完成的。其中,mapper参数表示将原始Observable发射的事件转换成的新Observable,它是一个Function类型的参数,即接受一个T类型的参数并返回一个ObservableSource类型的结果。 ObservableFlatMap的构造函数如下所示: ```java ObservableFlatMap(ObservableSource<T> source, Function<? super T, ? extends ObservableSource<? extends R>> mapper, boolean delayErrors, int maxConcurrency, int bufferSize) { this.source = source; this.mapper = mapper; this.delayErrors = delayErrors; this.maxConcurrency = maxConcurrency; this.bufferSize = bufferSize; } ``` ObservableFlatMap的核心实现是在subscribeActual方法中完成的: ```java @Override public void subscribeActual(Observer<? super R> observer) { if (ObservableScalarXMap.tryScalarXMapSubscribe(source, observer, mapper)) { return; } source.subscribe(new FlatMapObserver<>(observer, mapper, delayErrors, maxConcurrency, bufferSize)); } ``` 在subscribeActual方法中,首先判断Observable是否可以直接转换为ObservableScalarXMap,如果可以的话直接进行转换,否则创建一个FlatMapObserver对象并进行订阅。 FlatMapObserver是flatMap的核心实现类,它实现了Observer接口,并且在接收到Observable发射的事件时,会先将事件转换成新的Observable,然后将新Observable的发射事件序列合并到一个新的Observable中,最后再将新的Observable发射出去。 ```java static final class FlatMapObserver<T, R> extends AtomicInteger implements Observer<T>, Disposable { // ... @Override public void onNext(T t) { ObservableSource<? extends R> o; try { o = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper returned a null ObservableSource"); } catch (Throwable e) { Exceptions.throwIfFatal(e); upstream.dispose(); onError(e); return; } if (cancelled) { return; } if (maxConcurrency != Integer.MAX_VALUE) { synchronized (this) { if (wip == maxConcurrency) { queue.offer(t); return; } wip++; } } o.subscribe(new InnerObserver(inner, delayErrors, this)); } // ... } ``` 在FlatMapObserver的onNext方法中,首先调用mapper将Observable发射的事件转换成新的Observable,并进行非空检查。然后判断当前的并发度是否达到了最大值,如果达到了最大值,就将Observable发射的事件放到队列中。否则,就将并发度加1,并订阅新Observable。 InnerObserver是FlatMapObserver的内部类,它实现了Observer接口,并在接收到来自新Observable的发射事件序列时,将它们合并到一个新的Observable中,并将新的Observable发射出去。 ```java static final class InnerObserver<R> implements Observer<R> { // ... @Override public void onNext(R t) { if (done) { return; } inner.onNext(t); } // ... } ``` 当所有的新Observable都完成后,FlatMapObserver会调用onComplete方法通知观察者。如果发生了异常,FlatMapObserver会调用onError方法通知观察者。同时,FlatMapObserver还实现了Disposable接口,可以通过dispose方法取消订阅。 综上所述,flatMap操作符的实现是比较复杂的,它通过创建ObservableFlatMap对象,并在subscribeActual方法中创建FlatMapObserver对象来完成转换操作。在FlatMapObserver中,它还需要实现对新Observable的订阅以及将新Observable发射的事件合并到一个新的Observable中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值