我是靠谱客的博主 激昂大碗,最近开发中收集的这篇文章主要介绍java源码分析---Integer类(JDK14),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述


更多源码分析,请点击


Integer

Integer 类将基本类型 int 的值包装在对象中。 Integer 类型的对象包含一个类型为 int 的属性。

另外,提供了几种将 int 转换为 StringString 转换为 int 的方法,以及其他在处理 int 类型时有用的方法。

Integer 类被 final 关键字修饰,不能被继承。Integer 类继承自 Number 类,实现了 ComparableConstableConstantDesc 接口。

public final class Integer extends Number implements Comparable<Integer>, Constable, ConstantDesc {
private final int value;
@Native public static final int SIZE = 32;
public static final int BYTES = SIZE / Byte.SIZE;
@Native public static final int
MIN_VALUE = 0x80000000;
@Native public static final int
MAX_VALUE = 0x7fffffff;
public static final Class<Integer>
TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
}

value 为常量,用于保存 Integer 对象所对应的基本类型 int 的值。

SIZE 为静态常量,用于表示二进制补码形式的 int 类型所需要的位数。

BYTES 为静态常量,用于表示二进制补码形式的 int 值所占的字节数。即4个字节。

TYPE 为静态常量,基本类型 intClass 对象。

MIN_VALUE 为静态常量, int 型所能表示的最小数。

MAX_VALUE 为静态常量, int 型所能表示的最小数。

@Native 指示可以从本地代码引用定义常量值的字段。

static final char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};
static final byte[] DigitTens = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
} ;
static final byte[] DigitOnes = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
} ;

digits 数组用于表示所有可能出现的字符,因为 int 支持从2进制到36进制,所以这里需要有36个字符才能表示所有不同进制的数字。

DigitTensDigitOnes 两个数组主要用于获取 [0, 99] 区间内某个数的十位和个位,比如 52DigitTens[52] = 5, DigitOnes[52] = 2

Integer 类的构造方法很少使用,并且官方不推荐使用,推荐使用 valueOf(int) 方法。

IntegerCache

缓存以支持 JLS(Java Language Specification) 要求的 [-128, 127] 之间的值的自动装箱的对象标识语义。

首次使用时将初始化缓存。 缓存的大小可以由{@code -XX:AutoBoxCacheMax = }选项控制。 在VM初始化期间,可以设置java.lang.Integer.IntegerCache.high属性并将其保存在jdk.internal.misc.VM类的私有系统属性中。

注意:缓存是使用 CDS(Content Distribution Service) 存档的,并在运行时从共享存档中重新加载。 归档的缓存(Integer [])和Integer对象位于封闭的归档堆区域中。 更改实现时应注意,初始化后不应为缓存数组分配新的Integer对象。

private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache;
static Integer[] archivedCache;
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
h = Math.max(parseInt(integerCacheHighPropValue), 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
// Load IntegerCache.archivedCache from archive, if possible
VM.initializeFromArchive(IntegerCache.class);
int size = (high - low) + 1;
// Use the archived cache if it exists and is large enough
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}

toString(int)

返回表示指定整数的 String 对象。该参数将转换为带符号的十进制表示形式,并作为字符串返回。

public static String toString(int i) {
int size = stringSize(i);
if (COMPACT_STRINGS) {
byte[] buf = new byte[size];
getChars(i, size, buf);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[size * 2];
StringUTF16.getChars(i, size, buf);
return new String(buf, UTF16);
}
}
  • 调用 stringSize(int) 方法计算字符串长度。
  • 根据 COMPACT_STRINGS 的值,对字符串采用不同的编码。
  • 创建大小为 sizebyte[] ,调用 getchars(int, int, byte[]) 方法将数字以十进制将每一位保存在 byte[] 中。
  • 调用 String 的构造方法,并使用 byte[] 对字符串初始化。
static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}

COMPACT_STRINGS 定义在 String 类中,并在静态代码块中初始化为 true 。表示该字符串是否可以被压缩,用于具有多个可能实现路径的方法。(java 9 新特性)

