java的位运算符(>>,<<,>>>,&,|)

主要总结下java的位运算符的操作。java的位运算符不紧可以提高运行效率,同时也有会意想不到的效果(java.util.ArrayDeque有很好的体现),在后续中会举例说明。

开始说位运算符之前,先简单的复习下补码的知识,然后举个简单的例子说明下计算机中的补码操作(计算机中的加减法)。

补码

计算机进行加减法操作时,都是以补码进行操作的,所以java中的位运算都是以补码进行操作的。正数的补码是其本身,而负数的补码为其反码+1。如下例子。

因为java中int型是4个字节,需要32位,为了写起来和看起来更加直观,这里使用8位来进行模拟。

对于正数2 ,其二进制形式为00000010,其补码也为00000010。

对于负数-2,其二进制形式为10000010,其补码为11111110。

为什么计算机会用补码进行操作,我用十进制来模拟一下。举两个数,一个是a=9145,一个是b=0645。(第一位为符号位,9表示负数,0表示正数)

对于二进制来说,1取反为0,因为1+0=1(比2小1);对于十进制来说,1取反为8,因为1+8=9(比10小1);对于16进制来说,1取反为14,因为1+14=15(比16小1);

所以对于十进制a=9155,他的反码为9844,而其补码为9845(反码+1),对于b,因为是正数,所以补码跟原码一样。所以a+b(补码相加)=9845+0645=10500。因为我们都是四位正数进行相加,所以10500的第一位就要舍去,得到的结果为0500。而0代表的是正数,所以结果就是500;

再举一个例子 比如 a=9645,b=0145(第一位为符号位,9表示负数,0表示正数)

a的补码为9355,b的补码跟原码一样。a+b=9355+0145=9500。所以结果就是-500。

计算机为什么要用补码运算呢,而不是用原码,因为计算机不像人一样,他不会进行减法运算,只是通过一种方式将减法变成了加法运算,也就是所谓的补码。

java的位操作

介绍完了补码,接下来介绍java的位操作(通过补码来进行操作)。

例1  右移操作

5>>1,-5>>1;  结果分别为2,-3;

先分析5>>1,因为5的补码为00000101。右移一位以后为00000010(结果为补码),再求其原码(跟补码一样),结果为2。因为5是正数,所以最高位补0,

再分析-5>>1,因为-5的补码为11111011。右移一位以后为11111101(结果为补码),在求其原码,结果为10000011,转换成十进制为-3。因为-5是负数,所以最高位补1。

例2  无符号右移

5>>>1,-5>>>1;结果分别为2,2147483645

在例1右移操作中,正数移动时,最高位补0,而负数移动时,最高位补1,而对于无符号右移,不管是正数还是负数,移动时最高位都会补0;

5>>>1和例1中类似,直接分析-5>>>1。-5的补码为11111011,无符号右移一位后为01111101,再求其原码(移动后变成了正数,所以原码和补码一致)最后结果为2147483645。

例3 &操作

5&7,5&-7,-5&-7。结果为5,1,-7。

先分析5&7,因为5的补码为00000101,7的补码为00000111;所以两个相与后为00000101,即为5。(&操作即每一位进行操作,都是1的话结果为1)

再分析5&-7,5的补码为00000101,-7的补码为11111001。所以两个相与后为00000001(因为是正数,其原码与补码一致),转换成十进制为1。

再分析-5&-7,-5的补码为11111011,-7的补码为11111001,两个相与后为11111001,因为是负数,所以再求其原码,为10000111,结果为-7。

java的 ’<<‘ 和 ’|‘ 操作与 ’>>‘ 和 ’&‘ 类似,就不在举例说明。

java位操作在JDK中的应用

在java.util包中有一个ArrayDeque类来实现队列的操作。ArrayDeque<E>类中维护了一个E[] elements数组来存储对象。

ArrayDeque类提供了不同的构造方法,其中有一个构造方法可以用来定义elements数组的大小,如下:

   public ArrayDeque(int numElements) {
        allocateElements(numElements);
    }

   private void allocateElements(int numElements) {
        int initialCapacity = MIN_INITIAL_CAPACITY;
        // Find the best power of two to hold elements.
        // Tests "<=" because arrays aren't kept full.
        if (numElements >= initialCapacity) {
            initialCapacity = numElements;
            initialCapacity |= (initialCapacity >>>  1);
            initialCapacity |= (initialCapacity >>>  2);
            initialCapacity |= (initialCapacity >>>  4);
            initialCapacity |= (initialCapacity >>>  8);
            initialCapacity |= (initialCapacity >>> 16);
            initialCapacity++;

            if (initialCapacity < 0)   // Too many elements, must back off
                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
        }
        elements = (E[]) new Object[initialCapacity];
    }

其中在allocateElements方法中,经过一系列的操作来初试化elements的大小。例如你给个初试化大小为6,经过allocateElements方法后,大小就变了8,。如果是14.则最后的elements的大小为16。最后不论怎样,都会变成2的N次方。

最后主要是说下ArrayDeque的进队和出队。在ArrayDeque类中维护了两个变量,分别是head和tail。分别指向第一个进队的元素和最后一个进队的元素。

如下为入队的方法

    public boolean add(E e) {
        addLast(e);
        return true;
    }

    public void addLast(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[tail] = e;
        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
            doubleCapacity(); //这个方法在后续的博客中讲解,这里先不用管
    }

接下的代码为出队的操作

    public E pop() {
        return removeFirst();
    }

    public E removeFirst() {
        E x = pollFirst();
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }

接下来画图说明下进队和出队时head和tail的变化。

初使时elements数组为空

当插入一个元素时

当弹出一个元素时

当再连续入队6个时,这个时候tail指向了数组的最后一个元素,当再入队一个元素,此时tail应该为8。而tail已经超过了数组的长度,此时经过

(tail = (tail + 1) & (elements.length - 1)

操作,tail又指向了第一个位置。当tail和head指向同一个位置时,此时说明了队列已满,就要扩容了。也就是如下的方法。

doubleCapacity();

如果队列一直不满的话。此时的数组就会不断循环使用。这些操作都是通过位操作来完成的。

主要总结下java的位运算符的操作。java的位运算符不紧可以提高运行效率,同时也有会意想不到的效果(java.util.ArrayDeque有很好的体现),在后续中会举例说明。

时间: 2024-10-12 21:14:39

java的位运算符(>>,<<,>>>,&,|)的相关文章

Java的位运算符详解实例

Java的位运算符详解实例——与(&).非(~).或(|).异或(^).右移(>>).左移(<<).无符号右移(>>>) 位运算符主要针对二进制, 它包括了:“与”.“非”.“或”.“异或”."右移"."左移"."无符号右移". 从表面上看似乎有点像逻辑运算符, 但逻辑运算符是针对两个关系运算符来进行逻辑运算, 而位运算符主要针对两个二进制数的位进行逻辑运算. 下面详细介绍每个位运算符. 1.与运

Java的位运算符笔记

Java的位运算符有:&与.|或.^异或.~非.<<算术左移.>>算术右移.>>>逻辑右移 1. &(与) 全是1-->1 全是0-->0 有1有0-->0 例:000 111 010 101 000 111 101 101 ---------------------------- 000 111 000 101 1 int i = 1; //00000000000000000000000000000001 2 int j = 2

Java的位运算符实例——与(&amp;)、非(~)、或(|)、异或(^)

一.Java的位运算符实例——与(&).非(~).或(|).异或(^) 1.与(&) 0 & 2 = 0 0 0 0 0 1 0 0 1 0 2.非(~) ~0 = 7 0 0 0 1 1 1 3.或(|) 0 & 2 = 2 0 0 0 0 1 0 0 1 0 4.异或(^) 1 & 2 = 3 0 0 1 0 1 0 0 1 1 二.运用场景.(类似打标) public enum FlagEnums { A(1, "高"), B(2, &qu

[转]Java的位运算符详解实例——与(&amp;)、非(~)、或(|)、异或(^)

位运算符主要针对二进制,它包括了:“与”.“非”.“或”.“异或”.从表面上看似乎有点像逻辑运算符,但逻辑运算符是针对两个关系运算符来进行逻辑运算,而位运算符主要针对两个二进制数的位进行逻辑运算.下面详细介绍每个位运算符. 1.与运算符与运算符用符号“&”表示,其使用规律如下:两个操作数中位都为1,结果才为1,否则结果为0,例如下面的程序段.public class data13{public static void main(String[] args){int a=129;int b=128

Java基础-位运算符Bitwise Operators

Java基础-位运算符Bitwise Operators 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 原文地址:https://www.cnblogs.com/yinzhengjie/p/8689059.html

Java按位运算符之按位取反

一 数据储存形式 二进制在内存中以补码的形式存在. 补码首位是符号位,0表示该数是正数,1表示该数是负数. 例如: 数值 带符号的二进制原码 (首位表示符号位) 补码 内存中的形式 (*表示无效位,其数量取决于分配的内存空间) 9 01001 01001 0***1001 -1 11 11 1***1  二 补码是什么 正数: 补码 = 反码 = 原码 负数: 原码取反 = 反码,反码+1 = 补码 ??运算时: 符号位不变,有效位进行运算!带*号的为无效位. 例如:   原码 反码 补码 9

JAVA 按位运算符的解释

按位运算符 Java定义了几个按位运算符,可以将其应用于整数类型long,int,short,char和byte. 按位运算符对位执行,并执行逐位运算.假设a = 60和b = 13; 现在以二进制格式,他们将如下 - a = 0011 1100 b = 0000 1101 ----------------- a&b = 0000 1100 a | b = 0011 1101 a ^ b = 0011 0001 a = 1100 0011 假设整数变量A保持60,变量B保持13,则 - publ

Java千问:Java语言位运算符详解

很多编程语言都有位运算符,Java语言也不例外.在Java语言中,提供了7种位运算符,分别是按位与(&).按位或(|).按位异或(^).取反(~).左移(<<).带符号右移(>>)和无符号右移(>>>).这些运算符当中,仅有~是单目运算符,其他运算符均为双目运算符.在讲解这些运算符的使用之前,必须了解一个常识,那就是:位运算符是对long.int.short.byte和char这5种类型的数据进行运算的,我们不能对double.float和boolean进

Java的位运算符具体解释实例——与(&amp;amp;)、非(~)、或(|)、异或(^)

位运算符主要针对二进制,它包含了:“与”.“非”.“或”.“异或”.从表面上看似乎有点像逻辑运算符,但逻辑运算符是针对两个关系运算符来进行逻辑运算,而位运算符主要针对两个二进制数的位进行逻辑运算.以下具体介绍每一个位运算符. 1.与运算符与运算符用符号“&”表示,其使用规律例如以下:两个操作数中位都为1,结果才为1,否则结果为0,比如以下的程序段.public class data13{public static void main(String[] args){int a=129;int b=