Java位运算符总结

Java中的位操作符

&(与)操作

两个操作数中位都为1,结果才为1,否则结果为0

public class data13
{
    public static void main(String[] args)
    {
        int a=129;
        int b=128;
        System.out.println("a 和b 与的结果是:"+(a&b));
    }
}

运行结果:
a 和b 与的结果是:128
下面分析这个程序:
“a”的值是129,转换成二进制就是10000001,而“b”的值是128,转换成二进制就是10000000。根据与运算符的运算规律,只有两个位都是1,结果才是1,可以知道结果就是10000000,即128。

|(或)运算符

或运算符用符号“|”表示,其运算规律如下:
两个位只要有一个为1,那么结果就是1,否则就为0,下面看一个简单的例子。

public class data14
{
    public static void main(String[] args)
    {
        int a=129;
        int b=128;
        System.out.println("a 和b 或的结果是:"+(a|b));
    }
}

运行结果
a 和b 或的结果是:129
下面分析这个程序段:
a 的值是129,转换成二进制就是10000001,而b 的值是128,转换成二进制就是10000000,根据或运算符的运算规律,只有两个位有一个是1,结果才是1,可以知道结果就是10000001,即129。

^(异或)运算符

异或运算符是用符号“^”表示的,其运算规律是:
两个操作数的位中,相同则结果为0,不同则结果为1。下面看一个简单的例子。

public class data16
{
    public static void main(String[] args)
    {
        int a=15;
        int b=2;
        System.out.println("a 与 b 异或的结果是:"+(a^b));
    }
}

运行结果
a 与 b 异或的结果是:13
分析上面的程序段:a 的值是15,转换成二进制为1111,而b 的值是2,转换成二进制为0010,根据异或的运算规律,可以得出其结果为1101 即13。

~(非)运算符

非运算符用符号“~”表示,其运算规律如下:

如果位为0,结果是1,如果位为1,结果是0,下面看一个简单例子。

public class data15
{
    public static void main(String[] args)
    {
        int a=2;
        System.out.println("a 非的结果是:"+(~a));
    }
}

运行结果是: -3, 2的二进制表示是:0000….000010
然后取~, 结果是1111….111101, 将补码转换成十进制就是-3

<< (左移)运算符

<< 和>>为数值位移,>>>为逻辑位移。【注】:Java中不存在<<<。
m<<n的含义:把整数m表示的二进制数左移n位,高位移出n位都舍弃,低位补0. (此时将会出现正数变成负数的形式)

3<<2剖析:

3的二进制形式: 00000000 00000000 00000000 00000011,按照左移的原理,得到00000000 00000000 00000000 00001100,即为12.
左移使整数变为负数:

10737418<<8

10737418二进制表示形式:00000000 10100011 11010111 00001010,按照左移的原理,得到10100011 11010111 00001010 00000000,即为:-1546188288.

>>(逻辑右移)运算符

m>>n的含义:把整数m表示的二进制数右移n位,m为正数,高位全部补0;m为负数,高位全部补1.
>> 会根据符号位的正负进行补位

3>>2剖析:

3二进制形式: 00000000 00000000 00000000 00000011,按照右移的原理,得到00000000 00000000 00000000 00000000,即为0.
-3>>2剖析:
-3二进制形式: 11111111 11111111 11111111 11111101,按照右移的原理,得到11111111 11111111 11111111 11111111,即为-1.

以上:每 个整数表示的二进制都是32位的,如果右移32位和右移0位的效果是一样的。依次类推,右移32的倍数位都一样。

>>>(无符号右移)运算符

m>>>n:整数m表示的二进制右移n位,不论正负数,高位都补零。

3>>>2剖析:

3二进制形式: 00000000 00000000 00000000 00000011,按照无符号右移的原理,得到00000000 00000000 00000000 00000000,即为0.
-3>>>2剖析:
-3二进制形式: 11111111 11111111 11111111 11111101,按照无符号右移的原理,得到00111111 11111111 11111111 11111111,即为1073741823.


&0xFF的意义

byte类型转换成int类型时需要进行 &0xFF的操作, 原因跟计算机的存储原理有关。

数据在内存是以补码的形式存在的。
补码:
正数(000000001): 正数的补码和反码都是它本身。
负数(100000001): 反码是对原码除了符号位之外作取反运算即(111111110),补码是对反码作+1运算即(111111111)。

System.out.println(-127 & 0xFF);
// 结果是129

下面分析-127&0xFF的过程

  1. -127的补码表示(10000001)

  2. JVM向控制台输出时,检测到byte向int类型的转换于是做了一个补位处理
    (10000001) -> (11111111,11111111,11111111,10000001)
    这个32位的补码表示也是-127, 此时转换过后的二进制数据的十进制表示仍然是相同的,但是此时补码的因为高位补1已经不一致了,我们为了保证补码的一致性,必须进行&0xFF操作.

  3. 进行&0xFF操作
    &0xff可以将高的24位置为0,低8位保持原样。这样做的目的就是为了保证二进制数据的一致性。
    当然,保证了二进制数据性的同时,如果二进制被当作byte和int来解读,其10进制的值必然是不同的,因为符号位位置已经发生了变化。
    比如-127&0xff; -127 & 0xff=(11111111,11111111,111111111,10000001) & (00000000,00000000,00000000,11111111) = (00000000,00000000,00000000,10000001) 这个值算一下就是129.

// & 0xFF 的区别
System.out.println(Integer.toBinaryString(-127));
System.out.println(Integer.toBinaryString(-127 & 0xFF));
// 11111111111111111111111110000001
// 10000001

Java实现int和long类型的序列化

