Integer 包装类源码实现与分析

网友投稿 650 2022-10-23

Integer 包装类源码实现与分析

Integer 包装类源码实现与分析

这是《水煮 JDK 源码》系列 的第8篇文章,计划撰写100篇关于JDK源码相关的文章

在 Java 语言中,默认定义的整数类型为 int 类型,默认定义的浮点类型为 double 类型,如果定义的数值在基本类型所允许的范围内,那么在定义时就不需要显式申明,直接定义即可,如下所示:

// 下面的定义都是合法的 int intNum = 2; // byte 的范围为 -128 到 127,所以 2 在范围内 byte byteNum = 2; // short 的范围为 -32768 到 32767,所以 2 在范围内 short shortNum = 2; // long 的范围为 -2的63次方 到 2的63次方-1 long longNum = 2; // float 的范围为 1.4e-45f 到 3.4028235e+38f float floatNum = 2; // double 的范围为 4.9e-324 到 1.7976931348623157e+308 double doubleNum = 2; // 下面的定义是不合法的,数值都超过了类型所允许的最大值 // 这种情况需要选择合适的数据类型 byte byteNum2 = 200; byte shortNum2 = 40000; // 该定义也是不合法的,默认的浮点类型为 double float floatNum2 = 2.0;

虽然基本数据类型 byte、short、int、long、float、double 经常使用,但是我们平时可能并不会过多关注其相应的包装类 Byte、Short、Int、Long、Float 、Double,这里以 Integer 类为例,分析其具体源码的实现。

Integer 类位于 java.lang 下,其继承于 Number 类,实现了 Comparable 比较接口,其定义如下:

public final class Integer extends Number implements Comparable

关于父类 Number 类,已经在之前的文章中分析过了,可以查看我的另外一篇文章:

Number 类及各子类所占字节数源码分析

对于 Comparable 比较接口,其定义也是很简单的,只有一个 compareTo() 方法,如下:

package java.lang; import java.util.*; public interface Comparable { public int compareTo(T o); }

整个 Integer 类的源码还是比较多的,加上注释的话,接近 1600 行代码了,在分析源码的时候,按照以下的分类进行:

成员变量 构造函数 内部缓存类 方法

1、成员变量

Integer 类中定义了一个 value 成员变量,用于表示 Integer 对应的 int 值,如下:

// Integer 对象对应的 int 值 private final int value;

2、构造函数

Integer 类提供了2个构造函数,其定义如下:

public Integer(int value) { this.value = value; } public Integer(String s) throws NumberFormatException { // 调用 parseInt 方法,默认基数为 10,将字符串解析成 int this.value = parseInt(s, 10); }

从上面可以看出,既可以从 int 类型构建 Integer,也可以从 String 类型构建,在实际的开发过程中,使用构造函数来创建 Integer 其实很少用到,因为 Integer 类和其他的普通类不一样,它对应于基础数据类型 int,而自从 JDK 1.5 提供的自动装箱和拆箱操作,可以使用一个数值来创建 Integer 对象;如果是对于 String 类型,想要转换为 Integer 类型,实际中更多直接使用 Integer.parseInt() 方法进行,如下:

// 自动装箱 Integer num = 1; // Integer.parseInt() 方法首先返回的是 int 类型,然后会涉及自动装箱 Integer strNum = Integer.parseInt("1");

Java 的自动装箱和拆箱操作是编译器自动完成的,装箱的时候调用的是包装类的 valueOf() 方法,上面代码定义的 num 和 strNum 对象其实是相同的,至于为什么会相同,在下文分析 valueOf() 方法时会作出具体的解释。

3、内部缓存类

在 Integer 类的内部,定义了缓存类 IntegerCache,该类是一个静态类,其定义如下:

private static class IntegerCache { // 最小值 -128 static final int low = -128; // 最大值 static final int high; // 缓存数组 static final Integer cache[]; static { // 最大值默认为 127,也可以通过属性字段配置,具体属性名为 java.lang.Integer.IntegerCache.high int h = 127; // 获取 java.lang.Integer.IntegerCache.high 属性值 String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); // 如果属性值不为空 if (integerCacheHighPropValue != null) { try { // 使用 parseInt() 方法将属性值转换为 int 类型 int i = parseInt(integerCacheHighPropValue); // 取属性值与127两者之间的最大值,也就是说 i 的最小值其实是127 i = Math.max(i, 127); // 数组的最大值为 Integer.MAX_VALUE // 取 i 和 Integer.MAX_VALUE - (-low) -1 两者之间最小值 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; // 创建大小为 (high - low) + 1 的整型数组 cache = new Integer[(high - low) + 1]; int j = low; // 创建并缓存 Integer 对象 for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) // 断言缓存最大值 high 大于等于 127 assert IntegerCache.high >= 127; } private IntegerCache() {} }

从 IntegerCache 的定义可以看出,3个成员变量都是静态常量,只有一个静态代码块,没有任何其他的方法,关于静态代码块的分析已经在代码中备注了,从静态代码块中可以得出以下的几点:

IntegerCache 的缓存最小值 low 为 -128,与其他的类 Byte、Short、Long 是相同的; IntegerCache 的缓存最大值 high 可以通过属性 java.lang.Integer.IntegerCache.high 进行设置,而其他的类 Byte、Short、Long 都是无法设置的; IntegerCache 的缓存最大值 high 的最小值为127,如果通过属性设置的值比127小,则赋值为 127,也就是此时的属性值是无效的;

关于 Byte、Short、Integer、Long 的内部缓存类详细的对比与分析,可以参考我的上一篇源码分析文章:

[Byte、Short、Integer、Long内部缓存类的对比与分析]()

4、方法

Integer 类提供的方法较多,大部分都是静态方法,主要分为以下的几类:

toString() 方法:主要是将 Integer 转换为字符串,这类方法中还有 toUnsignedString()、toHexString() 等等; parseInt() 方法:这个方法和 toString() 方法相反,主要是将 String 类型转换为 int 类型; valueOf() 方法:主要是通过 int 或 String 类型创建 Integer 对象; getInteger() 方法:主要用于获取指定名称的系统属性的整数值; compare() 方法:用于比较两个整型数值是否相等; 位操作方法 其他方法

4.1 toString() 方法

public String toString() { return toString(value); } public static String toString(int i) { // 如果为 int 类型最小值 if (i == Integer.MIN_VALUE) return "-2147483648"; // 获取 int 数值字符长度 int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); char[] buf = new char[size]; getChars(i, size, buf); return new String(buf, true); } public static String toString(int i, int radix) { // MIN_RADIX 为 2,MAX_RADIX 为36,如果不在范围内,默认为 10 if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) radix = 10; /* Use the faster version */ if (radix == 10) { return toString(i); } char buf[] = new char[33]; boolean negative = (i < 0); int charPos = 32; if (!negative) { i = -i; } while (i <= -radix) { buf[charPos--] = digits[-(i % radix)]; i = i / radix; } buf[charPos] = digits[-i]; if (negative) { buf[--charPos] = '-'; } return new String(buf, charPos, (33 - charPos)); } /** 转换为指定进制的无符号字符串 */ public static String toUnsignedString(int i, int radix) { return Long.toUnsignedString(toUnsignedLong(i), radix); } /** 转换为十六进制 */ public static String toHexString(int i) { return toUnsignedString0(i, 4); } /** 转换为八进制 */ public static String toOctalString(int i) { return toUnsignedString0(i, 3); } /** 转换为二进制 */ public static String toBinaryString(int i) { return toUnsignedString0(i, 1); } /** 转换为无符号字符串,int 类型转换为无符号可能越界,因此使用 long 类型 */ public static String toUnsignedString(int i) { return Long.toString(toUnsignedLong(i)); } private static String toUnsignedString0(int val, int shift) { // assert shift > 0 && shift <=5 : "Illegal shift value"; int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val); int chars = Math.max(((mag + (shift - 1)) / shift), 1); char[] buf = new char[chars]; formatUnsignedInt(val, shift, buf, 0, chars); // Use special constructor which takes over "buf". return new String(buf, true); }

toString() 方法又细分了很多方法,比如转换为二进制、八进制、十六进制、无符号字符串等方法,利用 toString() 方法可以将 int 整型转换为二进制、八进制、十六进制,如下:

public static void main(String[] args) { // 由于最小的 MIN_RADIX 为 2,而传入的 1 小于 2,所以默认为 10进制 System.out.println(Integer.toString(10, 1)); // 十进制 System.out.println(Integer.toString(10, 10)); // 二进制 System.out.println(Integer.toBinaryString(10)); // 八进制 System.out.println(Integer.toOctalString(10)); // 十六进制 System.out.println(Integer.toHexString(10)); }

输出结果如下:

10 10 1010 12 a

4.2 parseInt() 方法

public static int parseInt(String s) throws NumberFormatException { // 默认转换为 10 进制数值,这个方法在实际中应用最多 return parseInt(s,10); } public static int parseInt(String s, int radix) throws NumberFormatException { /* * WARNING: This method may be invoked early during VM initialization * before IntegerCache is initialized. Care must be taken to not use * the valueOf method. */ 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 static int parseUnsignedInt(String s) throws NumberFormatException { // 转换为无符号的十进制数值 return parseUnsignedInt(s, 10); } public static int parseUnsignedInt(String s, int radix) throws NumberFormatException { if (s == null) { throw new NumberFormatException("null"); } int len = s.length(); if (len > 0) { char firstChar = s.charAt(0); if (firstChar == '-') { throw new NumberFormatException(String.format("Illegal leading minus sign " + "on unsigned string %s.", s)); } else { if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits return parseInt(s, radix); } else { long ell = Long.parseLong(s, radix); if ((ell & 0xffff_ffff_0000_0000L) == 0) { return (int) ell; } else { throw new NumberFormatException(String.format("String value %s exceeds " + "range of unsigned int.", s)); } } } } else { throw NumberFormatException.forInputString(s); } }

4.3 valueOf() 方法

valueOf() 方法主要是通过 int 或 String 类型创建 Integer 对象,其源码如下:

public static Integer valueOf(int i) { // 如果数值 i 在缓存的区间之内,则直接从缓存复用 Integer 对象 // 自动装箱的时候会调用此方法 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } public static Integer valueOf(String s) throws NumberFormatException { // 先通过 parserInt() 方法将字符串转为 int,默认为十进制 return Integer.valueOf(parseInt(s, 10)); } public static Integer valueOf(String s, int radix) throws NumberFormatException { // 先通过 parserInt() 方法将字符串转为指定进制的 int return Integer.valueOf(parseInt(s,radix)); }

int 与 Integer 之间涉及到自动装箱和拆箱操作,自动装箱操作调用的是 valueOf() 方法,如果数值在缓存区间的最小值与最大值之间时,会复用缓存中的对象,默认缓存区间为 [-128, 127]。

4.4 getInteger() 方法

getInteger() 方法主要用于获取指定名称的系统属性的整数值,相关源码如下:

public static Integer getInteger(String nm) { return getInteger(nm, null); } public static Integer getInteger(String nm, int val) { Integer result = getInteger(nm, null); // 如果属性值不存在,则返回默认值 val return (result == null) ? Integer.valueOf(val) : result; } public static Integer getInteger(String nm, Integer val) { String v = null; try { // 获取属性名为 nm 的系统属性 v = System.getProperty(nm); } catch (IllegalArgumentException | NullPointerException e) { } if (v != null) { try { // 调用 decode 方法将属性值转换为 Integer return Integer.decode(v); } catch (NumberFormatException e) { } } return val; }

关于 System.getProperty() 获取系统属性的更多应用,可以参考我写的另一篇文章:

Java代码判断当前操作系统是Windows或Linux或MacOS

4.5 compare()`方法

compare() 方法用于比较两个整型数值是否相等,其源码如下:

public int compareTo(Integer anotherInteger) { // 这里比较的是数值 return compare(this.value, anotherInteger.value); } public static int compare(int x, int y) { // 如果 x 小于 y,则返回 -1 // 如果 x 等于 y,则返回 0 // 如果 x 大于 y,则返回 1 return (x < y) ? -1 : ((x == y) ? 0 : 1); } public static int compareUnsigned(int x, int y) { // 无符号数值比较 return compare(x + MIN_VALUE, y + MIN_VALUE); } public boolean equals(Object obj) { if (obj instanceof Integer) { // 比较数值是否相等 return value == ((Integer)obj).intValue(); } return false; }

对于 compare() 比较方法,返回的结果有 -1、0、1 三种,如果不需要返回 boolean 类型,可以使用这个方法,对于 Integer 包装类的比较,建议使用 equals() 方法。

4.6 位操作方法

Integer 类中提供了很多位操作的方法,主要有以下的这些:

highestOneBit():返回给定数值二进制最高位1的权值; lowestOneBit():返回给定数值二进制最低位1的权值; numberOfLeadingZeros():返回给定数值二进制中从最左边算起 0 的个数; numberOfTrailingZeros():返回给定数值二进制中从最右边算起 0 的个数; bitCount():返回给定数值的二进制中 1 的个数; rotateLeft():将给定整数值的二进制补码数左旋转给定位数; rotateRight():将给定整数值的二进制补码数右旋转给定位数; reverse():将给定整数值的二进制补码数进行反转; signum():返回给定 int 值的 sign 函数; reverseBytes():将给定整数的二进制补码按照字节进行反转;

4.7 其他方法

sum():获取两个整数的和; max():获取两个整数之间的最大值,自 JDK 1.8 版本新增的,具体调用的是 Math.max() 方法; min():获取两个整数之间的最小值,自 JDK 1.8 版本新增的,具体调用的是 Math.min() 方法;

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:elton- 高性能简单的 Go Web 框架
下一篇:JIT编译日志
相关文章

 发表评论

暂时没有评论,来抢沙发吧~