JavaRush /Java 博客 /Random-ZH /Java中的位运算

Java中的位运算

已在 Random-ZH 群组中发布
你可能对“击败”这个词很熟悉。如果没有,让我们来了解一下:) 位是计算机中信息的最小计量单位。它的名字来源于英文“ binary digital ”——“二进制数”。一位可以表示为两个数字之一:1 或 0。有一个基于 1 和 0 的特殊数字系统 - 二进制。我们不会深入数学丛林,只是注意到 Java 中的任何数字都可以转换为其二进制形式。为此,您需要使用包装类。 位运算 - 1例如,以下是对数字执行此操作的方法int
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(x));
   }
}
控制台输出:

101010110
1010 10110(为了便于阅读,我添加了一个空格)是二进制数 342。我们实际上已将这个数字分成单独的位 - 零和一。通过它们,我们可以执行称为按位的运算。
  • ~— 按位“非”运算符。

它的工作原理非常简单:它遍历数字的每一位并将其值更改为相反的值:从零到一,从一到零。如果我们将它应用到数字 342 上,我们会得到如下结果: 101010110 - 二进制中的数字 342 010101001 - 表达式 ~342 的结果 但是由于 int 变量占用 4 个字节,即 32 位,实际上变量中的数字存储为: 00000000 00000000 00000001 01010110- java 中 int 类型变量中的数字 342 11111111 11111111 11111110 10101001- java 中表达式 ~342 的结果 让我们尝试在实践中这样做:
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(~x));
   }
}
控制台输出:
11111111111111111111111010101001
  • &— 按位运算符“AND”

正如你所看到的,它的写法与逻辑“AND”(&&)非常相似。&&正如您所记得的,true仅当两个操作数都为 true 时,运算符才会返回。按位的&工作方式类似:它逐位比较两个数字。比较的结果是第三个数字。例如,我们以数字 277 和 432 为例: 100010101 - 二进制形式的数字 277 110110000 - 二进制形式的数字 432 接下来,运算符将&较高数字的第一位与较低数字的第一位进行比较。由于这是一个“AND”运算符,因此仅当两个位都等于 1 时,结果才等于 1。在所有其他情况下,结果将为 0。 100010101 & 110110000 _______________ 100010000 - 工作结果& 我们首先比较第一位两个数字彼此的组合,然后是第二位,第三位,依此类推。正如您所看到的,只有在两种情况下,数字中的两个位都等于 1(第一位和第五位)。其他所有比较的结果都是0。因此,最终我们得到了数字100010000。在十进制中,它对应于数字272。我们来检查一下:
public class Main {

   public static void main(String[] args) {
       System.out.println(277&432);
   }
}
控制台输出:

272
  • |- 按位“或”。操作原理是相同的——我们逐位比较两个数字。只有现在,如果至少一位等于 1,结果就等于 1。让我们看一下相同的数字 - 277 和 432:
100010101 | 110110000 _______________ 110110101 - 工作结果。| 这里的结果是不同的:只有那些在两个数字中都为零的位仍然为零。运算结果是数字 110110101。在十进制中,它对应于数字 437。让我们检查一下:
public class Main {

   public static void main(String[] args) {
       System.out.println(277|432);
   }
}
控制台输出:

437
我们计算的一切都正确!:)
  • ^- 按位异或(也称为 XOR)
我们以前从未遇到过这样的操作员。但这并不复杂。它看起来像一个普通的“或”。区别之一:true如果至少一个操作数为真,则普通的“或”返回。但不一定是其中之一——如果两者都存在的话true——那就是结果truetrue但仅当其中一个操作数为 true 时,异或才返回。如果两个操作数都为 true,则将返回常规“or” true(“至少有一个为 true”),但独占 or 将返回false。这就是为什么它被称为独家。知道了前面按位运算的原理,你大概可以轻松地自己执行277^432运算了。但让我们更好地再次一起弄清楚:) 100010101 ^ 110110000 _______________ 010100101 - 工作结果^ 这是我们的结果。两个数字中相同的位返回 0(“其中之一”公式不起作用)。但那些0-1或1-0的组合最终变成了一个整体。结果我们得到了数字010100101,在十进制中,它对应的是数字165。我们来看看我们计算是否正确:
public class Main {

   public static void main(String[] args) {
       System.out.println(277^432);
   }
}
控制台输出:

165
极好的!一切都与我们想象的完全一样:) 现在是时候熟悉称为位移位的操作了。原则上,这个名字本身就说明了一切。我们将获取一些数字并左右移动它的位:)让我们看看它是什么样的:

左移