简单对上面的知识进行一个总结
这个小demo就是将int和long类型的数值写到文件中,然后在读出来,如果结果正确证明序列化成功.

创建文件

 private static void createFile() {
        sFile = new File("./", "obj");
        sFile.delete();
        if (!sFile.exists()) {
            try {
                sFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

int类型的序列化

int类型占8个字节,每次右移8个单位存储,需要分四次写入

// 将int数据写到硬盘上
private static void writeInt(int num) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(sFile));
        bos.write((num >> 0) & 0xFF);
        bos.write((num >> 8) & 0xFF);
        bos.write((num >> 16) & 0xFF);
        bos.write((num >> 24) & 0xFF);
        bos.flush();
        bos.close();
    }

 // 同样也是分四次读,每次获取8位数据,然后读四次
 // 从文件中读取int类型的值
 private static int readInt() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sFile));
        int num = 0;
        num |= bis.read();
        num |= bis.read() << 8;
        num |= bis.read() << 16;
        num |= bis.read() << 24;
        bis.close();
        return num;
    }

long类型的序列化

 // long类型在JVM运行时占用8个字节,也就是64位,所以我们需要分8次向文件中写入数据
 private static void writeLong(long num) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(sFile));
        bos.write((int) ((num >> 0) & 0xFFL));
        bos.write((int) ((num >> 8) & 0xFFL));
        bos.write((int) ((num >> 16) & 0xFFL));
        bos.write((int) ((num >> 24) & 0xFFL));
        bos.write((int) ((num >> 32) & 0xFFL));
        bos.write((int) ((num >> 40) & 0xFFL));
        bos.write((int) ((num >> 48) & 0xFFL));
        bos.write((int) ((num >> 56) & 0xFFL));
        bos.flush();
        bos.close();
    }

    // 同样, 分8次从文件中读取数据,记得 &0xFFL 转换成long类型
    private static long readLong() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sFile));
        long num = 0L;
        num |= (bis.read() & 0xFFL) << 0;
        num |= (bis.read() & 0xFFL) << 8;
        num |= (bis.read() & 0xFFL) << 16;
        num |= (bis.read() & 0xFFL) << 24;
        num |= (bis.read() & 0xFFL) << 32;
        num |= (bis.read() & 0xFFL) << 40;
        num |= (bis.read() & 0xFFL) << 48;
        num |= (bis.read() & 0xFFL) << 56;
        bis.close();
        return num;
    }

测试代码

private static void serialIntTest() throws IOException {
        final int magic = -0x20170507;
        System.out.println("序列化前: " + magic);
        writeInt(magic);
        System.out.println("序列化后: " + readInt());
    }

    private static void serialLongTest() throws IOException{
        // 如果是long类型,那么数字结尾处必须加上L,否则会认为是int类型
        final long magicLong = -0x2017050720170507L;
        System.out.println("序列化前: " + magicLong);
        writeLong(magicLong);
        System.out.println("序列化后: " + readLong());
    }

完整代码


/**
 * Created by yangtianrui on 17-5-7.
 */
public class WriteByteToFile {


    private static File sFile;

    public static void main(String[] args) throws Exception {

        createFile();

        serialIntTest();
        serialLongTest();
        /*
         * 结果:
         * 序列化前: -538379527
         * 序列化后: -538379527
         * 序列化前: -2312322461839328519
         * 序列化后: -2312322461839328519
         */
    }

    private static void serialIntTest() throws IOException {
        final int magic = -0x20170507;
        System.out.println("序列化前: " + magic);
        writeInt(magic);
        System.out.println("序列化后: " + readInt());
    }

    private static void serialLongTest() throws IOException{
        // 如果是long类型,那么数字结尾处必须加上L,否则会认为是int类型
        final long magicLong = -0x2017050720170507L;
        System.out.println("序列化前: " + magicLong);
        writeLong(magicLong);
        System.out.println("序列化后: " + readLong());
    }



    private static void writeInt(int num) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(sFile));
        bos.write((num >> 0) & 0xFF);
        bos.write((num >> 8) & 0xFF);
        bos.write((num >> 16) & 0xFF);
        bos.write((num >> 24) & 0xFF);
        bos.flush();
        bos.close();
    }

    private static int readInt() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sFile));
        int num = 0;
        num |= bis.read();
        num |= bis.read() << 8;
        num |= bis.read() << 16;
        num |= bis.read() << 24;
        bis.close();
        return num;
    }


    private static void writeLong(long num) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(sFile));
        bos.write((int) ((num >> 0) & 0xFFL));
        bos.write((int) ((num >> 8) & 0xFFL));
        bos.write((int) ((num >> 16) & 0xFFL));
        bos.write((int) ((num >> 24) & 0xFFL));
        bos.write((int) ((num >> 32) & 0xFFL));
        bos.write((int) ((num >> 40) & 0xFFL));
        bos.write((int) ((num >> 48) & 0xFFL));
        bos.write((int) ((num >> 56) & 0xFFL));
        bos.flush();
        bos.close();
    }


    private static long readLong() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sFile));
        long num = 0L;
        num |= (bis.read() & 0xFFL) << 0;
        num |= (bis.read() & 0xFFL) << 8;
        num |= (bis.read() & 0xFFL) << 16;
        num |= (bis.read() & 0xFFL) << 24;
        num |= (bis.read() & 0xFFL) << 32;
        num |= (bis.read() & 0xFFL) << 40;
        num |= (bis.read() & 0xFFL) << 48;
        num |= (bis.read() & 0xFFL) << 56;
        bis.close();
        return num;
    }

    private static void createFile() {
        sFile = new File("./", "obj");
        sFile.delete();
        if (!sFile.exists()) {
            try {
                sFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值