这个字段的实际值是由JVM注入的。静态初始化块用于设置这里的值,以表明这个静态final字段不可静态折叠,并避免在vm初始化期间任何可能的循环依赖。

实例字段值通常对于优化JIT编译器是不透明的。因此,在性能敏感的地方,首先检查静态布尔 COMPACT_STRINGS,然后再检查编码器字段

Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。

stringSize(int)

返回给定int值的字符串表示所需要的长度。

  • 如果 x 为负数,d 等于1;否则,d 等于0。因为如果 x 为负数,字符串的第一个字符应该为 ‘-’。

  • 如果 x 是正数,将 x 装换成负数进行计算,方法如下:

  • 判断 x 是否大于 -10 ,如果大于,说明 x 在区间 [-9, 0] 之间。即 x 只有1位。

  • 如果 x 小于 -10,则给 -10×10,比较 x 与 -100 的大小,依次类推……

  • 求出数字所需要的位数,加上符号位 d 的长度,即为字符串所需要的长度。

static int stringSize(int x) {
int d = 1;
if (x >= 0) {
d = 0;
x = -x;
}
int p = -10;
for (int i = 1; i < 10; i++) {
if (x > p)
return i + d;
p = 10 * p;
}
return 10 + d;
}

getChars(int, int, byte[])

将代表整数 i 的字符放入字符数组 buf 。字符从指定索引处的最低有效数字(不包括最高字符)开始向前放置

static int getChars(int i, int index, byte[] buf) {
int q, r;
int charPos = index;
boolean negative = i < 0;
if (!negative) {
i = -i;
}
// Generate two digits per iteration
while (i <= -100) {
q = i / 100;
r = (q * 100) - i;
i = q;
buf[--charPos] = DigitOnes[r];
buf[--charPos] = DigitTens[r];
}
// We know there are at most two digits left at this point.
q = i / 10;
r = (q * 10) - i;
buf[--charPos] = (byte)('0' + r);
// Whatever left is the remaining digit.
if (q < 0) {
buf[--charPos] = (byte)('0' - q);
}
if (negative) {
buf[--charPos] = (byte)'-';
}
return charPos;
}
  • 如果整数 i 是正数,将其转换为负数。
  • i 小于100时,每次对 i 除以 100,然后再乘以100,减去 i ,可以得到 i 除 100 的余数 r,通过数组 DigitOnesDigitTens 分别取到 r 的个位和十位存到数组 buf 中,依此循环。
  • 当 i 大于100 时,不能直接通过数组 DigitOnesDigitTens 获得数字,因为不能确定此时 i 的位数。所以对 i 除 10 求余数将其存放再数组 buf 中,如果 q 仍小于 0,说明最高位就是 q ,将其保存再数组 buf 中。
  • 根据符号标志 negative 判断数字是否为负数,如果是负数,则在 buf 数组最前面加上负号。

思考:为什么将正数转化为负数?

因为 int 型整数的范围为 [-231 , 231-1],将正数转换为负数,以覆盖 Integer.MIN_VALUE 的情况。否则(将负数转换为正数),转换将暴露 -Integer.MIN_VALUE,该整数将溢出。

思考:为什么 (‘0’ + r)但是(’0’ - q)?

因为 r 的结果是正数,而 q 的计算结果是负数( i 为负数)。

toString(int, int)

将给定的数字 i 以 radix 进制的字符串形式返回。

