JDK源码之Integer类分析
一 简介
Integer是int基本类型的包装类,同样继承了Number类,实现了Comparable接口,String类中的一些转化方法就使用了Integer类中的一些API,且fianl修饰不可继承:
public final class Integer extends Number implements Comparable<Integer> {
Number传送门
Long类源码和Integer类源力基本相同,大部分API是一样的逻辑!
二 源码解析
Integer类API比较多也比较重要,分开几个部分解析:
1 属性
// 包装类的int类型值
private final int value;
//两个被废弃的构造器,官方推荐valueOf形式
@Deprecated(since="9")
public Integer(int value) {
this.value = value;
}
@Deprecated(since="9")
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
// int最小值,
@Native public static final int MIN_VALUE = 0x80000000;
//int最大值, int 范围 - 2^{31} 到2^{31}-1之间的整数即: -2147483648 ~2147483647
@Native public static final int MAX_VALUE = 0x7fffffff;
// 表示二进制补码形式的int值的比特数比,32
@Native public static final int SIZE = 32;
//字节数常量,4
public static final int BYTES = SIZE / Byte.SIZE;
// Class类实例
public static final Class<java.lang.Integer> TYPE = (Class<java.lang.Integer>) Class.getPrimitiveClass("int");
//将数字表示为字符串的所有可能字符,因为int支持从2进制到36进制,所以这里需要有36个字符才能表示所有不同进制的数字
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'
};
/**
* DigitTens和DigitOnes两个数组主要用于获取0到99之间某个数的十位和个位字符,
* 比如48,通过DigitTens数组直接取出来十位为4,而通过DigitOnes数组取出来个位为8
*/
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',
} ;
/**
* sizeTable数组主要用在判断一个int型数字(只能判断正数)对应字符串的长度。比如相关的方法如下,这种方法可以高效得到对应字符串长度,避免了使用除法或求余等操作
* jdk8中并没有使用这个数组,直接用的while循环计算,正负数都可以判断,返回长度算上了符号长度,即-1的长度是2
* static int stringSize(int x) {
* for (int i=0; ; i++)
* if (x <= sizeTable[i])
* return i+1; //直接通过判断返回长度
* }
*/
static final int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, java.lang.Integer.MAX_VALUE };
2 toString方法(重点,需要用到上面三个byte矩阵数组)
//实例方法
public String toString() {
return toString(value);
}
/**
* 返回第一个参数的字符串形式,第二个参数为进制的基数,二进制10进制十六进制等
*/
public static String toString(int i, int radix) {
//如果基数小于2或者大于36,则默认使用10进制转换
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
//返回int类型参数十进制形式字符串
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;
}
/**
* 按进制处理,求余digits从获取对应字符串,比如 -15转为16进制 -15 % 16 = 15 ,digits 中15 为 f
*/
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);
}
/**
* 返回int类型参数十进制形式字符串
*/
public static String toString(int i) {
int size = stringSize(i);
if (COMPACT_STRINGS) { //jvm是否开启字符串压缩
byte[] buf = new byte[size];
getChars(i, size, buf); //将int参数字符串放入byte数组中
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[size * 2];
StringUTF16.getChars(i, size, buf);// 思路与上面getChars一样,放进数组的时候会进行高低位两个byte放
return new String(buf, UTF16);
}
}
//返回给定int值的字符串表示长度
static int stringSize(int x) {
int d = 1;
if (x >= 0) {
d = 0;
x = -x; //整数改为负数,统一用负数判断大小
}
int p = -10;//判断大小基数,大于-10,一位,否则再判断大于-100,两位等
for (int i = 1; i < 10; i++) { // 判断9次
if (x > p)
return i + d;
p = 10 * p;
}
return 10 + d; //超过九位数,返回int最大的长度,10或者11位
}
//将int参数字符串放入byte数组中
static int getChars(int i, int index, byte[] buf) {
int q, r;
int charPos = index; //数组开始位置坐标,传入的是数组大小,从 --index 最后一位往前添加数据
boolean negative = i < 0;
if (!negative) { //正数转化为负数
i = -i;
}
/**
* 每次取后两位数,将最后两位字符添加到数组中,比如: -2358
* q=-23 整数相除,结果都为整数
* r=-2300-(-2358)=58
* 从DigitOnes和DigitTens中找出第58个字符,即8和5依次加入数组中
*/
while (i <= -100) {
q = i / 100;
r = (q * 100) - i;
i = q; // 每次增大100,即去掉后两位数,继续循环处理,直到成为两位数以内
buf[--charPos] = DigitOnes[r];
buf[--charPos] = DigitTens[r];
}
// 处理剩余的两位数,比如: -23 q=-2, r= 3
q = i / 10;
r = (q * 10) - i;
buf[--charPos] = (byte)('0' + r); // 转换为byte存储
if (q < 0) {
buf[--charPos] = (byte)('0' - q);
}
//处理符号位
if (negative) {
buf[--charPos] = (byte)'-';
}
return charPos;
}
//按照一个字符占用两个byte处理
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;
}
//按进制处理,求余digits从获取对应字符串,比如 -15转为16进制 -15 % 16 = 15 ,digits 中15 为 f
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));
}
3 to系列其他方法
//1.8新增方法,返回无符号参数int的十进制字符串,注意: 两个新增方法实现逻辑都在Long类中,Unsigned方法参数如果是有符号的(即负数),结果都会有问题
public static String toUnsignedString(int i) {
return Long.toString(toUnsignedLong(i));
}
/**
* 将无符号int转换为long类型,负数不报错结果不正确
* @since 1.8
*/
public static long toUnsignedLong(int x) { return ((long) x) & 0xffffffffL; }
//1.8新增方法: 根据进制基数,返回无符号int参数号的字符串形式,新增方法,功能与下面三种方法一样,只不过还支持10进制等进制
public static String toUnsignedString(int i, int radix) {
return Long.toUnsignedString(toUnsignedLong(i), radix);
}
// 转换为16进制字符串
public static String toHexString(int i) {
return toUnsignedString0(i, 4);
}
// 转换为8进制字符串
public static String toOctalString(int i) {
return toUnsignedString0(i, 3);
}
// 转换为2进制字符串
public static String toBinaryString(int i) {
return toUnsignedString0(i, 1);
}
// 将无符号整数转换为String,私有方法,只支持2,8,16三种进制转换, 负数不报错但结果不正确
private static String toUnsignedString0(int val, int shift) {
/**
* 32减去numberOfLeadingZeros, 表示实际表示此数字只需要的位数。
* 比如10的二进制补码是0000 0000 0000 0000 0000 0000 0000 1010,
* 它实际只需要1010这4位数字就可以代表10. 所以10的mag就是4
*/
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
/**
* 表示转换成byte数组所需要的长度,
* 其中shift的值1-二进制,3-八进制,4-十六进制。比
* 如10的mag是4,如果要转成二进制shift=1,则chars=4,因为需要长度为4的字符数组来存放1010。
* 如果要转成16进制a,则shift=4,得出chars=1,因为只需要长度为1的字符串数组来存放结果a.
*/
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
if (COMPACT_STRINGS) {
byte[] buf = new byte[chars];
//将int值转化为对应进制的字符形式添加到buf数组中
formatUnsignedInt(val, shift, buf, 0, chars);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[chars * 2];
formatUnsignedIntUTF16(val, shift, buf, 0, chars);
return new String(buf, UTF16);
}
}
/**
获取int值补码形式前面的0的个数,0返回32,负数返回0
该方法返回i的二进制从头开始有多少个0。i为0的话则有32个0。
这里处理其实是体现了二分查找思想的,先看高16位是否为0,是的话则至少有16个0,否则左移16位继续往下判断,
接着右移24位看是不是为0,是的话则至少有16+8=24个0,直到最后得到结果。
*/
public static int numberOfLeadingZeros(int i) {
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);// 返回二进制补码前面0的个数
}
//将int值转化为对应进制的字符形式添加到buf数组中
static void formatUnsignedInt(int val, int shift, byte[] buf, int offset, int len) {
/**
* 二进制,因为2的1次方是2,所以shift就是1,那么radix就是1左移1位得到2,mask就是1,对应的二进制就是1;
* 八进制,因为2的3次方是8,所以shift就是3,那么radix就是1左移3位得到8,mask就是7,对应的二进制就是111;
* 十六进制,因为2的4次方是16,所以shift就是4,那么radix就是1左移4位得到16,mask就是15,对应的二进制就是1111;
*/
int charPos = offset + len;
int radix = 1 << shift;
int mask = radix - 1; //掩码
/**
* 十进制数如果是转换成八进制或十六进制这种进制数为2的整数次方的进制,有更快的算法,就是先得到二进制,然后每几位一组转换。
* 比如要把19转换成八进制:
* 先把19转成二进制,也就是10011;
* 因为8是2的3次方,所以把10011从低位开始每3位一组划分,也就是10 011;
* 把10 011按每一组转为八进制,也就是2 3,所以19的八进制表示就是23。
*
* 循环val & mask 与运算的过程就像分组转换的过程,每次循环可以将mask对应的位数得到,再利用digits数组转换成对应的字符,这个字符就是这次分组的这几位所对应的结果,
* 每次分组得到结果以后把val右移相应的位数,继续下一轮的循环分组。
*
* 比如val为19,shift为3,radix为8,mask为7。
* 第一次循环:19 & 7 就是10011 & 111,结果为11,也就是3,通过digits数组得到这一位字符为3。然后10011右移3位,得到val为10。
* 第二次循环:10 & 111,结果为10,也就是2,通过digits数组得到这一位字符为2。然后10右移3位,得到val为0,循环结束。
* 最终结果就是23。
*/
do {
buf[--charPos] = (byte) Integer.digits[val & mask]; //分组转化算法思想
val >>>= shift;
} while (charPos > offset);
}
//使用两个byte存储字符形式添加
private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {
int charPos = offset + len;
int radix = 1 << shift;
int mask = radix - 1;
do {
StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]);
val >>>= shift;
} while (charPos > offset);
}
4 parse系列方法
//解析十进制的字符串形式数字并返回int值
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
/**
* 将对应进制的字符串形式转化为十进制int返回,
* 比如: Integer.parseInt("10",16) = 16
*/
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"); }
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);
}
if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
}
i++;
}
int multmin = limit / radix;
int result = 0;
while (i < len) {//循环计算每一位值
//根据Character类获取当前对应字符对应进制的数字
int digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix; //乘进制数转换为十进制数结果
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s);
}
}
/**
* @since 1.8 将无符号的十进制字符串形式解析为int, 负数字符串形式会直接抛异常
*/
public static int parseUnsignedInt(String s) throws NumberFormatException {
return parseUnsignedInt(s, 10);
}
/**
* @since 1.8 将对应进制的无符号字符串解析为int. 注意: "-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); //调用parseInt方法
} 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);
}
}
/**
* 将对应进制的无符号CharSequence解析为int. 注意: "-10" 这种负数字符串形式会直接抛异常
* 即可以使用StringBuffer等参数,逻辑与上面String参数是一样的
* @since 9
*/
public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix)
throws NumberFormatException {
s = Objects.requireNonNull(s);
if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
throw new IndexOutOfBoundsException();
}
int start = beginIndex, len = endIndex - beginIndex;
if (len > 0) {
char firstChar = s.charAt(start);
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, start, start + len, radix);
} else {
long ell = Long.parseLong(s, start, start + len, 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 new NumberFormatException("");
}
}
/**
* 解析CharSequence为int,根据指定起始位置和进制数,即可以使用StringBuffer等参数,逻辑与上面String参数是一样的
* @since 9
*/
public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
throws NumberFormatException {
s = Objects.requireNonNull(s);
if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
throw new IndexOutOfBoundsException();
}
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 = beginIndex;
int limit = -Integer.MAX_VALUE;
if (i < endIndex) {
char firstChar = s.charAt(i);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = java.lang.Integer.MIN_VALUE;
} else if (firstChar != '+') {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
i++;
if (i == endIndex) { // Cannot have lone "+" or "-"
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
}
int multmin = limit / radix;
int result = 0;
while (i < endIndex) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
i++;
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString("");
}
}
5 valueOf系列方法与静态内部缓存类
/**
* 静态内部类: 把-128~最大边界(默认是127)的数字缓存起来了,用于提升性能和节省内存
* 最大边界可以通过-XX:AutoBoxCacheMax进行配置
*/
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 =
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 Integer.IntegerCache.high >= 127;
}
//构造器私有,保护数据
private IntegerCache() {}
}
// 根据int返回Integer对象
public static Integer valueOf(int i) {
//如果在-128-high缓存区间内,则返回缓存里的对象,即区间内用valueOf返回的对象都是同一个,相等的
if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high)
return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)];
return new Integer(i);
}
// 根据字符串和进制基数构造Integer对象并返回
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
// 根据String返回十进制Integer对象
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
7 getInteger和比较,hashCode等方法
//Integer hash值是其value
@Override
public int hashCode() {
return Integer.hashCode(value);
}
public static int hashCode(int value) {
return value;
}
//比较value的int值是否相等,如果两个Integer的值应该用这个方法,而不是 ==
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
/**
* Integer.getInteger(String)方法假设String参数是一个系统属性数值的名称,会读取该系统属性,
* 然后把系统属性的值转换成一个数字。当我们调用Integer.getInteger("521") 应该是得到 null(系统默认肯定没有521的系统属性)。
*
* 常见的系统属性
* 在JDK文档中System类中有这样的方法getProperties()在此方法的详细介绍中有下面的参数可供使用:
* java.version Java 运行时环境版本
* java.vendor Java 运行时环境供应商
* java.vendor.url Java 供应商的 URL
* java.home Java 安装目录
* 当启动JVM时,请使用System.setProperty或使用-Dname = value标志
*/
public static Integer getInteger(String nm) {
return getInteger(nm, null);
}
public static Integer getInteger(String nm, int val) {
Integer result = getInteger(nm, null);
return (result == null) ? Integer.valueOf(val) : result;
}
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;
}
/**
* ecode合适用来分析数字
* 可以分析
* 8进:010=>分析后为 8
* 10进:10=>分析后为 10
* 16进:#10|0X10|0x10=>分析后是 16
* 而valueof 只能分析纯数字的String
* 像 010 这样的8进制 他会解析成 =>10
*/
public static Integer decode(String nm) throws NumberFormatException {
int radix = 10;
int index = 0;
boolean negative = false;
Integer result;
if (nm.length() == 0)
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;
}
/**
* 比较value值
*/
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
//比较两个int大小
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
/**
* 将两个数视为无符号比较,此时如果参数中不同号,结果会相反,同号的结果与compare()相同
* ,任意一个参数如果有负数,加上MIN_VALUE,值会变成最大值
*/
public static int compareUnsigned(int x, int y) {
return compare(x + MIN_VALUE, y + MIN_VALUE);
}
8 数学计算方法(重点,很多算法思想)
/**
* 返回i的二进制中最高位的1,其他全为0的值。
* 比如i=10时,二进制即为1010,最高位的1,其他为0,则是1000
* MIN_VALUE = 0x80000000 = 10000000000000000000000000000000 最高为1其他位为0 ,右移i的左边0的个数为得到i的最高位为1其他位为0的值,再 & 得到结果
* >>>: 无符号右移,不管正负高位都补0
*/
public static int highestOneBit(int i) {
return i & (MIN_VALUE >>> numberOfLeadingZeros(i));
}
/**
* 获取int值补码形式前面的0的个数,0返回32,负数返回0
* 该方法返回i的二进制从头开始有多少个0。i为0的话则有32个0。
* 这里处理其实是体现了二分查找思想的,先看高16位是否为0,是的话则至少有16个0,否则左移16位继续往下判断,
* 接着右移24位看是不是为0,是的话则至少有16+8=24个0,直到最后得到结果。
*/
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);
}
/**
* 与highestOneBit方法对应,lowestOneBit获取最低位1,其他全为0的值。
* 先取负数,得到的结果和i进行与操作,即 原码 & 补码 结果刚好是加的那个1
*/
public static int lowestOneBit(int i) {
return i & -i;
}
/**
* 该方法主要用于计算二进制数中1的个数。
* 先将重要的列出来,
* 0x55555555等于01010101010101010101010101010101,
* 0x33333333等于00110011001100110011001100110011,
* 0x0f0f0f0f等于00001111000011110000111100001111。
* 0x3f等于00000000000000000000000000111111
* 核心思想就是先每两位一组统计看有多少个1,比如10011111则每两位有1、1、2、2个1,记为01011010,
* 然后再算每四位一组看有多少个1,而01011010则每四位有2、4个1,记为00100100,
* 接着每8位一组就为00000110,接着16位,32位,最终在与0x3f进行与运算,得到的数即为1的个数
* 分治思想
*/
public static int bitCount(int i) {
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;
}
/**
* 该方法即是将i进行反转,反转就是第1位与第32位对调,第二位与第31位对调,以此类推。
* 核心思想是先将相邻两位进行对换,比如10100111对换为0101 1011,接着再将相邻四位两两进行对换,对换后为1010 1101,
* 接着将相邻八位四四进行对换,最后字节对换,即把32位中间的16位对换,然后最高8位再和最低8位对换。
* 用到了典型的分治思想,先将每个字节(8位)自己全部反转,然后再将四个字节进行反转,可能开始看有点绕,下面逻辑详细分析一下:
* 比如现在有一个32位: 标记前8位数字为 1 2 3 4 5 6 7 8
* 第一次相邻对换后为: 2 1 4 3 6 5 8 7
* 第二次相邻四个再两两对换: 4 3 2 1 8 7 6 5
* 第三次相邻8个再四四对换: 8 7 6 5 4 3 2 1 刚好完成每个字节中的对换
* 然后把32位四个字节进行对换得到结果,其中 1 刚好到了最后32位,以此类推
*/
public static int reverse(int i) {
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
return reverseBytes(i);
}
/**
* 反转指定int值的字节数得到的值,即int 四个字节,第一个字节和最后一个字节调换位置,第二个和第三个调换位置
* 核心思想: 将指定字节移动到指定位置,其他位置都置为0,然后|得出结果,
*/
public static int reverseBytes(int i) {
return (i << 24) | //左移24位,第四个字节移动到第一字节位置,后面全部补0
((i & 0xff00) << 8) | // 0xff00= 00000000 00000000 11111111 00000000 , 获取第三个字节并移动八位到第二个字节,其他位置全部为0
((i >>> 8) & 0xff00) | // 无符号右移8位,第二字节移动到第三字节位置并 & 运算获取第三字节,其他位为0
(i >>> 24); // 无符号右移24位,第一字节移动到第四字节位置,其他位为0, 全部 | 运算即为反转后的值
}
/**
* 循环移位: 就是把数值变成二进制,然后循环移动的过程;
* 换句话说,循环移位就是将移出的低位放到该数的高位(循环右移)或把移出的高位放到该数的低位(循环左移)
* 比如: -2 10000000000000000000000000000010 补码为: 111111111111111111111111111111110
* 左移2位,即把最高的两位 11 -> 放到低位右边为 11111111111111111111111111111011 = -5
* 核心思想就是把左移或者右移的几位数(左移后面补零,右移前面补零),再通过右移或者左移到最后面或者最前面几位,然后一与(都是0,原来是什么就会得到什么结果)
* 比如 -2 前面的 11 通过 >>> -2 (右移30位,移到最后面,刚好是左移补的零,达到循环)
* 11 111111111111111111111111111000
* 000000000000000000000000000000 11 |
* 11111111111111111111111111111011
*/
public static int rotateLeft(int i, int distance) {//左移
return (i << distance) | (i >>> -distance);
}
public static int rotateRight(int i, int distance) {//右移
return (i >>> distance) | (i << -distance);
}
/**
* 正数返回1,负数返回-1,0返回0
*/
public static int signum(int i) {
return (i >> 31) | (-i >>> 31);
}
//@since 1.8 无符号除法
public static int divideUnsigned(int dividend, int divisor) {
return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
}
//@since 1.8 无符号求余数
public static int remainderUnsigned(int dividend, int divisor) {
return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
}
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对象相等问题
@Test
public void test01(){
Integer a=127;
Integer b=127;
System.out.println(a==b);// true 自动装箱会使用缓存中同一个对象
Integer d=new Integer(127);
Integer e=new Integer(127);
System.out.println(d==e); // false 使用new每次都是一个新对象
Integer f=Integer.valueOf(127);
Integer n=Integer.valueOf(127);
System.out.println(f==n); // true valueOf方法会使用缓存中的对象 [-128,hign(默认127)] 之间都是同一个对象
Integer c=129;
System.out.println(a==c); // false 不同对象
System.out.println(a==b.intValue()); //true Integer会拆箱转为int,进行比较数值
System.out.println(a.equals(b)); //true 比较基本数值的值
}
四 Long类源码分析
Long类源码逻辑跟Integer基本差不多,好多API都是一样的,可对照Integer阅读即可!,这里就不贴详细分析了!
JDK源码之Integer类分析的更多相关文章
- JDK源码之Byte类分析
一 简介 byte,即字节,由8位的二进制组成.在Java中,byte类型的数据是8位带符号的二进制数,以二进制补码表示的整数 取值范围:默认值为0,最小值为-128(-2^7);最大值是127(2^ ...
- JDK源码之Boolean类分析
一 简介 boolean类型的封装类,将基本类型为boolean的值包装在一个对象中,实现序列化接口,和Comparable接口 额外提供了许多便捷方法,比较简单,直接贴代码分析 二 源码分析 //t ...
- JDK源码之AbstractStringBuilder类分析
一 概述 二 实现接口 AbstractStringBuilder实现了两个接口: Appendable 概述: Appendable的实现类的对象可以附加字符序列和值. 要追加的字符应该是Unico ...
- JDK源码之Double类&Float类分析
一 概述 Double 类是基本类型double的包装类,fainl修饰,在对象中包装了一个基本类型double的值.Double继承了Number抽象类,具有了转化为基本double类型的功能. 此 ...
- JDK源码之String类解析
一 概述 String由final修饰,是不可变类,即String对象也是不可变对象.这意味着当修改一个String对象的内容时,JVM不会改变原来的对象,而是生成一个新的String对象 主要考虑以 ...
- [Android FrameWork 6.0源码学习] LayoutInflater 类分析
LayoutInflater是用来解析XML布局文件,然后生成对象的ViewTree的工具类.是这个工具类的存在,才能让我们写起Layout来那么省劲. 我们接下来进去刨析,看看里边的奥秘 //调用i ...
- jdk源码理解-String类
String类的理解 简记录一下对于jdk的学习,做一下记录,会持续补充,不断学习,加油 1.String的hash值的计算方法. hash值的计算方法多种多样,jdk中String的计算方法如下,比 ...
- JDK源码阅读-Integer
先上一版字符串转数值的几个方法的区别 parseInt(String s),解析字符串数,10进制,返回int parseInt(String s, int radix),解析字符串数,radix为指 ...
- jdk源码阅读-Object类
native 关键字 private static native void registerNatives(); static { registerNatives(); } public final ...
随机推荐
- vue学习笔记(四)事件处理器
前言 在上一章vue学习笔记(三)class和style绑定的内容中,我们学习了如何在vue中绑定class和style,介绍了常用的绑定方法,class的数组绑定和对象绑定以及style的数组绑定和 ...
- 洛谷$P2046\ [NOI2010]$海拔 网络流+对偶图
正解:网络流+对偶图 解题报告: 传送门$QwQ$ $umm$之前省选前集训的时候叶佬考过?然而这和我依然不会做有什么关系呢$kk$ 昂这题首先要两个结论?第一个是说每个位置的海拔一定是0/1,还一个 ...
- $[SHOI2007]$ 园丁的烦恼 二维数点/树状数组
\(Sol\) 设一个矩阵的左上角为\((x_1,y_1)\),右下角为\((x_2,y_2)\),\(s_{x,y}\)是到\((1,1)\)二维前缀和,那么这个矩阵的答案显然是\(s_{x_2,y ...
- JVM探秘:内存溢出
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. 在 Java 虚拟机内存区域中,除了程序计数器外,其他几个内存区域都可能会发生OutO ...
- CSRF绕过后端Referer校验
CSRF绕过后端Referer校验分正常情况和不正常的情况,我们这里主要讨论开发在写校验referer程序时,不正常的情况下怎么进行绕过. 正常情况 正常的情况指服务器端校验Referer的代码没毛病 ...
- 解决 Table ‘performance_schema.session_variables’ doesn’t exist 问题
performance_schema在mysql5.5以上就有自带 performance_schema(安装数据库时自带的)如果装数据库或者使用数据时不小心删除了,就会出现Table‘perform ...
- 2020 年 Java 程序员应该学习什么?
大家好,我相信大家在新的一年都有一个良好的开端,并准备好制定一个提升自我技术的目标.作为 Java 开发人员,我还制定了一些目标,希望在今年成为一名更好的 Java 开发人员. 如果你尚未制定目标,这 ...
- kubespy 用bash实现的k8s动态调试工具
原文位于 https://github.com/huazhihao/kubespy/blob/master/implement-a-k8s-debug-plugin-in-bash.md 背景 Kub ...
- FUTABA舵机参数大全
S9150 Digital servo 尺寸:47.5X27X25.3mm 重量:53g 速度:0.18sec/60"(4.8V) 扭力:5.8kg:cm(4.8V) ——————————— ...
- 学习集合Collection_通用方法
Collection 常用接口 集合List和Set通用的方法 public boolean add(E e) 添加对象到集合 public boolean remove(E e) 删除指定元素 pu ...