Java运算符
最后修改于 2024 年 1 月 27 日
本文介绍如何在Java中使用运算符。
运算符是一种特殊符号,表示执行特定的过程。编程语言中的运算符取自数学。程序员处理数据。运算符用于处理数据。操作数是运算符的输入(参数)之一。
表达式由操作数和运算符构成。表达式的运算符指示要应用于操作数的操作。表达式中运算符的求值顺序由运算符的优先级和结合性决定。
运算符通常有一个或两个操作数。仅使用一个操作数的运算符称为一元运算符。使用两个操作数的运算符称为二元运算符。还有一个三元运算符?:
,它使用三个操作数。
某些运算符可以在不同的上下文中使用。例如,+
运算符。它可以用于不同的情况。它可以加数字、连接字符串或表示数字的符号。我们说运算符是重载的。
Java 符号运算符
有两个符号运算符:+
和 -
。它们用于表示或改变值的符号。
package com.zetcode; public class SignOperators { public static void main(String[] args) { System.out.println(2); System.out.println(+2); System.out.println(-2); } }
+
和 -
符号表示值的符号。加号可用于表示我们有一个正数。它可以省略,而且通常也是这样做的。
package com.zetcode; public class MinusSign { public static void main(String[] args) { int a = 1; System.out.println(-a); System.out.println(-(-a)); } }
减号会改变值的符号。
Java 赋值运算符
赋值运算符 =
将一个值赋给一个变量。变量是值的占位符。在数学中,= 运算符具有不同的含义。在一个等式中,=
运算符是一个相等运算符。等式的左侧等于右侧。
int x = 1;
在这里,我们将一个数字赋给 x
变量。
x = x + 1;
这个表达式在数学上没有意义,但在编程中是合法的。该表达式将 x 变量加 1。右侧等于 2,并将 2 赋值给 x。
3 = x;
此代码行会导致语法错误。我们不能将值分配给字面量。
Java 连接字符串
在 Java 中,+ 运算符也用于连接字符串。
package com.zetcode; public class ConcatenateStrings { public static void main(String[] args) { System.out.println("Return " + "of " + "the king."); System.out.println("Return".concat(" of").concat(" the king.")); } }
我们将三个字符串连接在一起。
System.out.println("Return " + "of " + "the king.");
字符串使用 +
运算符连接。
System.out.println("Return".concat(" of").concat(" the king."));
连接字符串的另一种方法是 concat
方法。
$ java ConcatenateStrings.java Return of the king. Return of the king.
Java 递增和递减运算符
在编程中,将一个值递增或递减 1 是一个常见的任务。Java 有两个方便的运算符:++
和 --
。
x++; x = x + 1; ... y--; y = y - 1;
以上两对表达式执行相同的操作。
package com.zetcode; public class IncDec { public static void main(String[] args) { int x = 6; x++; x++; System.out.println(x); x--; System.out.println(x); } }
在上面的示例中,我们演示了这两个运算符的用法。
int x = 6; x++; x++;
我们将 x
变量初始化为 6。然后我们对 x
加一两次。现在变量的值是 8。
x--;
我们使用了递减运算符。现在变量的值是 7。
$ java IncDec.java 8 7
这是示例的输出。
Java 算术运算符
下表是 Java 中的算术运算符。
符号 | 名称 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
% | 余数 |
下面的示例展示了算术运算。
package com.zetcode; public class Arithmetic { public static void main(String[] args) { int a = 10; int b = 11; int c = 12; int add = a + b + c; int sb = c - a; int mult = a * b; int div = c / 3; int rem = c % a; System.out.println(add); System.out.println(sb); System.out.println(mult); System.out.println(div); System.out.println(rem); } }
在前面的示例中,我们使用了加法、减法、乘法、除法和取余运算。这些都与数学中的一样熟悉。
int rem = c % a;
%
运算符称为余数或模运算符。它用于找出两个数相除的余数。例如,9 % 4
,9 模 4 等于 1,因为 4 能整除 9 两次,余数为 1。
$ java Arithmetic.java 33 2 110 4 2
接下来,我们展示整数和浮点数除法之间的区别。
package com.zetcode; public class Division { public static void main(String[] args) { int c = 5 / 2; System.out.println(c); double d = 5 / 2.0; System.out.println(d); } }
在前面的示例中,我们对两个数进行了除法运算。
int c = 5 / 2;
在这段代码中,我们进行了整数除法。除法运算的返回值是整数。当我们对两个整数进行除法时,结果是一个整数。
double d = 5 / 2.0;
如果其中一个值是双精度浮点数或单精度浮点数,我们就执行浮点数除法。在本例中,第二个操作数是双精度浮点数,所以结果也是双精度浮点数。
$ java Division.java 2 2.5
我们看到了程序的运行结果。
Java 布尔运算符
在 Java 中,我们有三个逻辑运算符。 boolean
关键字用于声明布尔值。
符号 | 名称 |
---|---|
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
布尔运算符也称为逻辑运算符。
package com.zetcode; public class BooleanOperators { public static void main(String[] args) { int x = 3; int y = 8; System.out.println(x == y); System.out.println(y > x); if (y > x) { System.out.println("y is greater than x"); } } }
许多表达式会产生布尔值。例如,布尔值用于条件语句。
System.out.println(x == y); System.out.println(y > x);
关系运算符始终产生布尔值。这两行打印 false 和 true。
if (y > x) { System.out.println("y is greater than x"); }
只有当括号内的条件满足时,才会执行 if
语句的主体。y > x
返回 true,因此消息 "y is greater than x" 会打印到终端。
true
和 false
关键字表示 Java 中的布尔字面量。
package com.zetcode; public class AndOperator { public static void main(String[] args) { boolean a = true && true; boolean b = true && false; boolean c = false && true; boolean d = false && false; System.out.println(a); System.out.println(b); System.out.println(c); System.out.println(d); } }
代码示例展示了逻辑与 (&&
) 运算符。仅当两个操作数都为 true 时,它才为 true。
$ java AndOperator.java true false false false
只有一个表达式的结果为 true
。
逻辑或 (||
) 运算符,如果任何一个操作数为真,则求值为 true
。
package com.zetcode; public class OrOperator { public static void main(String[] args) { boolean a = true || true; boolean b = true || false; boolean c = false || true; boolean d = false || false; System.out.println(a); System.out.println(b); System.out.println(c); System.out.println(d); } }
如果运算符的任一边为 true,则操作的结果为 true。
$ java OrOperator.java true true true false
四个表达式中有三个的结果为 true
。
否定运算符 !
将 true 变为 false,将 false 变为 true。
package com.zetcode; public class Negation { public static void main(String[] args) { System.out.println(! true); System.out.println(! false); System.out.println(! (4 < 3)); } }
该示例展示了否定运算符的实际应用。
$ java Negation.java false true true
||
和 &&
运算符是短路求值的。短路求值意味着仅当第一个参数不足以确定表达式的值时,才对第二个参数求值:当逻辑与的第一个参数求值为 false 时,总值必须为 false;当逻辑或的第一个参数求值为 true 时,总值必须为 true。短路求值主要用于提高性能。
一个例子可以更清楚地说明这一点。
package com.zetcode; public class ShortCircuit { public static boolean One() { System.out.println("Inside one"); return false; } public static boolean Two() { System.out.println("Inside two"); return true; } public static void main(String[] args) { System.out.println("Short circuit"); if (One() && Two()) { System.out.println("Pass"); } System.out.println("#############"); if (Two() || One()) { System.out.println("Pass"); } } }
我们在示例中有两个方法。 它们用作布尔表达式中的操作数。 我们将看到它们是否被调用。
if (One() && Two()) { System.out.println("Pass"); }
One
方法返回 false。 短路 && 不会评估第二个方法。 没有必要。 一旦一个操作数为假,逻辑结论的结果始终为假。 只有“Inside one”会打印到控制台。
if (Two() || One()) { System.out.println("Pass"); }
在第二种情况下,我们使用 ||
运算符并将 Two
方法用作第一个操作数。 在这种情况下,“Inside two”和“Pass”字符串会打印到终端。 同样,没有必要评估第二个操作数,因为一旦第一个操作数求值为 true,逻辑或始终为 true。
$ java ShortCircuit.java Short circuit Inside one ############# Inside two Pass
我们看到了程序的运行结果。
Java 关系运算符
关系运算符用于比较值。这些运算符始终产生布尔值。
符号 | 含义 |
---|---|
< | 小于 |
<= | 小于或等于 |
> | 大于 |
>= | 大于或等于 |
== | 等于 |
!= | 不等于 |
关系运算符也称为比较运算符。
package com.zetcode; public class Relational { public static void main(String[] args) { System.out.println(3 < 4); System.out.println(3 == 4); System.out.println(4 >= 3); System.out.println(4 != 3); } }
在代码示例中,我们有四个表达式。 这些表达式比较整数值。 每个表达式的结果为 true 或 false。 在 Java 中,我们使用 ==
来比较数字。(一些语言,如 Ada、Visual Basic 或 Pascal 使用 =
来比较数字。)
Java 位运算符
十进制数对人类来说很自然。 二进制数是计算机原生的。 二进制、八进制、十进制或十六进制符号只是数字的符号表示。 位运算符使用二进制数的位。 位运算符在 Java 等高级语言中很少使用。
符号 | 含义 |
---|---|
~ | 按位取反 |
^ | 按位异或 |
& | 按位与 |
| | 按位或 |
按位取反运算符 将每个 1 变为 0,将 0 变为 1。
System.out.println(~7); // prints -8 System.out.println(~ -8); // prints 7
运算符反转数字 7 的所有位。 其中一位还确定数字是否为负数。 如果我们再次否定所有位,我们将再次得到数字 7。
按位与运算符对两个数字执行逐位比较。只有当操作数中对应的位都为 1 时,结果的该位才为 1。
00110 & 00011 = 00010
第一个数字是 6 的二进制表示法,第二个是 3,结果是 2。
System.out.println(6 & 3); // prints 2 System.out.println(3 & 6); // prints 2
按位或运算符对两个数字执行逐位比较。当操作数中对应的位任一为 1 时,结果的该位为 1。
00110 | 00011 = 00111
结果是 00110
或十进制的 7。
System.out.println(6 | 3); // prints 7 System.out.println(3 | 6); // prints 7
按位异或运算符对两个数字执行逐位比较。当操作数中对应的位任一为 1 但不是两者都为 1 时,结果的该位为 1。
00110 ^ 00011 = 00101
结果是 00101
或十进制的 5。
System.out.println(6 ^ 3); // prints 5 System.out.println(3 ^ 6); // prints 5
Java 复合赋值运算符
复合赋值运算符是由两个运算符组成的简写运算符。
a = a + 3; a += 3;
+=
复合运算符是这些简写运算符之一。上面的两个表达式是相等的。将值 3 加到 a 变量上。
其他复合运算符是
-= *= /= %= &= |= <<= >>=
以下示例使用两个复合运算符。
package com.zetcode; public class CompoundOperators { public static void main(String[] args) { int a = 1; a = a + 1; System.out.println(a); a += 5; System.out.println(a); a *= 3; System.out.println(a); } }
我们使用 +=
和 *=
复合运算符。
int a = 1; a = a + 1;
a
变量初始化为 1。 使用非简写符号将值 1 添加到变量。
a += 5;
使用 +=
复合运算符,我们将 5 添加到 a 变量。 该语句等于 a = a + 5;
。
a *= 3;
使用 *=
运算符,a 乘以 3。 该语句等于 a = a * 3;
。
$ java CompoundOperators.java 2 7 21
Java instanceof 运算符
instanceof
运算符将对象与指定的类型进行比较。
package com.zetcode; class Base {} class Derived extends Base {} public class InstanceofOperator { public static void main(String[] args) { Base b = new Base(); Derived d = new Derived(); System.out.println(d instanceof Base); System.out.println(b instanceof Derived); System.out.println(d instanceof Object); } }
在该示例中,我们有两个类:一个基类和一个从基类派生的类。
System.out.println(d instanceof Base);
此行检查变量 d
是否指向作为 Base
类实例的类。 由于 Derived
类继承自 Base
类,因此它也是 Base
类的实例。 该行打印 true。
System.out.println(b instanceof Derived);
b
对象不是 Derived
类的实例。 此行打印 false。
System.out.println(d instanceof Object);
每个类都有 Object
作为超类。 因此,d
对象也是 Object
类的实例。
$ java InstanceofOperator.java true false true
Java Lambda 运算符
Java 8 引入了 lambda 运算符 (->
)。
(parameters) -> expression (parameters) -> { statements; }
这是 Java 中 lambda 表达式的基本语法。 Lambda 表达式允许在 Java 中创建更简洁的代码。
参数的类型声明是可选的;编译器可以从参数的值推断类型。 对于单个参数,括号是可选的;对于多个参数,它们是必需的。
如果表达式主体中只有一个语句,则大括号是可选的。 最后,如果主体有一个表达式要返回值,则 return 关键字是可选的; 需要大括号来指示表达式返回值。
package com.zetcode; import java.util.Arrays; public class LambdaExpression { public static void main(String[] args) { String[] words = { "kind", "massive", "atom", "car", "blue" }; Arrays.sort(words, (String s1, String s2) -> (s1.compareTo(s2))); System.out.println(Arrays.toString(words)); } }
在该示例中,我们定义了一个字符串数组。 该数组使用 Arrays.sort
方法和 lambda 表达式进行排序。
$ java LambdaExpression.java [atom, blue, car, kind, massive]
Lambda 表达式主要用于定义函数式接口的内联实现,即仅具有单个方法的接口。 接口是用于强制执行契约的抽象类型。
package com.zetcode; interface GreetingService { void greet(String message); } public class LambdaExpression2 { public static void main(String[] args) { GreetingService gs = (String msg) -> { System.out.println(msg); }; gs.greet("Good night"); gs.greet("Hello there"); } }
在该示例中,我们借助 lambda 表达式创建了一个问候服务。
interface GreetingService { void greet(String message); }
创建了 GreetingService
接口。 实现此接口的所有对象都必须实现 greet
方法。
GreetingService gs = (String msg) -> { System.out.println(msg); };
我们创建一个使用 lambda 表达式实现 GreetingService
的对象。 该对象具有一个将消息打印到控制台的方法。
gs.greet("Good night");
我们调用该对象的 greet
方法,该方法将给定的消息打印到控制台。
$ java LambdaExpression2.java Good night Hello there
有一些常见的函数式接口,例如 Function
、Consumer
或 Supplier
。
package com.zetcode; import java.util.function.Function; public class LambdaExpression3 { public static void main(String[] args) { Function<Integer, Integer> square = (Integer x) -> x * x; System.out.println(square.apply(5)); } }
该示例使用 lambda 表达式来计算整数的平方。
Function<Integer, Integer> square = (Integer x) -> x * x; System.out.println(square.apply(5));
Function
是一个接受一个参数并产生结果的函数。 lambda 表达式的操作产生给定整数的平方。
Java 双冒号运算符
双冒号运算符 (::) 用于创建对方法的引用。
package com.zetcode; import java.util.function.Consumer; public class DoubleColonOperator { private static void greet(String msg) { System.out.println(msg); } public static void main(String[] args) { Consumer<String> f = DoubleColonOperator::greet; f.accept("Hello there"); } }
在代码示例中,我们使用双冒号运算符创建对静态方法的引用。
private static void greet(String msg) { System.out.println(msg); }
我们有一个静态方法,可以将问候语打印到控制台。
Consumer<String> f = DoubleColonOperator::greet;
Consumer
是一个函数式接口,表示接受单个输入参数且不返回结果的操作。 使用双冒号运算符,我们创建对 greet
方法的引用。
f.accept("Hello there");
我们使用 accept
方法执行函数式操作。
Java 运算符优先级
运算符优先级告诉我们哪些运算符首先被求值。优先级级别对于避免表达式中的歧义是必需的。
以下表达式的结果是 28 还是 40?
3 + 5 * 5
就像在数学中一样,乘法运算符的优先级高于加法运算符。所以结果是 28。
(3 + 5) * 5
要更改求值顺序,我们可以使用括号。括号内的表达式总是首先被求值。上述表达式的结果是 40。
Java 运算符优先级列表
下表显示了按优先级排序的常见 Java 运算符(优先级最高的排在第一位)
运算符 | 含义 | 结合性 |
---|---|---|
[] () . |
数组访问、方法调用、对象成员访问 | 从左到右 |
++ -- + - |
递增、递减、一元加号和减号 | 从右到左 |
! ~ (type) new |
取反、按位非、类型转换、对象创建 | 从右到左 |
* / % |
乘法、除法、取模 | 从左到右 |
+ - |
加法、减法 | 从左到右 |
+ |
字符串连接 | 从左到右 |
<< >> >>> |
移位 | 从左到右 |
< <= > >= |
关系 | 从左到右 |
instanceof |
类型比较 | 从左到右 |
== != |
相等 | 从左到右 |
& |
按位与 | 从左到右 |
^ |
按位异或 | 从左到右 |
| |
按位或 | 从左到右 |
&& |
逻辑与 | 从左到右 |
|| |
逻辑或 | 从左到右 |
? : |
三元 | 从右到左 |
= |
简单赋值 | 从右到左 |
+= -= *= /= %= &= |
复合赋值 | 从右到左 |
^= |= <<= >>= >>>= |
复合赋值 | 从右到左 |
表中同一行的运算符具有相同的优先级。 如果我们使用具有相同优先级的运算符,则应用结合性规则。
package com.zetcode; public class Precedence { public static void main(String[] args) { System.out.println(3 + 5 * 5); System.out.println((3 + 5) * 5); System.out.println(! true | true); System.out.println(! (true | true)); } }
在这段代码示例中,我们展示了几个表达式。每个表达式的结果取决于优先级级别。
System.out.println(3 + 5 * 5);
此行打印 28。 乘法运算符的优先级高于加法。 首先,计算 5*5
的乘积,然后加 3。
System.out.println(! true | true);
在这种情况下,取反运算符的优先级高于按位或。 首先,初始的真值被取反为假,然后 |
运算符将假和真组合在一起,最终得到真。
$ java Precedence.java 28 40 true false
Java 结合性规则
有时优先级不足以确定表达式的结果。还有另一个规则称为结合性。运算符的结合性决定了具有相同优先级级别的运算符的求值顺序。
9 / 3 * 3
这个表达式的结果是 9 还是 1?乘法、除法和模运算符是从左到右结合的。所以表达式的求值方式是:(9 / 3) * 3
结果是 9。
算术、布尔、关系和位运算符都是从左到右结合的。 赋值运算符、三元运算符、递增、递减、一元加号和减号、取反、按位非、类型转换、对象创建运算符都是从右到左结合的。
package com.zetcode; public class Associativity { public static void main(String[] args) { int a, b, c, d; a = b = c = d = 0; String str = String.format("%d %d %d %d", a, b, c, d); System.out.println(str); int j = 0; j *= 3 + 1; System.out.println(j); } }
在该示例中,我们有两种情况,其中结合性规则确定了表达式。
int a, b, c, d; a = b = c = d = 0;
赋值运算符是从右到左结合的。 如果结合性是从左到右,则先前的表达式是不可能的。
int j = 0; j *= 3 + 1;
复合赋值运算符是从右到左结合的。 我们可能期望结果为 1。但实际结果为 0。这是因为结合性。 首先评估右侧的表达式,然后应用复合赋值运算符。
$ java Associativity.java 0 0 0 0 0
Java 三元运算符
三元运算符 ?:
是一个条件运算符。 对于我们想要根据条件表达式选择两个值之一的情况,它是一个方便的运算符。
cond-exp ? exp1 : exp2
如果 cond-exp 为 true,则评估 exp1 并返回结果。 如果 cond-exp 为 false,则评估 exp2 并返回其结果。
package com.zetcode; public class TernaryOperator { public static void main(String[] args) { int age = 31; boolean adult = age >= 18 ? true : false; System.out.println(String.format("Adult: %s", adult)); } }
在大多数国家/地区,成年是基于年龄的。 如果您超过某个年龄,您就是成年人。 这是三元运算符的一种情况。
boolean adult = age >= 18 ? true : false;
首先,计算赋值运算符右侧的表达式。三元运算符的第一阶段是条件表达式求值。因此,如果年龄大于或等于 18,则返回 ?
字符后面的值。否则,返回 :
字符后面的值。然后将返回的值赋给 adult 变量。
$ java TernaryOperator.java Adult: true
一个 31 岁的人是成年人。
计算质数
在以下示例中,我们将计算质数。
package com.zetcode; public class PrimeNumbers { public static void main(String[] args) { int[] nums = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }; System.out.print("Prime numbers: "); for (int num : nums) { if (num == 0 || num == 1) { continue; } if (num == 2 || num == 3) { System.out.print(num + " "); continue; } int i = (int) Math.sqrt(num); boolean isPrime = true; while (i > 1) { if (num % i == 0) { isPrime = false; } i--; } if (isPrime) { System.out.print(num + " "); } } System.out.print('\n'); } }
在上面的示例中,我们处理了几个运算符。质数(或素数)是一个自然数,它恰好有两个不同的自然数除数:1 和它本身。我们选择一个数字,然后用从 1 到所选数字的数字来除它。实际上,我们不必尝试所有较小的数字;我们可以用小于或等于所选数字的平方根的数字来除它。该公式将有效。我们使用求余运算符。
int[] nums = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 };
我们将从这些数字中计算质数。
if (num == 0 || num == 1) { continue; }
值 0 和 1 不被认为是质数。
if (num == 2 || num == 3) { System.out.print(num + " "); continue; }
我们跳过 2 和 3 的计算。它们是质数。请注意等号和条件或运算符的用法。==
的优先级高于 ||
运算符。所以我们不需要使用括号。
int i = (int) Math.sqrt(num);
如果我们只尝试小于目标数字的平方根的数字,那就可以了。
while (i > 1) { ... i--; }
这是一个 while 循环。i
是计算出的数字的平方根。我们使用递减运算符使 i
在每个循环周期中减一。当 i 小于 1 时,我们终止循环。例如,我们有数字 9。9 的平方根是 3。我们将用 3 和 2 除数字 9。这足以满足我们的计算。
if (num % i == 0) { isPrime = false; }
如果求余运算符对于任何 i 值返回 0,则目标数字不是质数。
在本文中,我们介绍了 Java 表达式。我们提到了各种类型的运算符,并描述了表达式中的优先级和结合性规则。
来源
作者
列出所有Java教程。