public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
/* Use the faster version */
if (radix == 10) {
return toString(i);
}
if (COMPACT_STRINGS) {
byte[] buf = new byte[33];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = (byte)digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = (byte)digits[-i];
if (negative) {
buf[--charPos] = '-';
}
return StringLatin1.newString(buf, charPos, (33 - charPos));
}
return toStringUTF16(i, radix);
}
public static String newString(byte[] val, int index, int len) {
return new String(Arrays.copyOfRange(val, index, index + len),
LATIN1);
}
  • 如果进制 radix 小于 Character.MIN_RADIX (2) 或者大于 Character.MAX_RADIX (36) 。采用 10 进制。
  • 如果 radix == 10 ,直接调用 toString(int) 方法。
  • 否则,先根据 COMPACT_STRINGS 的值,对字符串采用不同的编码。
  • 如果为 true ,即采用 LATIN1 编码:1)先初始化一个大小为 33 的数组,从最后一位,即索引 32 处开始存放数据。2)如果 i 为正数,将 i 转换为负数。当 i 小于等于 -radix ,循环取余,将余数通过数组 digits 转化为 radix 进制数保存到 buf 数组中。3)如果是负数,在加上负号。4)调用 StringLatin1.newString() 方法以 buf 数组中从索引 charPos 处开始初始化 String 对象返回。(本质上就是通过数组拷贝的方式将 buf 数组中有效的部分(即从索引 charPos 开始之后的数据)复制一份作为 String 对象的初始值,并设置编码方式为 LATIN1 )。
  • 否则,采用 UTF16 编码,调用 toStringUTF16() 方法实现。

思考:为什么进制数不能超过 36

因为 26 个英文字母,加上0到9一共 10 个数字,一共36个字符,最多表示 36 进制的数。

思考:为什么初始化数组 buf 的大小为 33

因为 int 型数据最大长度为 32 位(如果以2进制形式表示),如果是负数的话,需要加上负号,一共33位。

toStringUTF16(int, int)

将给定的数字 i 以 radix 进制的字符串形式返回。字符串编码方式为 UTF16 。具体实现原理和上述 toString(int, int) 方法相似,这里不再赘述。

private static String toStringUTF16(int i, int radix) {
byte[] buf = new byte[33 * 2];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
StringUTF16.putChar(buf, charPos--, digits[-(i % radix)]);
i = i / radix;
}
StringUTF16.putChar(buf, charPos, digits[-i]);
if (negative) {
StringUTF16.putChar(buf, --charPos, '-');
}
return StringUTF16.newString(buf, charPos, (33 - charPos));
}

putChar()

@HotSpotIntrinsicCandidate
static void putChar(byte[] val, int index, int c) {
assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
index <<= 1;
val[index++] = (byte)(c >> HI_BYTE_SHIFT);
val[index]
= (byte)(c >> LO_BYTE_SHIFT);
}

assert,断言,如果后面表达式为真,不采取任何措施,否则,抛出 AssertionError() ,后面的字符串即传入该错误的构造函数的值。

因为是采用 UTF16 编码形式,所以需要对索引index左移一位。然后将字符 c 的值拷贝到 buf 数组中。

newString()

newString() 方法底层调用 Arrays.copyOfRange() 方法实现区间 [start, end) 范围内的字符串复制。

public static String newString(byte[] val, int index, int len) {
return new String(Arrays.copyOfRange(val, index, index + len), LATIN1);
}

toUnsignedString(int, int)

返回指定数字 i10 进制的无符号整数的字符串表示形式。

  • 先使用 toUnsignedLong() 方法(见下文)将整数 i 转换为 long (长整型),然后调用 Long.toUnsignedString() 方法实现。
  • 关于 Long.toString() 方法实现细节,可点击查看 Long 类的源码分析
public static String toUnsignedString(int i) {
return Long.toString(toUnsignedLong(i));
}

toUnsignedString(int, int)

返回指定数字 iradix 进制的无符号整数的字符串表示形式。

  • 先使用 toUnsignedLong() 方法(见下文)将整数 i 转换为 long (长整型),然后调用 Long.toUnsignedString() 方法实现。
  • 关于 Long.toUnsignedString() 方法实现细节,可点击查看 Long 类的源码分析
public static String toUnsignedString(int i, int radix) {
return Long.toUnsignedString(toUnsignedLong(i), radix);
}

toUnsignedLong(int)

将给定的整数转换为无符号 long 型。 在转换为无符号 long 时,long的高阶 32 位为零,而低阶 32 位等于参数 x 的位。 因此,零和正整数值映射为数值相等的 long 值,而负整数值映射为等于输入加232long 值。

