关于数据的基础知识
众所周知,在计算机中,数据都是以2进制的方式储存。举个最最最简单的例子
10进制整数 1 以2进制表示
1
10进制整数 2 以2进制表示为10
10进制整数 16 以2进制表示为10000
这样看起来很简单的样子。但是在我们解读2进制数据的时候会有个很大的麻烦。例如:
A把10进制的整数16保存成10000
发送给B。如果A不告诉B他使用的是10进制数据的话,那么多于B来说,10000
可以为10进制的16,也可以是8进制的20,也可以是16进制的10,B就会懵逼的问A:“你传给我的是什么鬼“。
上面的例子足以说明数据类型对于数据的重要性。
为什么计算机是2进制呢?因为理论是最佳的进制是e进制,即2.718…。正常来说3进制与其更为接近,然而对于制造业来说,2进制更方便生产,所以就变成了2进制。
在java中1个int类型占用多少位呢?我们来做个测试
System.out.println(-1);
// output:11111111111111111111111111111111
A仔细的数了几遍以后确定确实是32位。于是A说:”新技能get!原来int是32位”。
然而A又错了。在java中,int确实固定为32位。不过在其他语言中int并不一定是32位(在C中有仔细说明int类型的问题)。
Java中short
是16位-32768~32768
这时:
System.out.println((short)32770);
//output: -32766
有符号类型的最高位表示正负(0正,1负),所以对于16位有符号类型的数字最大值应该为Math.pow(2,15)
。当数字在Math.pow(2,15)
和Math.pow(2,16)
之间的时候,就会出现最高位被置为1,导致出现负数。(java没有无符号类型)
说了这么多进入正题:
在JAVA中总共有3种移位运算符。
* >> 有符号右移
* << 右符号左移
* >>> 无符号右移
有符号和无符号的区别在于对最高位的处理。
有符号移位的时候回保留最高位的状态,例:
System.out.println(Integer.toBinaryString(-1));
//output: 11111111111111111111111111111111System.out.println(Integer.toBinaryString(-1>>1));
//output: 11111111111111111111111111111111System.out.println(Integer.toBinaryString(-1>>>1));
//output: 01111111111111111111111111111111
因为对于低位的处理无符号和有符号是相同的所以不存在无符号左移
那么这跟进制转换有毛关系?
再举个栗子:
2进制的10000
等于16进制的多少呢?
思路1:10000
是2的4
次方等于16等于16进制的10
。(确实毛关系没有!)
不过这是人的思维。
思路2:运用移位运算进行计算:
在2进制中4位代表16进制一位所以10000
等于00010000
把4位看作1位那么0001
等于1
,0000
等于0
所以16进制为10
.
再来看:
在2进制中3位代表8进制中的1位,10000
等于010000
等于八进制中的2位010
和000
,其中010等于2所以8进制中为20。
A恍然大悟!原来是这么玩的,这时A又问了十分愚蠢的问题:平时都是用10进制,研究这个有啥用?
然而位运算就是2进制的,虽然代码上写的是9 & 2
其实这个也是通过对应2进制进行计算的。
A最后问:说了着么多你到底想告诉我什么?
因为这就是Integer
中对于进制转换的实现。
/**
* Convert the integer to an unsigned number.
*/
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);
}
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;
}
A吐血身亡!!!!