Java-for循环使用<<操作者

时间:2013-07-25 15:25:47

标签: java

我正在研究这段代码,我不明白这行是做什么的:[(y << 3) + x]

    for (int y = 0; y <= 7; ++y) {
            for (int x = 0; x <= 7; ++x) {
                final String pieceCode = pieceCodes[(y << 3) + x];
                if (pieceCode.length() != 2) throw new IllegalArgumentException();
                if (!pieceCode.equals("--")) {
                    pieces[((7 - y) << 3) + x] = CheckersPiece.valueOf(pieceCode.charAt(0), pieceCode.charAt(1));   
                }
            }
        }

9 个答案:

答案 0 :(得分:6)

这是一种模糊的乘以8的方式。因此,(y << 3) + x等于8 * y + x

y << 3相当于乘以8的原因是因为<<是左移运算符:它将y的所有位移位一个位置。同样地,如果你取一个基数为10的数字并向左移一个位置你乘以10,那么在基数2中向左移动相当于乘以2.因此,向左移动三个位置相当于乘以2 * 2 * 2 = 8.通常,向左移n个位置相当于乘以2^n(只要你没有从左端掉落的位)。

在过去的日子里,程序员编写了这样的代码,因为左移是超级快速,比乘法更快,因此8 * y不如y << 3更优化。但是现在,编译器非常善于确定何时用8 * y替换y << 3之类的内容。

因此,我说它被混淆了,因为8 * y更明确地表达了意图:(y << 3) + x的意图是跳过y 8个块,并取x那个街区的位置。通过说8 * y + x可以更明确地表达这些 。请记住,我们使用高级语言编写代码来阅读和理解代码。我们的代码应该为人类编写。编译器可以为机器制作好的机器指令,以便理解。

这样做是因为它试图假装pieceCodes是一个2D数组,只是映射到一维数组。

也就是说,piecesCode看起来像这样

x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x

但我们可以假装它看起来像这样

x x x x x x x x 
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x

请参阅(x, y) -> 8y + x,我们访问了x y行,piecesCode y行。也就是说,x告诉我们要跳过多少8个块,{{1}}告诉我们该块内的去向。

答案 1 :(得分:3)

(y << 3)表示向左移位3次。它与乘以2 ^ 3 = 8相同。因此,整个表达式(y << 3) + x变为y * 8 + x

它应该以{{1​​}}的形式编写,因为它更具可读性,很可能没有性能提升。 Premature optimization is the root of all evil。最好将这种微优化留给编译器(或JVM)。

此外,电路板尺寸可以存储在一个常数中,只能在一个地方存放:

y * 8 + x

final int SIZE = 8; // ... for (int y = 0; y < SIZE; y++) { for (int x = 0; x < SIZE; x++) { final String pieceCode = pieceCodes[y * SIZE + x]; 只是迭代一个(逻辑上)2D表,其中包含8行和1列,存储为1D,包含64个单元格。

作为最后一点,我想指出,在给定代码中y * 8 + x是一个字符串数组...... 但事实上,它是一系列件代码。不只是一些字符串。现在,pieceCodes可以作为一个神奇的状态,除了程序员之外没有人知道它意味着什么。 "--"也看起来很糟糕。因此,应该有一个对象if (pieceCode.length() != 2),数组将被声明为PieceCode。在PieceCode[] pieceCodes中,我们可以实施适当的PieceCode方法。如果equals()只是一个州,它可以是一个枚举。例如PieceCode。比较字符串并不像比较枚举那么快。我们还必须注意写EMPTY, WHITE_PAWN, WHITE_QUEEN, BLACK_PAWN, BLACK_QUEEN,而不是equals()

答案 2 :(得分:2)

来自规范:

n&lt;&lt; s是n个左移位位;这相当于(即使发生溢出)将2乘以幂s。

答案 3 :(得分:2)

&LT;&LT;和&gt;&gt;是位移操作符。在这种情况下,它将y转换为二进制并在3个位置“移位”,根据需要向末尾添加新位

例如,如果y为8,则其值为1000

y&lt;&lt; 3将向左移3位,产生1000000或64

答案 4 :(得分:2)

该代码使用表示二维数组[m] [n]作为一维数组[m * n]的优化技术。 m和n在这里看起来都是8(8个皇后,国际象棋,也许?)。

诀窍是将索引元组(i,j)转换为一维数组的索引。

大多数情况下,你通过将i乘以n并添加j来实现这一点。

由于n = 8,因此在这种情况下可以通过向左移3位来表示乘法。这传达了这样的信息:“我们在这里做了一些很好的大小(即2的幂)阵列。”,至少对非初学者来说。

答案 5 :(得分:2)

这称为bitwise and bit shift operator。另外,请查看wiki

文档摘要

  

Java编程语言还提供对整数类型执行按位和位移操作的运算符。本节中讨论的运算符不太常用。

     

一元按位补码运算符“〜”反转位模式。签名左移运算符“&lt;&lt;”将位模式向左移位,并使用带符号的右移运算符“&gt;&gt;”将位模式向右移动。

     

按位&amp;运算符执行按位AND运算。

     

bitwise ^运算符执行按位异或运算。

     

按位|运算符执行按位包含OR运算。

示例代码:

class BitDemo {
    public static void main(String[] args) {
        int bitmask = 0x000F;
        int val = 0x2222;
        // prints "2"
        System.out.println(val & bitmask);
    }
}

那么......什么是按位和位移操作符?

为了节省时间和空间,我将简单地包含这个article来深入解释所有运算符!

答案 6 :(得分:1)

快速回答,这是将数字乘以8(2 ^ 3 = 8)的有效方法

答案 7 :(得分:1)

y&lt;&lt; 3意味着“向左移3位”......这实质上是另一种做“* 8”的方式

如果你进行右移(y>&gt;&gt; 3),那将是整数除以8,但是也很有用,因为这些位会从结尾掉下来,如果你有点“消耗”这些位循环。

曾经(当时的方式回来)CPU移位比乘法更快,因此使用“x&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;但是,这不再适用。

我以前在代码中看到表达式,例如“x&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 4&x;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 2“或”x * 22“。

答案 8 :(得分:1)

http://en.wikipedia.org/wiki/Bitwise_operation ...在Java中,所有整数类型都被签名,并且“&lt;&lt;”和“&gt;&gt;”运算符执行算术移位。 Java添加了运算符“&gt;&gt;&gt;”执行逻辑右移,但由于逻辑和算术左移操作相同,因此没有“&lt;&lt;&lt;&lt;&lt;&lt; Java中的运算符。