public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
}
//测试
System.out.println(Integer.toUnsignedLong(-10));//输出为:4294967286 即2^32(4294967296)+i

toHexString(int)

返回指定数字 i16 进制的无符号整数的字符串表示形式。调用 toUnsignedString(int, int) 方法实现。

public static String toHexString(int i) {
return toUnsignedString0(i, 4);
}

toOctalString(int)

返回指定数字 i8 进制的无符号整数的字符串表示形式。调用 toUnsignedString(int, int) 方法实现。

public static String toOctalString(int i) {
return toUnsignedString0(i, 3);
}

toBinaryString(int)

返回指定数字 i2 进制的无符号整数的字符串表示形式。调用 toUnsignedString(int, int) 方法实现。

public static String toBinaryString(int i) {
return toUnsignedString0(i, 1);
}

toUnsignedString0(int, int)

将指定的数字 i 转换成指定进制数的字符串表示形式。

  • 通过 numberOfLeadingZeros() 方法计算出计算出 val 二进制补码表示形式中最高位之前的 0 的个数,从而计算出 val 二进制补码表示中的有效位数。
  • 计算出使用指定进制表示 val 需要的位数。
  • 根据 COMPACT_STRINGS 的值,对字符串采用不同的编码。
  • 如果为 true ,即采用 LATIN1 编码,创建一个长度为 charsbyte 数组,调用 formatUnsignedInt() 方法(见下文)将 val 转化成指定进制存入 buf 数组中。然后通过 String 的构造方法转换为 String 对象。
  • 否则,采用 UTF16 编码,创建一个长度为 chars × 2byte 数组(因为UTF16编码每个字符占两个字节),调用 formatUnsignedIntUTF16() 方法(见下文)将 val 转化成指定进制存入 buf 数组中。然后通过 String 的构造方法转换为 String 对象。

思考:为什么上面 toHexString()toOctalString() 方法中调用 toUnsignedString0() 方法的第二个参数分别为 43

因为 4 位二进制数可以表示 1 位16进制数,三位二进制数可以表示1位8进制数。这样在方法中通过 二进制位数/shift 就能计算出用16进制或8进制表示 val 时需要的位数。

思考:为什么要先给二进制位数(mag)加上 shift - 1 之后,再除以 shift ?

假设二进制位数(mag)是 7 位,直接除以 shift(假设此时shift为 4 ),得到的结果为 1 。显然不对,如果先给 7 加上 3 ,结果为 2 。才我们想要的正确结果。读者可以思考那为什么不能使用 mag/shift + 1 的方式计算?看到这里不得不感叹写源码的人真机智????。

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);
if (COMPACT_STRINGS) {
byte[] buf = new byte[chars];
formatUnsignedInt(val, shift, buf, chars);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[chars * 2];
formatUnsignedIntUTF16(val, shift, buf, chars);
return new String(buf, UTF16);
}
}

numberOfLeadingZeros(int)

返回指定 int 值的二进制补码表示形式中最高位(“最左非零位”)一位之前的零位数目。 如果 i 小于等于零,则返回32。

public static int numberOfLeadingZeros(int i) {
// HD, Count leading 0's
if (i <= 0)
return i == 0 ? 32 : 0;
int n = 31;
if (i >= 1 << 16) { n -= 16; i >>>= 16; }
if (i >= 1 <<
8) { n -=
8; i >>>=
8; }
if (i >= 1 <<
4) { n -=
4; i >>>=
4; }
if (i >= 1 <<
2) { n -=
2; i >>>=
2; }
return n - (i >>> 1);
}

formatUnsignedInt(int, int, byte[], int)

val 转化成指定进制存入 buf 数组中。(LATIN1编码)

  • 从数组最后开始往前存放,通过对 shift 的移位操作计算进制数,1 左移 4 位即16。
  • 通过对 val 和 mask 做 与操作。计算每一位数字,然后将 val 右移 shift 位,循环操作
private static void formatUnsignedInt(int val, int shift, byte[] buf, int len) {
int charPos = len;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[--charPos] = (byte)Integer.digits[val & mask];
val >>>= shift;
} while (charPos > 0);
}