位左移由符号表示 示例<<
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(Integer.toBinaryString(x));
       System.out.println(Integer.toBinaryString(z));
   }
}
在此示例中,数字x=64称为值。我们将移动的是它的位。我们将位左移(这可以通过符号的方向来确定<<) 在二进制系统中,数字 64 = 1000000 这个数字y=3称为数量。Quantity 回答了“数字的位应该向右/向左移动多少位x?”的问题,在我们的示例中,我们将它们向左移动 3 位。为了让换档过程更加清晰,我们来看一张图。在我们的示例中,我们使用 int 类型的数字。Int占用32位计算机内存。这就是我们原来的数字 64 的样子: 位运算 - 2现在,从字面意义上来说,我们将每个位向左移动 3 个单元: 位运算 - 3这就是我们得到的。正如您所看到的,我们所有的位都已移位,并且从范围之外添加了 3 个零。3 - 因为我们移动了 3。如果我们移动了 10,就会添加 10 个零。因此,该表达式的x << y意思是“将 y 个单元格的位х向左移动”。我们的表达式的结果是数字 1000000000,在十进制中等于 512。让我们检查一下:
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
控制台输出:

512
这是正确的!理论上,位可以无限地移位。但由于我们有编号int,因此只有 32 个可用单元。其中,7 个已被数字 64(1,000,000)占用。因此,例如,如果我们向左移动 27 次,我们唯一的单位将超出范围并“覆盖”。只剩下零!
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 26;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
控制台输出:

0
正如我们所料,这个超出了 32 位单元并消失了。我们得到了一个仅由零组成的 32 位数字。 位运算 - 4当然,在十进制中它对应于 0。记住左移的一个简单规则:每左移一次,数字就乘以 2。例如,让我们尝试计算没有位图片的表达式的结果。 111111111 << 3 我们需要将数字 111111111 乘以 2 三倍,结果是 888888888,我们来编写代码并检查一下:
public class Main {

   public static void main(String[] args) {
       System.out.println(111111111 << 3);
   }
}
控制台输出:

888888888

右移

它们由符号 表示>>。他们做同样的事情,只是方向不同!:) 我们不要重新发明轮子,而是尝试使用相同的数字 int 64 来完成此操作。
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 2;//quantity

       int z = (x >> y);
       System.out.println(z);
   }
}
位运算 - 5位运算 - 6由于右移 2,我们的数字的两个极端零超出了范围并被删除。我们得到数字 10000,在十进制中对应于数字 16。输出到控制台:

16
记住右移的一个简单规则:每个右移除以二,丢弃任何余数。例如, 35 >> 2 这意味着我们需要将35除以2 2次,丢弃余数 35/2 = 17(丢弃余数1) 17:2 = 8(丢弃余数1)总计35 >> 2应该等于8。检查:
public class Main {

   public static void main(String[] args) {
       System.out.println(35 >> 2);
   }
}
控制台输出:

8

Java中操作的优先级

当您编写或阅读代码时,您经常会遇到同时执行多个操作的表达式。了解它们的执行顺序非常重要,否则结果可能会出乎意料。由于Java中有很多操作,所以它们都被分成一个特殊的表:

运算符优先级

运营商 优先级
后缀 expr++ expr--
一元 ++expr --expr +expr ~ !
乘法 * / %
添加剂 + -
转移 << >> >>>
关系型的 < > <= >=实例化
平等 == !=
按位与 &
按位异或 ^
按位或 |
逻辑与 &&
逻辑或 ||
三元 ? :
任务 = += -= *= /= %= &= ^= |= <<= >>= >>>=
所有操作均从左到右执行,但要考虑到它们的优先级。例如,如果我们写: int x = 6 - 4/2; 首先将执行除法运算(4/2)。虽然她排在第二位,但她的优先级更高。圆括号或方括号将任何优先级更改为最大。你可能还记得学校里的这件事。例如,如果将它们添加到表达式中: int x = (6 - 4)/2; 将首先执行减法,因为它是在括号中计算的。&&从表中可以看出,逻辑运算符的优先级相当低。因此,大多数情况下它会最后执行。例如: boolean x = 6 - 4/2 > 3 && 12*12 <= 119; 该表达式将像这样执行:
  • 4/2 = 2

    boolean x = 6 - 2 > 3 && 12*12 <= 119;
  • 12*12 = 144

    boolean x = 6 - 2 > 3 && 144 <= 119;
  • 6-2 = 4

    boolean x = 4 > 3 && 144 <= 119;
  • 接下来将执行比较运算符:

    4 > 3 = true

    boolean x = true && 144 <= 119;
  • 144 <= 119 = false

    boolean x = true && false;
  • 最后,将执行最后一个运算符&&

    boolean x = true && false;

    boolean x = false;

    例如,加法运算符 ( +) 的优先级高于比较运算符!=(“不等于”);

    因此在表达式中:

    boolean x = 7 != 6+1;

    首先执行运算 6+1,然后检查 7!=7 (false),最后将结果赋给false变量x。分配通常在所有操作中具有最低优先级 - 请查看表。

唷!我们的讲座很长,但你做到了!如果您不完全理解本讲座和之前讲座的某些部分,请不要担心,我们将来会多次涉及这些主题。以下是一些对您有用的链接:
  • 逻辑运算符- 关于逻辑运算的 JavaRush 讲座。我们不会很快看到它们,但你现在可以阅读它们,不会有任何伤害
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION