JavaSE-位操作

2016-10-01  本文已影响18人  hylexus

[TOC]

基础概念

字节

单位转换

K (KiloBytes,千) 字节  1KB = 1024 byte =2^10 byte
M(MegaBytes,兆)字节    1MB = 1024 K =2^20 byte
G(GigaBytes,吉)字节    1GB = 1024 M =2^30 byte
T(TeraBytes,太)字节    1TB = 1024 G =2^40 byte
P(PetaBytes,拍)字节    1PB = 1024 T =2^50 byte

数字的表示

计算机数字有原码、反码、补码三种存储格式,通常都是补码。

比如:

1(000 0111) //符号位为1
1111 1000 //对原码取反
1111 1001 //加1

注意,以下所示的 基本规则 中的0和1表示的都是 二进制位

与(&)

基本规则

同时为1得1,否则为0

0 & 0 == 0
0 & 1 == 0
1 & 0 == 0
1 & 1 == 1

常用技巧

或(|)

基本规则

同时为零得0,否则为1

0 | 0 == 0
0 | 1 == 1
1 | 0 == 1
1 | 1 == 1

非(~)

基本规则

按位取反,0变1,1变0

异或(^)

基本规则

相同得0,不同得1

0 ^ 0 == 0
0 ^ 1 == 1
1 ^ 0 == 1
1 ^ 1 == 0

常用技巧

1 ^ 1 == 0
1 ^ 1 ^ 1 == 1
1 ^ 1 ^ 1 ^ 1 == 0
1 ^ 1 ^ 1 ^ 1 ^ 1 == 1
1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 == 0

移位

左移

基本规则

例子

6 << 2 == 24

00000000 00000000 00000000 00000110 (6)
00000000 00000000 00000000 00011000 (6 << 2)

常用技巧

对于正数和负数,在数字没有溢出的前提下:

右移

基本规则

例子

6 >> 2 == 1

00000000 00000000 00000000 00000110 (6)
00000000 00000000 00000000 00000001 (6 >> 2)

-3 >> 1 == -2
11111111 11111111 11111111 11111101 (-3-----补码)
11111111 11111111 11111111 11111110 (-2-----补码)

常用技巧

m >> n:即相当于m除以2的n次方

无符号右移

和右移的区别是:无论正负数,都在高位补0

例子:

-3 >>> 1 ==2147483646

11111111 11111111 11111111 11111101(-3-----补码)
01111111 11111111 11111111 11111110(右移1位高位补0而不是1)

应用

正负数切换

由原码反码补码的知识很容易得到如下结论:

~x + 1 == -x

求绝对值

问题就在如何获取符号位了:

x >> (size-1) ==========> 最左边的符号位,size为数字总的位长度,java的int为32个bit
public int abs(int x) {
    return x >> (Integer.SIZE - 1) == 0 ? x : ~x + 1;
}

判断奇偶数

通常我们判断一个数是奇数还是偶数都是用取模运算,但是这个效率有点底下了。
本人在一次面试的时候就遇到面试题让我写出最快的判断奇数偶数的方法。
计算机里最快的无非是位运算了。

(x & 1) == 1 则x是奇数
(x & 1) == 0 则x是偶数

原理:

奇数偶数的奇偶,关键就看最后一位了.
所以考虑只保留最后一位,其余的位都和0相与而“遮盖”掉.

例如:

00011010 (26)
00000001 (1)
-------------
00000000 (0)===>偶数


00011001 (25)
00000001 (1)
------------
00000001 (1)===>奇数

大小写转换

对于同一个字母而言,其对应的ASCII码的差值的绝对值刚好是32。
所以,我们常规的转换也就是对其对应的ASCII码加上或者减去32,即可得到其对应的大写或者小写字母了。

恰好这个差值32是2^5==0b100000==0x20,或许当初ASCII定制的时候就考虑到这点了吧。

// 这里的c和C代表a-zA-Z中的任意一个字符。
c ^ 0x20 == C
C ^ 0x20 == c

例如:

'a'====>97====>01100001
'A'====>65====>01000001
        32====>00100000

就差倒数第六位的1====>0b100000===>0x20。

原理

大小和小写字母的ASCII码之间就差倒数第六位的1或0
所以转换大小写只需考虑将倒数第六位取反即可。其余位不变。

所以可以用异或的特性来做开关位切换倒数第六位的0或者1。

交换两个数

平常我们的做法就是找第三个数作为临时的交换空间,有一次遇到了有人用这个方式交换的。

int a = 9;
int b = 10;
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println(a); //10
System.out.println(b); //9

十进制整数转为二进制字符串

尽量不适用任何内置库函数和内置类,只使用最基本的操作完成整数到二进制字符串的转换。

// i>=0 && i<Integer.SIZE

// 1. 倒数第i位后跟i个0
//比如i为3时可能为1000(倒数第三位为1)或0000(倒数第三位为0)
x & (1<<i) 

// 2.倒数第i位
(x & (1<<i)) >> i 
public String toBinaryString(int x) {
    char bts[] = new char[Integer.SIZE];
    //或者可以将循环倒过来处理
    for (int i = 0; i < Integer.SIZE; i++) {
        bts[Integer.SIZE - 1 - i] = (x & (1 << i)) >> i == 0 ? '0' : '1';
    }
    return new String(bts);
}

字符串和十六进制字符串互转

java字符串和十六进制字符串互转

上一篇 下一篇

猜你喜欢

热点阅读