操作符

Operators

既然你已经学会了如何声明和初始化变量,接下来你可能想知道如何对变量进行操作。学习Java编程语言的运算符是一个很好的起点。运算符是特殊符号,它们对一个、两个或三个操作数执行特定操作,然后返回结果。

在探索Java编程语言的运算符时,提前了解哪些运算符具有最高优先级会对您有所帮助。下表中的运算符按优先级顺序排列。运算符在表格中位置越靠上,其优先级越高。优先级较高的运算符将在优先级相对较低的运算符之前进行求值。同一行中的运算符具有相同优先级。当相同优先级的运算符出现在同一表达式中时,需遵循特定规则确定其计算顺序。除赋值运算符外,所有二元运算符均按从左到右的顺序计算;赋值运算符则按从右到左的顺序计算。

操作符 优先级
postfix expr++, expr–
unary ++expr, –expr, +expr, -expr, ~, !
multiplicative *, /, %
additive +, -
shift <<, >>, >>>
relational <,>,<=,>=,instanceof
equality ==, !=
bitwise AND &
bitwise exclusive OR ^
bitwise inclusive OR |
logical AND &&
logical OR ||
ternary ? :
assignment =,+=,-=,*=,/=,%=,&=,^=,|=,<<=,>>=,>>>=

在通用编程中,某些运算符的使用频率往往高于其他运算符;例如赋值运算符 = 的使用远比无符号右移运算符 >>> 更为普遍。基于此,下文将首先聚焦于日常工作中最常用的运算符,最后再探讨那些较少使用的运算符。每项讨论均附有可编译运行的示例代码,通过研究其输出结果,有助于巩固所学知识。

简单赋值运算符

你最常遇到的运算符之一就是简单的赋值运算符 =。你在 Bicycle 类中见过这个运算符;它将右侧的值赋给左侧的操作数:

int cadence = 0;
int speed = 0;
int gear = 1;

该运算符也可用于对象以分配对象引用。

算术运算符

Java编程语言提供了执行加法、减法、乘法和除法的运算符。这些运算符很可能与你在基础数学中接触过的对应运算符相似。唯一可能看起来陌生的符号是%,它表示将一个操作数除以另一个操作数,并返回余数作为结果。

操作符 描述
+ 加法运算符(也用于字符串连接)
- 减法运算符
* 乘法运算符
/ 除法运算符
% 求余运算符

以下程序 ArithmeticDemo 用于测试算术运算符。

public class ArithmeticDemo {
    public static void main(String[] args) {
        int result = 1 + 2;
        //result is now 3
        IO.println("1 + 2 = " + result);
        int original_result = result;

        result = result - 1;
        // result is now 2
        IO.println(original_result + " - 1 = " + result);
        original_result = result;

        result = result * 2;
        // result is now 4
        IO.println(original_result + " * 2 = " + result);
        original_result = result;

        result = result / 2;
        // result is now 2
        IO.println(original_result + " / 2 = " + result);
        original_result = result;

        result = result + 8;
        // result is now 10
        IO.println(original_result + " + 8 = " + result);
        original_result = result;

        result = result % 7;
        // result is now 3
        IO.println(original_result + " % 7 = " + result);
    }
}

运行该程序将产生以下输出:

1 + 2 = 3
3 - 1 = 2
2 * 2 = 4
4 / 2 = 2
2 + 8 = 10
10 % 7 = 3

您还可以将算术运算符与简单赋值运算符结合使用,形成复合赋值。例如,x += 1;x = x + 1; 都能将变量 x 的值增加 1。

  • 运算符也可用于连接(拼接)两个字符串,如下面的ConcatDemo程序所示:
public class ConcatDemo {
    public static void main(String[] args) {
        String firstString = "This is";
        String secondString = " a concatenated string.";
        String thirdString = firstString + secondString;
        IO.println(thirdString);
    }
}

本程序执行完毕时,变量 thirdString 包含字符串 This is a concatenated string.,该字符串将被打印到标准输出。

一元运算符

一元运算符仅需一个操作数;它们执行多种操作,例如将值增减1、取表达式的负值,或反转布尔值的状态。

操作符 描述
+ 一元加运算符;表示正值(不过数字本身是正的,无需此运算符)
- 一元减运算符;取表达式的负值
++ 递增运算符;将值增加1
递减运算符;将值减去1
逻辑取反运算符;将布尔值取反

以下程序 UnaryDemo 用于测试一元运算符:


public class UnaryDemo {
    public static void main(String[] args) {
        int  result = +1;
        // result is now 1
        IO.println(result);

        result--;
        // result is now 0
        IO.println(result);

        result++;
        // result is now 1
        IO.println(result);

        result = -result;
        // result is now -1
        IO.println(result);

        boolean success = false;
        // false
        IO.println(success);
        // true
        IO.println(!success);
    }
}

增量/减量运算符可置于操作数之前(前缀)或之后(后缀)。代码 result++;++result; 均会使 result 值增加 1。二者的唯一区别在于:前缀形式(++result)的表达式结果为递增后的值,而后缀形式(result++)的表达式结果为原始值。若仅执行简单递增/递减操作,选择哪种形式并无实质影响。但若在更复杂的表达式中使用该运算符,选择方式可能产生显著差异。
以下程序 PrePostDemo 演示了前缀/后缀一元自增运算符:

