public static final int MIN_VALUE = 0x80000000; -2^31
public static final int MAX_VALUE = 0x7fffffff; 2^31-1
public static String toString(int i, int radix)
该方法返回一个字符串形式的参数,第二个参数为指令的基数,将第一个参数转换为以第二个参数为基数的字符串
package com.yiibai; import java.lang.*; public class IntegerDemo { public static void main(String[] args) { Integer i = new Integer(10); // returns a string representation of the specified integer with radix 10 String retval = i.toString(30, 10); System.out.println("Value = " + retval); // returns a string representation of the specified integer with radix 16 retval = i.toString(30, 16); System.out.println("Value = " + retval); // returns a string representation of the specified integer with radix 8 retval = i.toString(30, 8); System.out.println("Value = " + retval); } }
返回结果:
Value = 30 Value = 1e Value = 36
如果基数小于Character.MIN_RADIX或大于Character.MAX_RADIX的,则基数10代替.
这个地方MIN_RADIX不能为1,是因为基数不能为1,如果基数为1,就会进入死循环,1都不管多少次方都不可能成为不是1的其它数值
下面的ASCII字符被用来作为数字: 0123456789abcdefghijklmnopqrstuvwxyz
将整数转换为16进制
public static String toHexString(int i) {
return toUnsignedString(i, 4);
}
这
个地方解释一下为什么是4,因为16=2^4,操作:先将1向左移动4位即radix = 1 <<4
,得到二进制10000,然后减去1,得到掩码mask=1111,这个mask就是用来与要转换整数,从低到高位,每四位一次进行&操作,这样
没四位与一次,得到一个16进制数值,直到所有的二进制转换为16进制为止。
将整数转换为8进制
public static String toOctalString(int i) {
return toUnsignedString(i, 3);
}
这个地方的3就是因为转换为8进制,8 = 2 ^3,调用与16进制相同的方法。
将整数转换为二进制:
public static String toBinaryString(int i) {
return toUnsignedString(i, 1);
}
这个地方的1同上,2 = 2^1,调用方法都是相同的
这个地方就是进制转换的时候调用的方法,i就是要进行转换的10进制数,shift就是那个4,3,1
radix就是将1向左移动几位,mask就是得到用来转换用的掩码
private static String toUnsignedString(int i, int shift) {
char[] buf = new char[32];
int charPos = 32;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[--charPos] = digits[i & mask];
i >>>= shift;
} while (i != 0);
return new String(buf, charPos, (32 - charPos));
}
这个地方是将一个整数转换为字符串,Integer.MIN_VALUE = 0x80000000
其中getChars是一个比较有趣的方法,将整数转换后放在buf中
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);
}
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); //这个地方52429数字非常神奇!!!!!!!!!!!!!!!
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;
}
}
用来计算十位数
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 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 int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
这个用来判断一个正数,判断这是几位数,正好调用上面的sizeTable
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
下面这个方法是将一个radix进制的s转换成十进制的整数
比如s为32,radix 为4,那么最后转换成的整数时3*4+2 = 14;
这个地方会因为字符串不满足格式个出现异常,所以首先抛出NUmberFormatException异常
/ * @param s the {@code String} containing the integer
* representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @return the integer represented by the string argument in the
* specified radix.
* @exception NumberFormatException if the {@code String}
* does not contain a parsable {@code int}.
*/
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.
*/
//这个地方当输入为null或者输入radix为小于2或者大于36都是不允许的,都会抛出异常
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) {
//这个地方单独出去第一个字符是用来判断这个是否是符号标示,如果是“-”或者“+”,那么他们<‘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);
//如果是+或者-,但长度是1的话也是不允许的,所以会报错
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix); 这个地方讲解放在这个方法的最后
//每个字符都要判断是否符合格式,如果有某个字符不符合格式也不是不能进行转换操作的
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
java.lang.Character.digit(char ch, int radix)API
public static int digit(char ch,
int radix)
- 返回使用指定基数的字符
ch
的数值。如果基数不在
MIN_RADIX
<=radix
<=MAX_RADIX
范围之内,或者ch
的值是一个使用指定基数的无效数字,则返回-1
。如果以下条件中至少有一个为真,则字符是一个有效数字: - 方法
isDigit
为true
,且字符(或分解的单字符)的 Unicode 十进制数值小于指定的基数。在这种情况下,返回十进制数值。
- 字符为
‘A‘
到‘Z‘
范围内的大写拉丁字母之一,且它的代码小于radix + ‘A‘ - 10
。在这种情况下,返回ch - ‘A‘ + 10
。
- 字符为
‘a‘
到‘z‘
范围内的小写拉丁字母之一,且它的代码小于radix + ‘a‘ - 10
。在这种情况下,返回ch - ‘a‘ + 10
。
这个地方从返回就可以看出来 parseInt(String s)实际上是parseInt(String s, int radix)的特出情况,及radix为10的时候
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
这
个地方可以清楚的看到value(String s ,int radix)先返回valueof(int i),而valueof(int
i)又调用了parseInt(String s,int radix)所以本质上还是执行了parseInt(String s,int radix)
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
IntegerCache是Integer的内部类,用来将-128——high之间的对象进行实例化
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;//h值,可以通过设置jdk的AutoBoxCacheMax参数调整(以下有解释),自动缓存区间设置为[-128,N]。注意区间的下界是固定
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);// 取较大的作为上界,但又不能大于Integer的边界MAX_VALUE
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low));
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
这个方法就是用来调用上面缓存里面的对象,如果整数值在缓存对象数组范围内,就直接返回缓存对象,如果不在里面,就要为其新建对象
Integer i= 5;这是自动装箱问题,java运行的就是下面这段代码
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
构造方法,默认执行是parse(Stirng s, int 10)方法。
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
//比较两个整数是否相等,首先判断被比较对象是否是整型实例,如果是,将其转换成int类型进行比较
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
//
public static Integer getInteger(String nm,
Integer val)返回具有指定名称的系统属性的整数值。
第一个参数被视为系统属性的名称。通过
System.getProperty(java.lang.String) 方法可以访问系统属性。然后,根据每个 Integer.decode
方法,将该属性的字符串值解释为一个整数值,并返回一个表示该值的 Integer 对象。 如果属性值以两个 ASCII 字符 0x 或者
ASCII 字符 # 开始,并且后面没有减号,则将它的剩余部分解析为十六进制整数,就好像以 16 为基数调用
valueOf(java.lang.String, int) 方法一样。
如果属性值以 ASCII 字符 0 开始,后面还有其他字符,则将它解析为八进制整数,就好像以 8 为基数调用 valueOf(java.lang.String, int) 方法一样。
否则,将属性值解析为十进制整数,就好像以 10 为基数调用 valueOf(java.lang.String, int) 方法一样。
第二个参数是默认值。如果未具有指定名称的属性,或者属性的数字格式不正确,或者指定名称为空或 null,则返回默认值。
public static Integer getInteger(String nm, Integer val) {
String v = null;
try {
v = System.getProperty(nm);//这个方法的解析放到System类中
} catch (IllegalArgumentException e) {
} catch (NullPointerException e) {
}
if (v != null) {
try {
return Integer.decode(v); //这个方法在下面进行具体介绍
} catch (NumberFormatException e) {
}
}
return val;
}
//这个方法是调用上面的方法,并且是使第二个参数的默认值为null
public static Integer getInteger(String nm) {
return getInteger(nm, null);
}
//这个地方实际上是先调用的最上面的方法,同样也是使第二个参数为null,然后根据返回结果,如果是null,将第二个参数转换成Integer类型返回
public static Integer getInteger(String nm, int val) {
Integer result = getInteger(nm, null);
return (result == null) ? Integer.valueOf(val) : result;
}
//这个方法是方法解码字符串转换为整数,(1)判断长度如果是0,则抛出0长度异常,(2)判断其第一个字符是‘-‘还是‘+‘,
(3)调用String.startWith(String s,int i)方法,判断这是多少进制的数值(4)如果第二个字符又出现了‘-‘或是‘+‘,则抛出符号位置异常
(5)调用Integer.valueof(String s, int i)方法,将其解码为十进制整数(6)根据其正负值,返回相应的数值
(7)最后抛出的异常是如果转换的整数刚好是Integer.MIN_VALUE,因为正数不包含,所以抛出异常,需要在异常中获取返回
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;
}
//比较两个整数,如果小于返回-1,相等返回0,大于返回1
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
//实际上是调用的compare方法
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
1.第一步的作用是把最高位1右移移位,并与原数据按位取或。那么这就使得最高位和它的下一位是连续两个1。
2、第二步的作用是把刚刚移位得到连续两个1继续右移两位并与原数据按位取或。那么这就使得最高两位和它的下两个连续位组成四个连续的1。
3、 以此类推,最终得到的i是从开始的最高位到结束全是1。并减去i不带符号的右移一位,即可得到一个int数据的最高位的值。
4、上述情况是针对于i不为零和负数的情况,如果i为零,那么得到的结果始终为零。如果i位负数,那么得到的结果始终是-2147483648。即等于Integer.MIN_VALUE。(原因在于负数的最高位始终为1,即是负数的符号位)
public static int highestOneBit(int i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
//求最低位数值,用这个数字与他的负数进行相与操作,用补码进行相与操作
public static int lowestOneBit(int i) {
// HD, Section 2-1
return i & -i;
}
//求得从高位开始到第一个非零数值之间0的个数
具体做法:
(1)如果是0,则返回32
(2)无符号右移16为,如果为0,说明左边这16位都为0,左移16位,将最左边的16删除
(3)无符号右移24位,如果是0,说明左边的8位都为0,左移8位,将左边的8位删除掉
(4)无符号右移28位,如果是0,说明左边的4位都为0,左移4位,将左边的4位删除掉
(5)无符号右移30位,如果是0,说明左边的2位都为0,左移2位,将左边的2位删除掉
(6)无符号右移31位,如果是0,说明原始数从小到大第二位是0,如果不是,说明是1,将一开始初始化的1减掉
public static int numberOfLeadingZeros(int i) {
// HD, Figure 5-6
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;
}
//求一个整数转换成二进制之后,从最低位开始到第一个不为0的数值之间有多少位0
(1)如果是0,则返回32,否则初始化0的总数为n = 31
(2)左移16为,如果结果不为0,说明右边这16位存在不为0的值,保存移动之后的结果,接下来继续对其进行移位操作,n = n - 16
(3)左移8位,如果结果不为0,说明右边的8位存在不为0的值,保存移动之后的结果,接下来继续对其进行移位操作,n = n - 8
(4)左移4位,如果结果不为0,说明右边的4位存在不为0的值,保存移动之后的结果,接下来继续对其进行移位操作,n = n - 4
(5)左移2位,如果结果不为0,说明右边的2位存在不为0的值,保存移动之后的结果,接下来继续对其进行移位操作,n = n - 2
(6)经过上一步结果不为0,说明了最后两位有三种可能,要么其中一位为1,另外一位为0;要么都为1;在这里这用考虑第一种情况就行,
先左移1位,得到最低位的数值,然后无符号右移31位,这样就能将最低位回复到正常位置
(7)最后用n减去这个数值,如果这个数值为1,减去之后结果为0,正好返回0;如果这个数值为0,减去结果为1,
public static int numberOfTrailingZeros(int i) {
// HD, Figure 5-14
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);
}
//这是求解一个整数转换成二进制补码之后,其中1的个数
二分法,两两一组相加,之后四个四个一组相加,接着八个八个,最后就得到各位之和了。
第一行是计算每两位中的 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 的个数.
将 0x55555555, 0x33333333, 0x0f0f0f0f 写成二进制数的形式就容易明白了.
这个还有个浅显的理解方式:
(1)
假设转换之后的二进制整数的最后两位是XY,那么无符号右移一位,然后与0101相与之后得到的0X,用原始数据相减之后得到二进制数X(Y-X)(转换
成十进制之后:X+Y,即:两位一组表示1的个数),得到的结果是每两位一组中1的个数,只不过 还是用二进制表示的
(2)将(1)中的到
的结果,每四位一组,先与0011相与,求得后两位中1的个数,然后加上结果无符号右移两位与0011相与,得到前两位中1
的个数,例子:XYZM(表示的是二进制最后四位),因为(1)中的结果都是两位一组来计算的,所以与0011相与后得到ZM,然后右移之后再相与得到
XY,这样相加的结果就是1的个数(2*X+Y+2*Z+M),最后的结果仍用二进制表示,就将(1)中的两位一组表示变成了四位一组表示
(3)
这一步先右移四位,然后与原数相加,最后与00001111进行相与操作。实际上就上将两个四位进行求和,然后与1111相与,但是相加的时候都会有两次
重复,所以将其中一次与0000相与。举个例子,0101001100110011,右移之后的数据0000010100110011,因为第二组中
0101+0011,然后与1111相与,所以第一组四位0101与0000相与,这样就避免了重复相加
(4)将上一步的结果右移8位,然后与之相加,这个地方记住只看第二组跟第四组的结果,因为这两个刚好是原来第一组与第二组的和,第三组与第四组的和
(5)将上一步的结果右移16位,然后相加,这里只看第二组的最后八位结果,这就是叠加之后的和,其他位都不用看
(6)最有一步与0x3f相与,因为32位最多只需要5位,这里可以多一位,得到最后的结果
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); //16位一组统计 结果放在 后8位 i = i + (i >>> 16);
return i & 0x3f; // 32位1组统计 结果放在 后16位
//这个地方我用了比较长时间来研究
这个方法的主要作用就是要将i转换成二进制之后,然后将数值先向左移动distance个单位,然后将数值再无符号向右移动【distance的补码后五位的值计算出来的数值(因为int只有32位,所以只有后五位的数值才是有效数字)】的单位,最后将两个结果取或操作。
举个例子,假设i转换成二进制之后为AB【A:32-distance位数字,B:distance位数字】,经过下面方法之后变成了BA,BA就是所求得的结果
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);
}
这个方法是将所有的位数进行翻转操作,即:0与31互换,1与30互换,。。。。。
具体操作:
(1)两位一组,进行互换位置
(2)四位一组,1与3,2与4互换位置
(3)八位一组,1与8,2与7,3与6,4与5互换位置
(4)现在的结果是四个八位数组,将第四个数组移动到第一个位置,将第三个数组移动到第二个位置,将第二个数组移动到第三个位置,第一个数组移动到第四个位置
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;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
//返回int值的正负号
具体操作先将原始数据转换成二进制补码,然后右移31,再将原始数据取负,转换成二进制补码,右移31位,最后进行或操作
正数返回1,负数返回-1,0返回0
如果是正数i>>31 的结果是0000。。。。0000,-i>>>31的结果是0000。。。。0001,最后结果就是1
如果是负数i>>31的结果是1111。。。。1111,-1>>>31的结果是0000。。。。0000,最后的结果是-1
public static int signum(int i) {
// HD, Section 2-7
return (i >> 31) | (-i >>> 31);
}
这个地方是以Byte为单位进行互换位置
将int转换成二进制补码,然后八位一组,分成四组,第一组跟第四组互换位置,二三组互换位置
public static int reverseBytes(int i) {
return ((i >>> 24) ) |
((i >> 8) & 0xFF00) |
((i << 8) & 0xFF0000) |
((i << 24));
}