formatUnsignedIntUTF16(int, int, byte[], int)

val 转化成指定进制存入 buf 数组中。(UTF16编码) 原理同上述方法相同,不再赘述。

private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int len) {
int charPos = len;
int radix = 1 << shift;
int mask = radix - 1;
do {
StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]);
val >>>= shift;
} while (charPos > 0);
}

parseInt(String, int)

将给定进制 radix 的字符串 s 解析为十进制的有符号整数。

  • 如果字符串 snull,或者进制数 radix 小于2或者大于36,则抛出异常。
  • 判断字符产 s 的第一个字符是否为 ‘-’ 或 ‘+’,
  • 从最高位开始计算,每取一次数字对当前结果乘以 radix 然后加上当前位数字。
  • 判断是否为正数,如果是正数,则需要在结果前加上负号将结果转为正数。

注意:在初始化 IntegerCache 之前,可以在 VM 初始化期间的早期调用此方法。 必须注意不要使用 valueOf 方法。

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");
}
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
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, radix);
}
if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s, radix);
}
i++;
}
int multmin = limit / radix;
int result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s, radix);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s, radix);
}
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s, radix);
}
}

其他 parseInt(String)parseInt(CharSequence, int, int, int)parseUnsignedInt()系列 方法与上述方法原理一致,这里不再赘述。

valueOf(int)

返回表示指定int值的Integer实例。 如果不需要新的Integer实例,则通常应优先于构造方法 Integer(int) 使用此方法,因为此方法通过缓存经常请求的值可能会产生明显更好的空间和时间性能。 此方法将始终缓存-128至127(包括)范围内的值,并且可能缓存该范围之外的其他值。

public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

valueOf(String, int)

将给定进制 radix 的字符串 s 解析为十进制的有符号整数。

public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}

valueOf(String)

将给定字符串 s (十进制)解析为十进制的有符号整数。

public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}

byteValue()shortValue()intValue()longValuefloatValue()doubleValue() 等方法实现简单,不再赘述。

toString()

String 返回该对象的值。调用 toString(int) 方法实现,前面已经讲过,忘记了点击了解详情。

public String toString() {
return toString(value);
}

hashCode(int)

返回 int 型整数的哈希值,即该数字本身。

public static int hashCode(int value) {
return value;
}

hashCode()

返回当前对象的哈希值,调用 hashCode() 方法实现。

public int hashCode() {
return Integer.hashCode(value);
}

equals(Object)

判断当前对象是否与给定的 obj 对象相等。

  • 先判断 obj 是否是 Integer 类型,如果是的话,比较他们的值是否相等。
  • 否则,返回 false
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}

getInteger(String, Integer)

返回指定名称的系统属性 nm 的整数值。val 是默认值。如果没有指定名称的属性,或者该属性的格式不正确,或者指定名称为空或null,则返回默认值。

  • 通过 System.getProperty(String) 方法获取到系统属性。关于该方法,请参考 System 类的源码分析
  • 根据 decode(String) 方法(见下文),将此属性的字符串值解释为整数值,并返回表示该值的 Integer 对象。
public static Integer getInteger(String nm, Integer val) {
String v = null;
try {
v = System.getProperty(nm);
} catch (IllegalArgumentException | NullPointerException e) {
}
if (v != null) {
try {
return Integer.decode(v);
} catch (NumberFormatException e) {
}
}
return val;
}

decode(String)

将字符串解码为数字,并返回该数字的 Integer 对象。

如果属性值以两个ASCII字符 0x 或ASCII字符 开头,而不以减号开头,则将其其余部分解析为十六进制整数,与使用进制数为16的方法 valueOf(String, int) 完全相同。

如果属性值以ASCII字符 0 开头,后跟另一个字符,则该属性值将被解析为八进制整数,与使用进制数为8的 valueOf(String, int) 方法完全相同。

否则,将属性值解析为十进制整数,与使用进制数为10的 valueOf(String, int) 方法完全相同。

关于 valueOf(String, int) 方法可点击跳转至上文查看。

public static Integer decode(String nm) throws NumberFormatException {
int radix = 10;
int index = 0;
boolean negative = false;
Integer result;
if (nm.isEmpty())
throw new NumberFormatException("Zero length string");
char firstChar = nm.charAt(0);
// Handle sign, if present
if (firstChar == '-') {
negative = true;
index++;
} else if (firstChar == '+')
index++;
// Handle radix specifier, if present
if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
index += 2;
radix = 16;
}
else if (nm.startsWith("#", index)) {
index ++;
radix = 16;
}
else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
index ++;
radix = 8;
}
if (nm.startsWith("-", index) || nm.startsWith("+", index))
throw new NumberFormatException("Sign character in wrong position");
try {
result = Integer.valueOf(nm.substring(index), radix);
result = negative ? Integer.valueOf(-result.intValue()) : result;
} catch (NumberFormatException e) {
// If number is Integer.MIN_VALUE, we'll end up here. The next line
// handles this case, and causes any genuine format error to be
// rethrown.
String constant = negative ? ("-" + nm.substring(index))
: nm.substring(index);
result = Integer.valueOf(constant, radix);
}
return result;
}

getInteger(String, int)

返回指定名称的系统属性 nm 的整数值。val 是默认值。如果没有指定名称的属性,或者该属性的格式不正确,或者指定名称为空或null,则将默认值 val 转为 Integer 对象返回。可参考上文中的 getInteger(String, Integer) 方法。

public static Integer getInteger(String nm, int val) {
Integer result = getInteger(nm, null);
return (result == null) ? Integer.valueOf(val) : result;
}

compare(int, int)

比较两个 int 型整数的大小

  • 如果 x 小于 y ,返回 -1 。
  • 如果 x 等于 y ,返回 0 。
  • 如果 x 大于 y ,返回 1 。
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

compareTo(Integer)

比较两个 Integer 对象的大小,即比较他们 value 值的大小。

public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}

compareUnsigned(int, int)

比较两个无符号整数的大小。即最高位不当作符号位进行比较,所以加上 MIN_VALUE 防止超过 int 的表示范围。

public static int compareUnsigned(int x, int y) {
return compare(x + MIN_VALUE, y + MIN_VALUE);
}

divideUnsigned(int, int)

将两个数转换为无符号的数,然后相除。

public static int divideUnsigned(int dividend, int divisor) {
// In lieu of tricky code, for now just use long arithmetic.
return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
}

remainderUnsigned(int, int)

将两个数转换为无符号的数,然后取余。

public static int remainderUnsigned(int dividend, int divisor) {
// In lieu of tricky code, for now just use long arithmetic.
return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
}

highestOneBit(int)

保留最高位的1,其余位全部置为0。

  • numberOfLeadingZeros(int) 方法返回整数 i 二进制补码形式从左边最高位开始第一个零的位置 index
  • MIN_VALUE 无符号右移 index 位,然后和 i 进行与操作。

例:i = 10,补码形式为 0x0000000A,第一个1的位置为28,MIN_VALUE右移28位为 0x00000008

0000……0000 1010 & 0000……0000 1000 —> 0000……0000 1000

public static int highestOneBit(int i) {
return i & (MIN_VALUE >>> numberOfLeadingZeros(i));
}

lowestOneBit(int)

保留最低位的1,其余位全部置0。因为负数的补码是正数每位取反然后加1,所以对正数和负数求与即可。

public static int lowestOneBit(int i) {
// HD, Section 2-1
return i & -i;
}

numberOfTrailingZeros(int)

返回 int 类型二进制补码表示形式最低为的1的右边有几个零,和 numberOfLeadingZeros(int) 方法原理类似 。

例,10的二进制位 0000……0000 1010,最低位的1的右边只有1个0,返回结果为1。

public static int numberOfTrailingZeros(int i) {
// HD, Count trailing 0's
i = ~i & (i - 1);
if (i <= 0) return i & 32;
int n = 1;
if (i > 1 << 16) { n += 16; i >>>= 16; }
if (i > 1 <<
8) { n +=
8; i >>>=
8; }
if (i > 1 <<
4) { n +=
4; i >>>=
4; }
if (i > 1 <<
2) { n +=
2; i >>>=
2; }
return n + (i >>> 1);
}

