ITEEDU

Java Gossip: 逻辑、位运算 

大于、小于的运算会了,但如果想要同时进行两个以上的条件判断呢?例如分数大于80但小于90的判断,在逻辑上有所谓的「且」、「或」与「反」,在 Java中也提供这几个基本逻辑运算所需的「逻辑运算子」(Logical operator),分别为「且」(&&)、 「或」(||)及「反相」(!)三个运算子。

来看看下面这个程序会输出什么?

int number = 75; 
System.out.println((number > 70 && number < 80)); 
System.out.println((number > 80 || number < 75)); 
System.out.println(!(number > 80 || number < 75)); 

三段程序分别会输出true、false与true三种状况。

接下来看看「位运算子」(Bitwise operator),在 数字设计上有AND、OR、NOT、XOR与补码等运算,在Java中提供这些运算的就是位运算子,它们的对应分别是 AND (&)、OR(|)、XOR(^)与补码(~)。

如果您不会基本的位运算,以下可以提供一个程序来显示各个运算的结果:

BitWiseOperator.java
public class BitwiseOperator {
	public static void main(String[] args) {
		System.out.println("AND运算:");
		System.out.println("0 AND 0\t\t" + (0 & 0));
		System.out.println("0 AND 1\t\t" + (0 & 1));
		System.out.println("1 AND 0\t\t" + (1 & 0));
		System.out.println("1 AND 1\t\t" + (1 & 1));
		System.out.println("\nOR运算:");
		System.out.println("0 OR 0\t\t" + (0 | 0));
		System.out.println("0 OR 1\t\t" + (0 | 1));
		System.out.println("1 OR 0\t\t" + (1 | 0));
		System.out.println("1 OR 1\t\t" + (1 | 1));
		System.out.println("\nXOR运算:");
		System.out.println("0 XOR 0\t\t" + (0 ^ 0));
		System.out.println("0 XOR 1\t\t" + (0 ^ 1));
		System.out.println("1 XOR 0\t\t" + (1 ^ 0));
		System.out.println("1 XOR 1\t\t" + (1 ^ 1));
	}
}

执行结果:

AND运算: 
0 AND 0?0 
0 AND 1?0 
1 AND 0?0 
1 AND 1?1 

OR运算: 
0 OR 0?0 
0 OR 1?1 
1 OR 0?1 
1 OR 1?1 

XOR运算: 
0 XOR 0?0 
0 XOR 1?1 
1 XOR 0?1 
1 XOR 1?0?

Java中的位运算是逐位运算的,例如10010001与01000001作AND运算,是一个一个位对应运算,答案就是00000001;而补码 运算是将所有的位0变1,1变0,例如00000001经补码运算就会变为11111110,例如下面这个程序所示:

byte number = 0; 
System.out.println((int)(~number));

这个程序会在主控台显示-1,因为byte占内存一个字节,它储存的0在内存中是00000000,经补码运算就变成11111111,这在计算机中 用整数表示则是-1。

要注意的是,逻辑运算子与位运算子也是很常被混淆的,像是&&与 &,||与|,初学时可得多注意。

位运算对初学者来说的确较不常用,但如果用的恰当的话,可以增进不少程序效率,例如下面这个程序可以判断使用者的输入是否为奇数:

BitWiseOperator.java
import java.util.Scanner;
public class BitwiseOperator {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		System.out.print("请输入数字: ");
		int inputedNumber = scanner.nextInt();
		System.out.println("是否为奇数? " +
		((inputedNumber&1) != 0 ? '是' : '否'));
	}
}

执行结果:

请输入数字: 8
是否为奇数? 否 

这个程序得以运算的原理是,奇数的数值若以二进制来表示,其最右边的位必为1,而偶数最右边的位必为0,所以我们使用1来与输入的值作AND运算,由 于1除了最右边的位为1之外,其它位都会是0,与输入数值AND运算的结果,只会留下最右边位为0或为的结果,其它部份都被0 AND运算遮掉了,这就是所谓「位屏蔽」,例如:

00000100 -> 4
00000001 -> 1
----------
00000000 -> 判断为偶数

00000011 -> 3
00000001 -> 1
----------
00000001 -> 判断为奇数

XOR的运算较不常见,这边举个简单的XOR字符加密例子,先看看程序:

XorCode.java
public class XorCode {
	public static void main(String[] args) {
		char ch = 'A';
		System.out.println("before encoding:" + ch);
		ch = (char)(ch^0x7);
		System.out.println("after encoding:" + ch);
		ch = (char)(ch^0x7);
		System.out.println("decoding:" + ch);
	}
}

执行结果:

before encoding:A 
after encoding:F 
decoding:A

0x7是Java中整数的16进位写法,其实就是10进位的7,将位与1作XOR的作用其实就是位反转,0x7的最右边三个位为1,所以其实就是反 转ch的最后两个位,如下所示:

01000001 -> 65 -> 对应ASCII中的'A'
00000111 -> 0x7
----------
01000110 -> 70 -> 对应ASCII中的'F'

同样的,这个简单的XOR字符加密,要解密也只要再进行相同的位反转就可以了。

要注意的是,虽然在说明时都只取8个位来说明,但实际的位在运算时,需依数据型态所占的内存长度而定,例如在使用int型态的0作运算时,要考虑的 是32个位,而不是只有8个位,因为int占有4个字节。

在位运算上,Java还有左移(<<)与右移(>>)两个运算子,左移运算子会将所有的位往左移指定的位 数,左边被挤出去的位会被丢弃,而右边会补上0;右移运算则是相反,会将所有的位往右移指定的位数,右边被挤出去的位会被丢弃,至于左边位补0或 补1 则视最左边原来的位而定,如果原来是0就补0,是1就补1,您还可以使用>>>运算子,这个运算子在右移后一行在最左边补上0。

可以使用左移运算来作简单的2次方运算示范,如下所示:

ShiftOperator.java
public class ShiftOperator {
	public static void main(String[] args) {
		int number = 1;
		System.out.println( "2的0次: " + number);
		number = number << 1;
		System.out.println("2的1次: " +?number);
		number = number << 1;
		System.out.println("2的2次: " + number);
		number = number << 1;
		System.out.println("2的3次:" + number);
	}
}

执行结果:

2的0次: 1 
2的1次: 2 
2的2次: 4 
2的3次:8

实际来左移看看就知道为何可以如此运算了:

00000001 -> 1
00000010 -> 2
00000100 -> 4
00001000 -> 8