我正在研究这段代码,我不明白这行是做什么的:[(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));
}
}
}
答案 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中的运算符。