bitCount(int)

返回一个int类型的二进制补码表示形式里面有多少个1。

例,10的二进制位 0000……0000 1010,有两个1,那么 bitCount(10) 结果就为2。

  • 核心思想是使用二分法,两两一组相加,之后四个四个一组相加,接着八个八个,最后就得到各位之和了。
  • 第一行是计算每两位中的 1 的个数 , 并且用该对应的两位来存储这个个数 , 如 : 01101100 转换后为 01011000 , 即先把前者每两位分段 01 10 11 00 , 分别有 1 1 2 0 个 1, 用两位二进制数表示为 01 01 10 00, 合起来为 01011000。
  • 第二行是计算每四位中的 1 的个数 , 并且用该对应的四位来存储这个个数 。如 : 01101100 经过第一行计算后得 01011000 , 然后把 01011000 每四位分段成 0101 1000 , 段内移位相加 : 前段 01+01 =10 , 后段 10+00=10, 分别用四位二进制数表示为 0010 0010, 合起来为 00100010 。
  • 下面的各行以此类推 , 分别计算每 8 位 ,16 位 ,32 位中的 1 的个数。
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}

rotateLeft(int, int)

返回通过将指定的 int 值的二进制补码循环左移指定的位数获得的值。 (位从左手移出,或移到高阶,在右侧重新移入,或移到低阶。)

(i << distance) 先把尾巴那几位空出来成0,然后(i >>> -distance)获得前面的那几位,然后按位或运算,就旋转了。

注意:向左旋转负距离等于向右旋转:rotateLeft(val, -distance) == rotateRight(val, distance) 。 还要注意,以32的任意倍数进行旋转都是空操作。

public static int rotateLeft(int i, int distance) {
return (i << distance) | (i >>> -distance);
}

rotateRight(int, int)

返回通过将指定的 int 值的二进制补码循环右移指定的位数获得的值。和 rotateLeft(int, int) 方法一样。

public static int rotateRight(int i, int distance) {
return (i >>> distance) | (i << -distance);
}

reverse(int)

将整数 i 的二进制补码表示形式翻转。即将整数 i 转换为32位二进制数据后,高位和低位对应位置数据互换。

public static int reverse(int i) {
// HD, Figure 7-1
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
return reverseBytes(i);
}

reverseBytes(int)

将整数 i 的二进制补码表示形式翻转。即将整数 i 转换为32位二进制数据后,以字节为单位翻转。

public static int reverseBytes(int i) {
return (i << 24)
|
((i & 0xff00) << 8)
|
((i >>> 8) & 0xff00) |
(i >>> 24);
}

signum(int)

返回指定 int 值的 signum 函数值。(如果指定的值为负,则返回值为-1;如果指定的值为零,则返回0;如果指定的值为正,则返回1)

public static int signum(int i) {
// HD, Section 2-7
return (i >> 31) | (-i >>> 31);
}

sum(int, int)

返回整数 a 和 b 的值。

public static int sum(int a, int b) {
return a + b;
}

max(int, int)

返回整数 a 和 b 中较大的值。

public static int max(int a, int b) {
return Math.max(a, b);
}

min(int, int)

返回整数 a 和 b 中较小的值。

public static int min(int a, int b) {
return Math.min(a, b);
}

describeConstable()

Constable 接口中的方法。点此了解详情。

@Override
public Optional<Integer> describeConstable() {
return Optional.of(this);
}

resolveConstantDesc(MethodHandles.Lookup)

ConstantDesc 接口中的方法,点此了解详情。

@Override
public Integer resolveConstantDesc(MethodHandles.Lookup lookup) {
return this;
}

更多源码分析,请点击

最后

以上就是激昂大碗为你收集整理的java源码分析---Integer类(JDK14)的全部内容,希望文章能够帮你解决java源码分析---Integer类(JDK14)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部