public class PrePostDemo {
    public static void main(String[] args) {
        int i = 3;
        i++;
        // prints 4
        IO.println(i);
        ++i;
        // prints 5
        IO.println(i);
        // prints 6
        IO.println(++i);
        // prints 6
        IO.println(i++);
        // prints 7
        IO.println(i);
    }
}

等号与关系运算符

等值运算符和关系运算符用于判断一个操作数是否大于、小于、等于或不等于另一个操作数。其中大多数运算符对您来说应该也很熟悉。请注意,在比较两个基本数据类型值是否相等时,必须使用 == 而非 =
以下程序 ComparisonDemo 用于测试比较运算符:

public class ComparisonDemo {
    public static void main(String[] args) {
        int value1 = 1;
        int value2 = 2;
        if (value1 == value2) {
            IO.println("value1 == value2");
        }
        if (value1 != value2) {
            IO.println("value1 != value2");
        }
        if (value1 > value2) {
            IO.println("value1 > value2");
        }
        if (value1 < value2) {
            IO.println("value1 < value2");
        }
        if (value1 <= value2) {
            IO.println("value1 <= value2");
        }
    }
}

运行此程序将产生以下输出:

value1 != value2
value1 < value2
value1 <= value2

条件运算符

&&|| 运算符对两个布尔表达式执行条件与和条件或运算。这些运算符具有”短路”特性,即仅在必要时才会求值第二个操作数。

运算符 描述
&& 条件与运算
|| 条件或运算

以下程序 ConditionalDemo1 测试了这些运算符:

public class ConditionalDemo1 {
    public static void main(String[] args) {
        int value1 = 1;
        int value2 = 2;
        if ((value1 == 1) && (value2 == 2)) {
            IO.println("value1 is 1 AND value2 is 2");
        }

        if ((value1 == 1) || (value2 == 1)) {
            IO.println("value1 is 1 OR value2 is 1");
        }
    }
}

另一个条件运算符是 ?:,可视为 if-then-else 语句的简写形式。该运算符因使用三个操作数而被称为三元运算符。在下例中,该运算符应解读为:”若 someCondition 为真,则将 value1 的值赋给 result;否则将 value2 的值赋给 result。”
以下程序 ConditionalDemo2 测试 ?: 运算符:

public class ConditionalDemo2 {
    public static void main(String[] args) {
        int value1 = 1;
        int value2 = 2;
        int result;
        boolean someConfition = true;
        result = someConfition ? value1 : value2;

        IO.println(result);
    }
}

由于 someCondition 为真,该程序将”1”输出到屏幕。当表达式紧凑且无副作用(如赋值操作)时,使用 ?: 运算符替代 if-then-else 语句可提升代码可读性。

类型比较运算符 instanceof

instanceof 运算符用于将对象与指定类型进行比较。你可以使用它来测试对象是否为某个类的实例、某个子类的实例,或是实现特定接口的类的实例。
以下程序 InstanceofDemo 定义了一个父类(命名为 Parent )、一个简单接口(命名为 MyInterface )以及一个继承自父类并实现该接口的子类(命名为 Child )。

public class InstanceOfDemo {
    public static void main(String[] args) {
        Parent obj1 = new Parent();
        Parent obj2 = new Child();

        IO.println("obj1 instanceof Parent: " + (obj1 instanceof Parent));
        IO.println("obj1 instanceof Child: " + (obj1 instanceof Child));
        IO.println("obj1 instanceof MyInterface: " + (obj1 instanceof MyInterface));

        IO.println("obj2 instanceof Parent: " + (obj2 instanceof Parent));
        IO.println("obj2 instanceof Child: " + (obj2 instanceof Child));
        IO.println("obj2 instanceof MyInterface: " + (obj2 instanceof MyInterface));
    }
}

class Parent{}
interface MyInterface{}
class Child extends Parent implements MyInterface{}

上面的程序将产生以下输出:

obj1 instanceof Parent: true
obj1 instanceof Child: false
obj1 instanceof MyInterface: false
obj2 instanceof Parent: true
obj2 instanceof Child: true
obj2 instanceof MyInterface: true

使用 instanceof 运算符时,请注意 null 不是任何类型的实例。

位运算符与位移运算符

Java 编程语言还提供了对整数类型执行位运算和位移运算的运算符。本节讨论的运算符使用频率较低,因此对其介绍较为简略;其目的仅在于让您了解这些运算符的存在。

一元位运算符~可对位模式进行反转;它可应用于任何整数类型,将所有”0”变为”1”,所有”1”变为”0”。例如,一个字节包含8位;对位模式为 00000000 的值应用此运算符后,其模式将变为 11111111

带符号左移运算符 << 将位模式向左移位,带符号右移运算符 > 将位模式向右移位。位模式由左操作数指定,移位位数由右操作数决定。无符号右移运算符 >>> 会在最左位移入零,而 > 操作后的最左位取决于符号扩展。

位运算符 & 执行位与运算。

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

位运算符 | 执行位或运算。

以下程序 BitDemo 使用位与运算符将数字 “2” 输出到标准输出。

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