JDK版本
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
不同的版本的实现可能会有些差异。
类定义
public final class Integer extends Number implements Comparable<Integer>
- 父类为
Number
,主要是一些类型转换的方法。 - 实现接口为
Comparable
,主要是Integer对象之间进行比较的方法。
属性
这里只列出了部分属性,其他属性在讲到具体方法时会列出。
//整型最小值
@Native public static final int MIN_VALUE = 0x80000000;
//整型最大值
@Native public static final int MAX_VALUE = 0x7fffffff;
//该包装类对应的基本类型
@SuppressWarnings("unchecked")
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
//digits数组为根据不同基数将整数转换为字符时,可能出现的数值。比如说16进制可能出现的字符为0~e。
final static 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为辅助数组,在getChars(int i, int index, char[] buf)方法中使用
final static char [] 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',
} ;
final static char [] 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',
} ;
toString相关方法
toString相关方法用于将给定整数转换为字符串。
toString(int i, int radix)方法
该方法根据基数radix,将整数i转换为字符串
public static String toString(int i, int radix) {
/**
* Character中保存着基数的范围,Character.MIN_RADIX=2,
* Character.MAX_RADIX=36,在这个范围之外的基数是非法的,
* 默认基数为10。
*/
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
//如果基数是10,直接采用Integer的toString(int i)方法进行转换
if (radix == 10) {
return toString(i);
}
/**
* Java中一个整型为4个字节,即32位,当基数为2时,能够转换得到最大
* 的字符串11111111111111111111111111111111,再加上负数需要负号,
* 故分配长度为33的字符数组用来临时存储转换得到的字符。
*/
char buf[] = new char[33];
//判断是否为负数
boolean negative = (i < 0);
//从末尾开始存放转换后得到的字符,数组从0开始,故从32开始存放
int charPos = 32;
/**
* 如果不是负数,将其转换为负数进行处理。个人认为之所以要转换为负数,
* 主要是为了统一进行处理,而无需分别对正负数进行处理。Java中整型的
* 范围为-2147483648~2147483647。如果统一用正数进行处理,当i为最小值
* -2147483648时,无对应的正数2147483648可进行操作。如果统一用负数进
* 行处理,当i为最大值2147483647,有相应的负数-2147483647可进行操作。
*/
if (!negative) {
i = -i;
}
while (i <= -radix) {
//根据取余得到的值从上述属性中的digits数组中获取字符
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];
//根据是否为负数加上负号
if (negative) {
buf[--charPos] = '-';
}
//获取起始位置和实际字符长度,由字符数组生成字符串
return new String(buf, charPos, (33 - charPos));
}
toString(int i)方法
该方法根据给定的整数返回相应的字符串,默认基数为10。
public static String toString(int i) {
//如果i是最小值,直接返回相应字符串,因为其无法进行之后的-i操作
if (i == Integer.MIN_VALUE)
return "-2147483648";
/**
* 使用Integer的stringSize(int x)获取i转换为字符串后的字符数,该
* 方法要求传入的数为整数。对于负数来说,还需要负号这个字符,故需
* 要stringSize(-i) + 1,获得实际字符数。
*/
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
/* 使用Integer的getChars(int i, int index, char[] buf)获取整数i转
* 换为字符串的字符数组buf。
*/
getChars(i, size, buf);
return new String(buf, true);
}
stringSize(int x)方法
该方法用于获取整数i有多少位,要求整数i必须为非负数。比如输入10,将返回2;输入100,将返回3。
//sizeTable数组为辅助数组,用于辅助stringSize(int x)方法的实现
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
/**
* 根据给定的正整数x获取其位数,使用辅助数组sizeTable来完成操作。思路是从小
* 到大与sizeTable进行比较。当x小于9时,肯定只有一位;否则与99相比,小于99的
* 话,肯定只有两位,依次类推。
*/
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
getChars(int i, int index, char[] buf)方法
该方法将整数i的每一位转换为字符存放到字符数组buf中,index表示该整数将占用的字符数组长度。
//DigitTens和DigitOnes为辅助数组,用于辅助getChars(int i, int index, char[] buf)方法的实现
final static char [] 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',
} ;
final static char [] 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',
} ;
static void getChars(int i, int index, char[] buf) {
int q, r;
//charPos用来指示当前得到的字符的存放位置
int charPos = index;
//sign用于标记正负数
char sign = 0;
/**
* 将整数i统一转换为正数进行处理,方便进行位操作。此时必须保证整数i
* 不为最小值,以防溢出。
*/
if (i < 0) {
sign = '-';
i = -i;
}
/**
* 当i大于等于65536时,每次获取i的最后两位存放到字符数组中,选用65536
* 的原因见之后解释。
*/
while (i >= 65536) {
/**
* q保存除去最后两位后剩下的数值。这里之所以不用乘法加移位操作来替
* 代除法操作,主要是因为一个较大的数进行乘法操作容易溢出。
*/
q = i / 100;
/**
* 实际上是进行r = i - (q * 100)的操作。i每左移一位,等同于i乘二。
* 故q<<6等同于q*2^6,即q*64。故(q << 6) + (q << 5) + (q << 2)等同于
* q*64+q*32+q*4,即q*100。此时r保存i的最后两位。采用移位操作的原因是
* 移位操作的效率比使用乘法的效率高。
*/
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
/**
* 这里借助字符数组DigitOnes和字符数组DigitTens来获取这两位上的字符。
* DigitOnes能根据r获取个位上的字符,DigitTens能根据r获取十位上的字符。
*/
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}
//当i小于65536时,每次获取i的最后一位存放到字符数组中
for (;;) {
/**
* 实际上是进行r=i/10操作,即r=i*0.1的操作。i每无符号右移移位,等同于i
* 除以2。故(i * 52429) >>> (16+3)等同于i*52429/2^19,即i*52429/524288,
* 相当于r=i*0.1。采用乘法和移位操作等原因是移位操作的效率比使用乘法的
* 效率高,使用乘法的效率又比使用除法的效率高。选用52429和16+3的原因见
* 之后解释。
*/
q = (i * 52429) >>> (16+3);
// 实际上是进行r = i-(q*10)操作,解释同上,此时r保存i的最后一位。
r = i - ((q << 3) + (q << 1));
//借助字符数组digits根据r来获取字符。
buf [--charPos] = digits [r];
i = q;
if (i == 0) break;
}
//判断是否需要添加负号
if (sign != 0) {
buf [--charPos] = sign;
}
}
要使整数a和整数b进行a>>>b的操作结果最接近0.1,应该有
a=2b/10+1
a
=
2
b
/
10
+
1
。
(1)当b取10时,有2^10=1024, 103/1024=0.1005859375。
(2)当b取11时,有2^11=2048, 205/2048=0.10009765625。
(3)当b取12时,有2^12=4096, 410/4096=0.10009765625。
可以看出,当b越大时,a越大,进行q=(i*a)>>>b操作时,为避免i*a操作溢出,a的 值也不是越大越好。我认为这里主要是从效率和精确度两个角度综合考虑,使用65536将其分为两部分操作:第一部分使用了除法,但一次性获取了两位;第二部分虽然一次只获取了一位, 但使用了乘法和位操作,从而避免了除法操作。
toHexString(int i)、toOctalString(int i)、toBinaryString(int i)
这三个方法的功能和实现类似,都是将整数i以16进制、8进制、2进制的字符串形式表示出来。
/**
* 返回一个整数参数的字符串表示形式在基数为16的无符号整数,使用Integer的
* toUnsignedString0(int val, int shift)方法实现。
*/
public static String toHexString(int i) {
return toUnsignedString0(i, 4);
}
/**
* 返回一个整数参数的字符串表示形式在基数为8的无符号整数,使用Integer的
* toUnsignedString0(int val, int shift)方法实现。
*/
public static String toOctalString(int i) {
return toUnsignedString0(i, 3);
}
/**
* 返回一个整数参数的字符串表示形式在基数为2的无符号整数,使用Integer的
* toUnsignedString0(int val, int shift)方法实现。
*/
public static String toBinaryString(int i) {
return toUnsignedString0(i, 1);
}
toUnsignedString0(int val, int shift)方法
该方法将给定的无符号整数val,根据shift,转换为相对应的字符串,使用Integer的formatUnsignedInt(int val, int shift, char[] buf, int offset, int len)
实现。 shift参数就我个人理解,作用于radix相似。它指的是将二进制中的多少位作为一位,比如2进制则每1位作为一位,shift的值为1;8进制则每3位作为一位,shift的值为3;16进制则将每4位作为一位,shift的值为4。可以说,基数
radix=2shift
r
a
d
i
x
=
2
s
h
i
f
t
。
private static String toUnsignedString0(int val, int shift) {
//计算给定的数的二进制表示形式的实际有效位数,numberOfLeadingZeros方法在后面会解释
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
//计算给定的数根据shift进行转换后,实际所需要占用的字节数
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
char[] buf = new char[chars];
//给定整数val,根据shift转换为字符数组
formatUnsignedInt(val, shift, buf, 0, chars);
return new String(buf, true);
}
formatUnsignedInt(int val, int shift, char[] buf, int offset, int len)
该方法根据给定的整数val和shift,将其转换为字符串存放在字符数组buf中,offset为buf中开始存放的位置,len为需要存储的字符数。
static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
int charPos = len;
int radix = 1 << shift;
/**
* mask为掩码,表示将多少位作为1位。比如shift为3时,radix为8,相应的mask的值为7,
* 其二进制形式为111,进行与操作可以得到3位。
*/
int mask = radix - 1;
do {
/**
* 通过val&mask每次可以得到val后三位所表示的数值,通过Integer的digits字符数组
* 可以获取相应的数值所对应的字符。
*/
buf[offset + --charPos] = Integer.digits[val & mask];
//最低3位已转换为相应的字符,右移3位,继续进行转换
val >>>= shift;
} while (val != 0 && charPos > 0);
return charPos;
}
parseInt相关方法
parseInt相关方法和toString相关方法相反,用于将给定的字符串转换为整数。
parseInt(String s, int radix)方法
该方法根据给定的字符串s和该字符串的基数radix,将其转换为相应的以10为基数的整数,该方法将忽略正号和前导零。
public static int parseInt(String s, int radix)
throws NumberFormatException
{
//字符串为null,抛出异常
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;
//i用于存放当前解析到的位置,该方法从字符的左端向右端进行处理
int i = 0, len = s.length();
/**
* 数值限制,由于统一转换为负数处理,故使用-Integer.MAX_VALUE用于限制
* result所得到的值不能小于该值。
*/
int limit = -Integer.MAX_VALUE;
/**
* multmin也是一个限制,主要是用于判断该字符串进行转换后是否会溢出,具体
* 解释见下面。
*/
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
//若小于字符0,则可能是正负号
if (firstChar < '0') {
//若是负号,设置负数标准和限制数值
if (firstChar == '-') {
negative = true;
//若为负数,设置限制为Integer.MIN_VALUE
limit = Integer.MIN_VALUE;
//若还不是正号,则只能是非法字符,抛出异常
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
//如果只有符号位,抛出异常
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
//设置multmin的值
multmin = limit / radix;
while (i < len) {
//使用Charcter的digit方法获取当前字符在基数radix下所对应的数值
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
//非法数值,即非法字符,抛出异常
throw NumberFormatException.forInputString(s);
}
//使用小于进行比较,是因为统一使用了负数进行处理
if (result < multmin) {
/**
* 当result<multmin时,假设result=multmin-n,其中n为任意正整数,
* 那么当进行result *= radix操作时,相当于result=(multmin-n)*radix,
* 相当于result=(limit/radix-n)*radix,相当于result=limit-n*radix,
* 由于limit为限制的最小数值,故此时result的结果必然溢出。
*/
throw NumberFormatException.forInputString(s);
}
result *= radix;
/**
* 相当于result-digit<limit,注意是result-digit,因为统一使用了负数进行处理,
* 由于limit为限制的最小数值,故此时result-digit的结果必然溢出。
*/
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
//统一使用负数处理,故使用减法
result -= digit;
}
} else {
//字符串长度为0直接抛出异常
throw NumberFormatException.forInputString(s);
}
//根据负号标志判断是否要转换为正数
return negative ? result : -result;
}
parseInt(String s)方法
该方法根据给定的字符串s,默认该字符串对应的基数为10,将其转换为相应的以10为基数的整数,该方法将忽略正号和前导零。使用Integer的parseInt(String s, int radix)方法实现。
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
parseUnsignedInt(String s, int radix)方法
该方法类似于Integer的parseInt(String s, int radix)方法,但字符串s代表的为无符号数。注意Java中是没有无符号数的,该方法中大于整数最大值的字符串其实使用long类型来计算的, 然后再将其转换为int类型。Java中其实没有无符号数,这里所说的无符号数是相对的。通过使用负数来表示一部分的无符号数,此时负数的符号位视为有效数值,所以说是否为无符号数,主要在于使用者如何看待负数
。比如说传入字符串2147483648
,这是超过有符号整数范围,却在无符号整数范围内的数,输出结果为负数-2147483648
。但从无符号数的角度看,将其二进制形式的符号位视为有效数值的话,-2147483648
代表的就是无符号整数2147483648
。
public static int parseUnsignedInt(String s, int radix)
throws NumberFormatException {
if (s == null) {
//字符串为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 || //整数最大值在最大基数下长度只有6,可以在有符号数的范围内处理
(radix == 10 && len <= 9) ) { //整数最大值在十进制下长度只有10,可以在有符号数的范围内处理
return parseInt(s, radix);
} else {
//超过有符号整数可以计算的范围,转换为Long类型进行处理
long ell = Long.parseLong(s, radix);
//判断转换后的数值是否在无符号整数的范围内,如果不在的话,高32位有非0数值,相与不为0
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);
}
}
parseUnsignedInt(String s)方法
该方法类似于Integer的parseInt(String s)方法,但字符串s代表的为无符号数,默认使用基数10。
public static int parseUnsignedInt(String s) throws NumberFormatException {
return parseUnsignedInt(s, 10);
}
valueOf相关方法
valueOf相关方法类似parseInt相关方法,但parseInt相关方法得到的是整数基本类型,该方法得到的是整数的包装类。
IntegerCache缓存
valueOf相关方法的实现与IntegerCache相关。IntegerCache是Integer类中一个私有的静态类,用来为Integer提供缓存和重用,从而节省内存和提高性能。
private static class IntegerCache {
//IntegerCache缓存的最小值
static final int low = -128;
//IntegerCache缓存的最大值
static final int high;
//缓存
static final Integer cache[];
static {
//设置IntegerCache缓存的最大值
int h = 127;
//获取Java程序运行时设置的IntegerCache缓存的最大值
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
//若设置的IntegerCache缓存的最大值小于127,则仍然使用127
i = Math.max(i, 127);
/**
* 数组的长度是有限制的,数组的length属性是int类型的,故数组的最大长度
* 为Integer.MAX_VALUE。而cache数组的长度是由low和high决定的,故high的
* 最大值只能是Integer.MAX_VALUE-(-low)-1。
*/
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
//获取Java程序运行时设置的IntegerCache缓存的最大值无法解析则忽视
}
}
high = h;
//使用low和hight确定数组长度
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
//初始化数组,其中的值为low到hight范围之间的值
cache[k] = new Integer(j++);
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
从中可以看出,默认情况下缓存0~127整数的包装类对象。
valueOf(int i)方法
该方法根据传入的整数i,获取其包装类型对象。
public static Integer valueOf(int i) {
//假如整数i在IntegerCache缓存的范围内,直接返回缓存数组中的值
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
valueOf(String s, int radix)方法
该方法类似parseInt(String s, int radix)方法,但parseInt(String s, int radix)方法得到的是整数基本类型,该方法得到的是整数的包装类。使用Integer的 parseInt(String s, int radix)方法和valueOf(int i)方法实现。
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
valueOf(String s)方法
该方法类似parseInt(String s)方法,但parseInt(String s, int radix)方法得到的是整数基本类型,该方法得到的是整数的包装类。使用Integer的parseInt(String s, int radix)方法和valueOf(int i)方法实现。
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
属性和构造函数
//用于存放该整型包装类代表的整型基本类型数值
private final int value;
//传入整数进行构造
public Integer(int value) {
this.value = value;
}
//传入字符串进行构建,使用Integer的parseInt(String s, int radix)方法实现
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
Number父类中的方法
//重写Number父类中的方法,获取该对象代表的数值的byte类型数值
public byte byteValue() {
return (byte)value;
}
//重写Number父类中的方法,获取该对象代表的数值的short类型数值
public short shortValue() {
return (short)value;
}
//重写Number父类中的方法,获取该对象代表的数值的int类型数值
public int intValue() {
return value;
}
//重写Number父类中的方法,获取该对象代表的数值的long类型数值
public long longValue() {
return (long)value;
}
//重写Number父类中的方法,获取该对象代表的数值的float类型数值
public float floatValue() {
return (float)value;
}
//重写Number父类中的方法,获取该对象代表的数值的double类型数值
public double doubleValue() {
return (double)value;
}
Object祖先类中的方法
//重写toString()方法,获取该对象的字符串表示形式
public String toString() {
return toString(value);
}
//重写hasCode()方法,使用Integer的hashCode(int value)实现
@Override
public int hashCode() {
return Integer.hashCode(value);
}
//使用value变量表示其hasCode
public static int hashCode(int value) {
return value;
}
//重写equals方法,先判断是否都为Integer类型,再判断两个对象的value值是否相同
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
getInteger相关方法
getInteger相关方法用于获取系统属性设置的整数。
decode(String nm)方法
该方法与getInteger相关方法的实现相关,用于解析给定的字符串,将其转换为相应的整数。
1. 使用0x、0X、#开头的字符串,将其视为十六进制数。
2. 使用0开头的字符串,将其视为八进制数。
3. 其他情况下,将其视为十进制数。
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);
//判断是否有符号位,并根据判断结果设置负数标志
if (firstChar == '-') {
negative = true;
index++;
} else if (firstChar == '+')
index++;
//判断是否为十六进制数
if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
index += 2;
radix = 16;
}
//判断是否为十六进制数
else if (nm.startsWith("#", index)) {
index ++;
radix = 16;
}
//判断是否为八进制数,由0开头且0不是最末尾字符
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 {
//使用Integer的valueOf(String s, int radix)方法获取相对应的整数,这里默认为正数
result = Integer.valueOf(nm.substring(index), radix);
//根据负号标志设置符号位
result = negative ? Integer.valueOf(-result.intValue()) : result;
} catch (NumberFormatException e) {
/**
* 如何抛出异常,可能是由于前面使用正数进行了处理,整数最小值的绝对值超过了整数的
* 最大值。将其转换为负数,再次尝试获取相对于的整数。
*/
String constant = negative ? ("-" + nm.substring(index))
: nm.substring(index);
result = Integer.valueOf(constant, radix);
}
return result;
}
getInteger(String nm, Integer val)方法
该方法根据给定的字符串nm,获取相应的系统属性并转换为整数,若转换失败,则使用给定的整数val作为默认值。
public static Integer getInteger(String nm, Integer val) {
String v = null;
try {
//获取系统属性
v = System.getProperty(nm);
} catch (IllegalArgumentException | NullPointerException e) {
}
if (v != null) {
try {
//使用Integer的decode(String nm)进行解析
return Integer.decode(v);
} catch (NumberFormatException e) {
}
}
return val;
}
getInteger(String nm)方法
该方法根据给定的字符串nm,获取相应的系统属性并转换为整数,若转换失败,则返回null。使用Integer的getInteger(String nm, Integer val)实现。
public static Integer getInteger(String nm) {
return getInteger(nm, null);
}
getInteger(String nm, int val)方法
该方法根据给定的字符串nm,获取相应的系统属性并转换为整数,若转换失败,则使用给定的整数val作为默认值。使用Integer的getInteger(String nm, Integer val)实现。
public static Integer getInteger(String nm, int val) {
Integer result = getInteger(nm, null);
return (result == null) ? Integer.valueOf(val) : result;
}
compareTo相关方法
compareTo相关方法用于比较两对象的大小。
compare(int x, int y)方法
该方法根据传入的两个整数判断其大小关系。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 anotherInteger)方法
该方法用于比较两个Integer对象的大小,使用Integer的compare(int x, int y)实现。
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
compareUnsigned(int x, int y)方法
Java中其实没有无符号数,这里所说的无符号数是相对的。其无符号数的最大 值其实是-1,其二进制的表示形式为11111111111111111111111111111111。负数的最高位为1,正数的最高位为0,从无符号数的角度看,负数的值一定大于正数。通过进行加MIN_VALUE的操作,可将负数的值进行正确的比较。
public static int compareUnsigned(int x, int y) {
return compare(x + MIN_VALUE, y + MIN_VALUE);
}
属性
//整数类型表示的位数
@Native public static final int SIZE = 32;
//整数类型表示的字节数
public static final int BYTES = SIZE / Byte.SIZE;
无符号数相关方法
再次强调,Java中其实没有无符号数,这里所说的无符号数是相对的。通过使用负数来表示一部分的无符号数,此时负数的符号位视为有效数值,所以说是否为无符号数,主要在于使用者如何看待负数
。
toUnsignedString(int i, int radix)方法
该方法将无符号整数i,根据给定技术radix,转换为对应的字符串。
public static String toUnsignedString(int i, int radix) {
return Long.toUnsignedString(toUnsignedLong(i), radix);
}
toUnsignedString(int i)方法
该方法给定整数i,将其转换为相应的无符号整数的字符串。该方法将整数i转换为long类型,在使用Long类型的toString方法将其转换为字符串。
public static String toUnsignedString(int i) {
return Long.toString(toUnsignedLong(i));
}
toUnsignedLong(int x)方法
该方法给定整数x,将其转换为相应的无符号整数,使用long类型表示。对于正数来说,其对应的无符号数仍为其本身;对于负数在说,需要将其符号位看为有效数值。
public static long toUnsignedLong(int x) {
//与0xffffffffL向与,保证高32位为0,在整数无符号数范围内
return ((long) x) & 0xffffffffL;
}
divideUnsigned(int dividend, int divisor)方法
该方法获取两无符号整数的相除结果。
public static int divideUnsigned(int dividend, int divisor) {
//使用Integer的toUnsignedLong(int x)方法转换为long类型再进行相除操作
return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
}
remainderUnsigned(int dividend, int divisor)方法
该方法获取两无符号整数的取余结果。
public static int remainderUnsigned(int dividend, int divisor) {
//使用Integer的toUnsignedLong(int x)方法转换为long类型再进行取余操作
return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
}
位操作相关方法
highestOneBit(int i)方法
该方法是取整数i的二进制形式最左边的位为1且后面全部补零,最后返回int型的结果。
1. 对0来说,二进制形式中无1,故返回0。
2. 对负数来说,二进制形式中最左端,即第32位必为1,故返回值的二进制形式为10000000000000000000000000000000,即Integer.MIN_VALUE。
3. 对正数来说,比如3,其二进制形式00000000000000000000000000000011,故返回值的二进制形式为00000000000000000000000000000010,即2。
public static int highestOneBit(int i) {
//将i与其带符号右移1位后的值相或,目的是为了将位为1的最高位的下一位也变为1,即连续2位为1
i |= (i >> 1);
//将i与其带符号右移2位后的值相或,目的是使从位为1的最高位开始有连续4个1
i |= (i >> 2);
//将i与其带符号右移2位后的值相或,目的是使从位为1的最高位开始有连续8个1
i |= (i >> 4);
//将i与其带符号右移2位后的值相或,目的是使从位为1的最高位开始有连续16个1
i |= (i >> 8);
/**
* 将i与其带符号右移2位后的值相或,目的是使从位为1的最高位开始有连续32个1,此时位为1的最高
* 为之后的位数都为1。
*/
i |= (i >> 16);
//i进行无符号右移移位,其实是将i位为1的最高位往右移移位,相减只剩下位为1的最高位
return i - (i >>> 1);
}
以八位数00010100为例,第一次得到00011110,最后得到00011111,进行i - (i >>> 1)
,得到00010000。
lowestOneBit(int i)方法
该方法是取整数i的二进制形式最右边的位为1且前面全部补零,最后返回int型的结果。
public static int lowestOneBit(int i) {
/**
* 这里主要利用了补码的特性来实现这个操作。一个负数的补码为其除符号位
* 的其他位数取反后加一。以8位为例,假设现在这个数为00001100,其负数的
* 表示形式则为11110100,相与得到000000100。
*/
return i & -i;
}
numberOfLeadingZeros(int i)方法
该方法返回给定整数的二进制形式的前导零的数目,该前导零将符号位计算在内。
public static int numberOfLeadingZeros(int i) {
if (i == 0)
return 32;
int n = 1;
/**
* 如果无符号右移16位得到0,说明高16位都为0,前导零数目加16,并将低16
* 位移动到高16位上。
*/
if (i >>> 16 == 0) { n += 16; i <<= 16; }
/**
* 若前面的条件不满足,则说明高16位上存在非零位数,只需处理高16位即可;
* 若前面的条件满足,则高16位上的前导零已处理完毕,并且已经将低16位移动
* 到了高16位上,只需处理高16位即可。之后的处理与前面的处理一致,只是依
* 次处理的位数为8位,4位,2位而已。
*/
if (i >>> 24 == 0) { n += 8; i <<= 8; }
if (i >>> 28 == 0) { n += 4; i <<= 4; }
if (i >>> 30 == 0) { n += 2; i <<= 2; }
/**
* (1)若i为负数,则前面的四个条件都不满足,此时n为1,i>>>31为1,n-=i>>>31得n=0。
* 即负数的前导零个数为0。
* (2)若i为正数,在进行前面的四个条件判断和相关操作之后,还需要对最后两位进行判断。
* 由于是正数,不可能两个都为0,要么都为1,要么前一位为0。将n初始化为1,默认最后两
* 位中有0,使用i>>>31判断最后两位是否有零,有的话i>>>31的值为0;没有的话值为1,需
* 要减去。比如00010000000000000000000000000000,其前导零个数有3个,上述四个条件只
* 有最后一个条件满足,执行完后i的值为01000000000000000000000000000000,n的值为3。
* i>>>31的值为0,n-=i>>>31的值为3。
*/
n -= i >>> 31;
return n;
}
numberOfTrailingZeros(int i)方法
该方法与求前导零个数类似,不过与前导零从左向右求零的个数相反,该方法返回给定整数的二进制数从 右端开始计算零的个数,直到遇到非零位的零的个数。
public static int numberOfTrailingZeros(int i) {
//y变量用于辅助计算
int y;
if (i == 0) return 32;
int n = 31;
y = i <<16; if (y != 0) { n = n -16; i = y; }
y = i << 8; if (y != 0) { n = n - 8; i = y; }
y = i << 4; if (y != 0) { n = n - 4; i = y; }
y = i << 2; if (y != 0) { n = n - 2; i = y; }
return n - ((i << 1) >>> 31);
}
bitCount(int i)方法
该方法用于计算给定的整数i的二进制形式中位为1的个数。
public static int bitCount(int i) {
/**
* 先总结一个规律,对于两位的二进制数来说,计算其位为1的个数有:
* (1)二进制数00,有00-00=00,位为1的个数为0。
* (2)二进制数01,有01-00=01,位为1的个数为1。
* (3)二进制数10,有10-01=01,位为1的个数为1。
* (4)二进制数11,有11-01=10,位为1的个数为2。
* 总结,对于二进制数i,其位为1的个数n有规律:n=i-i>>>1。
*/
/**
* 0x55555555的二进制表示形式为01010101010101010101010101010101。
* 这里实际上的用了上述规律,把i的每两位当成一个个体来计算。可将i
* 视为16个两位的独立的二进制数bi(0≤i≤15)。
* i>>>1直接运用了上述规律。观察以上规律可以发现,i>>>1时其实是在高位
* 补零,但由于这16个二进制数之间存在有位置关系,假设有b1b0,那么当进
* 行i>>>1操作时,b1的低位将移动到b0的高位,这时无法保证在b0的高位进行
* 补零的操作。因而将i>>>1与0x55555555进行与操作,可以将bi(0≤i≤15)的
* 高位强制置为零。这时,将bi(0≤i≤15)的值相加就是i的二进制形式中位为
* 1的个数。之后要做的就是不断地把bi(0≤i≤15)相加。
*/
i = i - ((i >>> 1) & 0x55555555);
/**
* 0x55555555的二进制表示形式为00110011001100110011001100110011。这里实际
* 做是将相邻的两个bi(0≤i≤15)相加。i&0x33333333实际上是保留bi(i=2k)所
* 在的值,将bi(i=2k+1)置为0。(i>>>2)&0x33333333实际上是将bi(i=2k+1)移
* 动到bi(i=2k)的位置上,再进行相加操作,从而实现部分bi(0≤i≤15)之间的
* 相加。注意,相加之后bi不再只是代表两位,而是代表四位,因为两个两位的
* bi(0≤i≤15)相加之后得到的值代表的是四位上为1的个数,故此时应该把i的每
* 四位当成一个个体来计算。可将i视为8个四位的独立的二进制数bi(0≤i≤7)。
*/
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
//之后的三步相加操作和上面的相加操作类似。只不过bi的位数分别变为了4,8,16。
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
/**
* 最后之所以与0x3f相与,是应为前面的两步并没有进行与操作,所以前面的数据是
* 无效的。而整数i最多只有32位,使用后面6位就足够表示了。
*/
return i & 0x3f;
}
rotateLeft(int i, int distance)方法
该方法将给定整数i左旋distance位。
public static int rotateLeft(int i, int distance) {
return (i << distance) | (i >>> -distance);
}
rotateRight(int i, int distance)方法
该方法将给定整数i右旋distance位。
public static int rotateRight(int i, int distance) {
return (i >>> distance) | (i << -distance);
}
signum(int i)方法
该方法返回给定整数的符号位,正数为1,零为0,负数为-1。
public static int signum(int i) {
return (i >> 31) | (-i >>> 31);
}
reverse(int i)方法
该方法给定整数i,将其二进制形式反转得到新的整数。
public static int reverse(int i) {
/**
* 以八位为例,表示为ABCDEFGH,其做法为:
* (1)每一位视为一个个体,每两位为一组进行反转,得到BADCFEHG
* (2)每两位视为一个个体,每四位为一组进行反转,得到DCBAHGFE
* (3)每四位视为一个个体,每八位为一组进行反转,得到HGFEDCBA
* 32位整数依次类推。
*/
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
/**
* 到这里为止,每八位之间的反转已经完成,使用字母代表八位的话,
* 现在该整数看做ABCD,接下来的操作就是将其反转为DCBA。
* (1)i<<24实际上就是将D移动到A的位置,得到D000(每个0代表8个0)。
* (2)i&0xff00实际上是得到00C0,左移8位,将C移动到B的位置,得到0C00。
* (3)i>>>8实际上是将B移动到C的位置,得到0ABC,再和0xff00进行相与,得到00B0。
* (4)i>>>24实际上就是将A移动到D的位置,得到000A。
* (5)将上述四步得到的四个值进行相与,即可得到DCBA。
*/
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
reverseBytes(int i)方法
该方法给定整数i,以字节为单位进行反转,其实现与Integer类的reverse(int i)方法 中的最后一步类似。
public static int reverseBytes(int i) {
return ((i >>> 24) ) |
((i >> 8) & 0xFF00) |
((i << 8) & 0xFF0000) |
((i << 24));
}
其他方法
sum(int a, int b)方法
该方法返回两个整数的和。
public static int sum(int a, int b) {
return a + b;
}
max(int a, int b)方法
该方法使用Math类的max方法返回两个整数的最大值
public static int max(int a, int b) {
return Math.max(a, b);
}
min(int a, int b)方法
该方法使用Math类的min方法返回两个整数的最小值。
public static int min(int a, int b) {
return Math.min(a, b);
}