Integer类为java基本类型int的包装类,除了前面提到的Byte类,Short类中的大部分方法,Integer类中还提供了很多处理int类型的方法,接下来就让我们一起看看吧。
基础知识:
1.Java移位运算,移位运算也是java中位运算的一部分主要有以下三种:
前提:
1).移位是在将对应的数字转换为2进制后进行的,JAVA中用补码表示二进制数.
2).移位后总长度不变,比如int类型为32位,移动后还需补齐为32位,其它也类似
3).左边为低位,右边为高位
左移( << ):将运算符左边的对象,向左移动运算符右边指定的位数,并且在低位补零。向左移n 位,就相当于乘上2 的n 次方
右移( >> ):将运算符左边的运算对象,向右移动运算符右边指定的位数。如果是正数,在高位补零,如果是负数,则在高位补1
无符号右移( >>> ):将运算符左边的对象向右移动运算符右边指定的位数,并且在高位补0
注:
1).对于正数来说,右移或无称号右移n 位,就相当于除上2 的n 次方。
2).对于int类型(长度为32位)移位,左移(<<)n位,相当于移动 n % 32 位,如: 1 << 33 实际上是 1 << 1 也就是2,其它类型移动超过自身类型长度的也应该是类似,有兴趣的可以自行研究下。
3).java中没有无符号左移,原因很简单,左移补的是低位,java中高位的第一位表示符号位。
前言:
从本文开始,对于比较简单的属性和方法,或是在之前文章中讲过的文章中将不再列出,有兴趣的同学可以看下之前的文章,或是留言笔者将根据大家的需求考虑是否后续在文章中添加。
几个数组属性:
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'
};
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',
} ;
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
digits数组用于表示所有可能出现的字符,因为int支持从2进制到36进制,所以这里需要有36个字符才能表示所有不同进制的数字
DigitTens和DigitOnes两个数组也很好理解,它们主要用于获取0到99之间某个数的十位和个位,比如36,通过DigitTens数组直接取出来十位为3,而通过DigitOnes数组取出来个位为6。
sizeTable数组主要用在判断一个int型数字对应字符串的长度。避免了使用除法或求余等操作,以提高效率。
toString(int i, int radix):
public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
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));
}
该方法的作用就是将int类型的数字,转换为指定进制的数的字符串形式。
第一步判断:int类型支持的进制数为2(Character.MIN_RADIX)到36(Character.MAX_RADIX),如果不是这个范围就按10进制来处理。
第二步:如果是10进制,调用toString(i)(这个方法我们后面再讲),如果不是10进制,继续往下走。
第三步:接着它创建了一个长度为33的char类型的数组,诶,为什么这里长度为33,int类型的最大长度为32啊,看到后面你就知道了,还要给 '-'留一个位置,原来这个方法的转换并不是真正意义上的转换,都是按照正数来转换,如果是负数就在正数转换的结果上加'-'。
第四步:创建了两个局部变量negative和charPos其中negative是个标识,用来标识目标数是正数还是负数。charPos是用来指定转换后的数存储在缓冲数组中的位置。
第五步:转换,这里就是按照10进制的数转换为其它进制数的转换方法进行的。如果不清楚的同学可以看下另一篇文章Java中的进制转换
第六步:创建一个字符串对象返回。
toString(int i):
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
这个方法用来将10进制的数转换为10进制的字符串形式。
第一步:判断如果是int类型的最小值,就直接返回一个固定的值,无需计算。
第二步:计算数字的长度,用到的stringSize方法,如下:
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
可以看到它使用了sizeTable这个数组,巧妙的避免了除法和求余,以高效的求得对应字符串长度。方法实现很简单,但是思想我们可以借鉴。
第三步:创建了一个数组,然后调用getChars方法填充数组中的内容。getChars方法实现如下:
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Generate two digits per iteration
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r];
i = q;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
}
}
这个方法的作用就是将一个int类型的数按顺序放到char数组中。不过这里使用了很多的技巧。它把int的高位的两个字节和低位的两个字节分开处理,while (i >= 65536)就是处理高位的两个字节`。每次处理两位数,使用了一个技巧((q << 6) + (q << 5) + (q << 2)),就是 q * (2^6 +2^5 + 2^2) = q * 100。DigitTens和DigitOnes用来取十位和个位。后面就是对低位的两个数进行处理了,其本质就是求余,也用了一些技巧,(i * 52429) >>> (16+3)其实约等于i/10,((q << 3) + (q << 1))其实等于q*10,最后通过digits数组获取到对应的字符。这里面使用乘法和移位运算代替除法和取余,用移位运算和加法代替乘法,可见在运算效率上加法和移位高于乘法,乘法高于除法。
第四步:根据填充好的char数组创建字符串对象返回
注:
1.这个方法也就是toString(int i, int radix)方法中对于10进制的处理。可以看到对于10进制的转化,可是花了大功夫在优化上,为了避免使用除法,应用各种移位操作来进行,即使在不得不使用除法的地方也尽可能用除以100而不是除以10来减少除法次数。
2.这里使用getChars去填充char数组,显然写这段代码的之前是一个写C语言这种面向过程的人。对于java这种面向对象的语言来说,这里我们应该用 char[] buf = getChars(i, size);这种方式,以后大家写java代码我也推荐大家使用这种方式。什么没看明白,自己去百度下面向过程和面向对象方面的知识吧。
int类型转换为其它进制的字符串形式:
//转换为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);
}
可以看到这几个转换的方法都调用了同一个方法toUnsignedString0只是传的参数不同,toUnsignedString0方法如下:
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);
}
第一步:获取目标值value的二进制形式有效位长度,Integer.numberOfLeadingZeros(val)这个方法是计算value的二进制高位共有多少位0,后面我们再讲这个方法。
第二步:获取缓冲数组的大小
第三步:调用formatUnsignedInt方法,这个方法才是核心,原因如下:
static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
int charPos = len;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[offset + --charPos] = Integer.digits[val & mask];
val >>>= shift;
} while (val != 0 && charPos > 0);
return charPos;
}
这里就是将10进制数转换为其它进制数的代码体现了,其中 1 << shift相当于2^shift,radix - 1如果转换为16进制就是15如果是8进制就是7,这里是为了后面做&的计算,你想一下如果转换为16进制,一个数&上15(1111),就是取得这个数字的低4位,这样4位4位的计算不就转换为这个数的16进制了吗,转换为8进制同理。后面的val&mask 就相当于 val%(mask+1)也就是进制转换的过程了。
第四步:根据buf数组,创建String对象后返回。
parseInt:
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) {
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;
}
parseInt有两个方法,作用是将指定进制的数的字符串形式转换为int类型。看上面这个就行。
第一步:参数校验。字符串为null或是radix不在可转换的进制范围内就抛出异常。
第二步:核心处理逻辑是字符串转换数字,其它进制转成十进制,如521为8进制,则结果为5* 8^2 + 28^1 + 18^0.上面的转换方法也差不多是根据此方法,只是稍微转变了思路( (5 * 8+2)*8)+1结果都是一样的。规律就是从左到右遍历字符串的每个字符,然后乘以进制数,再加上下一个字符,接着再乘以进制数,再加上下个字符,不断重复,直到最后一个字符。除此之外另外一个不同就是上面的转换不使用加法来做,全都转成负数来运算,其实可以看成是等价了。因为负数Integer.MIN_VALUE变化为正数时会导致数值溢出,所以全部都用负数来运算。
第三步:返回正确的结果如果是负数就添加负号。
无符号转换:
public static String toUnsignedString(int i, int radix) {
return Long.toUnsignedString(toUnsignedLong(i), radix);
}
public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
}
这两个方法就是将目标数转换为无符号表示的long或是字符串,无符号意思就是将二进制中的高位的第一位不当作符号位来看待。其中toUnsignedString使用了Long.toUnsignedString方法,一直跟踪源码可以发现实现方式与Integer中的实现方式相同,这里就不再重复了,不明白的同学可以看下Integer中的toString方法和toUnsignedString0方法。
parseUnsignedInt:
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);
}
}
将目标字符串数字转换为指定进制的无符号整型。
第一步:获取第一个字符,判断是否为'-',如果是'-'就抛出异常。
第二步:判断长度小于5或是小于9的10进制,使用parseInt方法长度小于5是因为int类型的最大数转换为最大进制36进制是6位。parseInt方法在上面已经讲过了。
第三步:如果超出第二步判断的范围,就要使用long来转换了,否则可能溢出。 if ((ell & 0xffff_ffff_0000_0000L) == 0) 若未超过int无符号数支持的范围,即数字高八位为0,则返回int值,否则抛出异常,数字超过int可表示的范围。
IntegerCache:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
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);
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
可以看出Integer类也有如同Byte和Short类类似的缓存池机制,而不同点在于Integer的缓存池可以改变上限的大小,通过 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");来获取上限,这个参数可以在JVM中配置。但是在设置的时候这个值是要大于或等于127小于Integer.MAX_VALUE。如果小于127以127为上限。注意。下限是-128这个是不可以改变的。
getInteger:
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;
}
这个方法是从系统属性中查找数据然后转换为对应的Integer对象,如果系统中不存在待查找的属性,则返回null。单从方法名上看Integer.getInteger与Integer.valueOf(由于valueOf方法在之前的Byte类或Short类中已经讲过了,都是相似的,这里不赘述)方法功能是一样的,但实际则不然,我们在使用的时候也要小心一点。
decode:
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;
}
这个方法是用来解析2进制,8进制,10进制16进制表示的字符串的。我们用数字前面加0表示8进制如056,数字前面加0x或是#,如0x1234或是#1234,表示16进制,默认数字为10进制。注意这个方法也不是太智能,如你传100这个字符串,他就不知道是10进制还是2进制,默认当10进制来转换了。又如你给定字符串 0000 0000 0000 0100 ,你想让他按2进制来解析,但实际上他按8进制来解析。所以使用的时候如果有这种有歧义的字符串,要小心一些。
无符号比较:
public static int compareUnsigned(int x, int y) {
return compare(x + MIN_VALUE, y + MIN_VALUE);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
无符号就是二进制的最高位符号位不当作符号位来,比较,实现过程也很简单。那么这个函数用来比较两个数-1是最大的,因为-1的所有位都是1,当然最大。
divideUnsigned:
public static int divideUnsigned(int dividend, int divisor) {
return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
}
divide意为除的意思,这个方法就是将两个数转换为无符号的数,然后再相除。
remainderUnsigned:
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));
}
将两个数转换为无符号的数,然后再计算余数,可以看到源码的注释 // In lieu of tricky code, for now just use long arithmetic.意思就是因为这个情况很棘手,所以现在暂时用long型数据,具体待我们看到Long类的源码时再研究
highestOneBit:
public static int highestOneBit(int i) {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
乍一看这个方法是干什么的,不明白。按照位运算|和移位运算一步一步的跟下来,你就会发现,将目标数转换为二进制后。保留这个数的最高位1,即从右边开始数第一个1保留。然后其它位全变为0后的结果。如10 ,二进制为1010,保留最高位1,其它位全变0就是1000,结果就为8.
lowestOneBit:
public static int lowestOneBit(int i) {
return i & -i;
}
同highestOneBit类似,从左边开始数第1位1保留,其它全变0后的结果。
numberOfLeadingZeros:
public static int numberOfLeadingZeros(int i) {
if (i == 0)
return 32;
int n = 1;
if (i >>> 16 == 0) { n += 16; i <<= 16; }
if (i >>> 24 == 0) { n += 8; i <<= 8; }
if (i >>> 28 == 0) { n += 4; i <<= 4; }
if (i >>> 30 == 0) { n += 2; i <<= 2; }
n -= i >>> 31;
return n;
}
这个函数的作用就是,取一个int类型数的二进制左边共有多少位0.如10的二进制为1010,int共有32位,那么左边就有28个0,即numberOfLeadingZeros(10)结果为28。这个方法作用很简单,但实现这个方法用的一个思想却是很重要,值得我们一学。有兴趣的同学可以看下我的别一篇文章从JDK源码看二分思想。
numberOfTrailingZeros:
public static int numberOfTrailingZeros(int i) {
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);
}
同numberOfLeadingZeros类似,这个方法的作用就是取一个int类型的二进制右边共有多少位0。如10的二进制为1010.右边共有1个0.numberOfTrailingZeros(10)结果就为1。
bitCount:
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;
}
这个方法的作用是,将一个int类型的数转换为二进制后,数里面有多少个1。如10,二进制为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 的个数 。
rotateLeft:
public static int rotateLeft(int i, int distance) {
return (i << distance) | (i >>> -distance);
}
(i << distance) 先把尾巴那几位空出来成0,然后(i >>> -distance)获得前面的那几位,然后按位或运算,就旋转了,即循环左移。
rotateRight:
public static int rotateRight(int i, int distance) {
return (i >>> distance) | (i << -distance);
}
跟前面的rotateLeft一样,先把位置空出来,然后取得对应的二进制位,按位或运算,就成了。
reverse:
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;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
将目标数转换为32位二进制数据后,高位和低位对应位置数据互换。如10转换为2进制后为00000000 000000000 00000000 0001010则转换后数据为01010000 00000000 00000000 00000000怎么样很好理解吧。其实Integer中的很多操作都是转换为二进制后,再处理的,光看代码很复杂。把数据转换成二进制,然后再对照代码看就很简单了。
signum:
public static int signum(int i) {
return (i >> 31) | (-i >>> 31);
}
这个方法我还没研究明白是干什么用的,i >> 31这个如果i为正数运算后全变为0,如果是负数运算后全变为1(指的是二进制位),(-i >>>31) 如果i为正数,运算后为1,如果i为负数运算后为0。两个数做|运算后,如果i为正则结果为1,如果为负数结果为-1,如果是0则结果为0,估计是运来判断一个数是正数负数还是0吧。如果是这样的话直接跟0做比较不就好了,写这段代码干什么呢,搞不明白。
reverseBytes:
public static int reverseBytes(int i) {
return ((i >>> 24) ) |
((i >> 8) & 0xFF00) |
((i << 8) & 0xFF0000) |
((i << 24));
}
这个方法同Byte类的reverseBytes方法有点类似。但这里是高8位与低8位互换,中间的两个8位互换之后的结果。转换成二进制后就一目了然了,我就不举例了。
其它方法:
//求两个数之和
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类中的很多方法都是操作二进制数的。光看代码可能一头雾水,转换为二进制后,再辅助代码就直观多了。
- 这个类中涉及了很多的位运算,如果对位运算不清楚的可以看下一起学JDK源码 -- Byte类和本章的基础知识部分。
- 这个类中有一些方法如signum、reverseBytes等操作二进制数的思想到是很精彩。但实际不知道有什么用。不知道是作者炫耀它的思想,还是我太菜没看出来他的意图。