Java 运算符详解
一、算术运算符
在 Java 中,使用算术运算符+
、-
、*
、/
表示加减乘除运算。当运算的两个操作数都是整数时,表示整数除法;否则,表示浮点除法。整数的求余操作(有时称为取模)用%
表示。
需要注意,整数被 0 除将会产生一个异常,而浮点数被 0 除将会得到无穷大或NaN
结果。
//加法操作
int a=3;
int b=2;
int c=a+b;
System.out.println("a(3)+b(2)="+c);//a(3)+b(2)=5
//减法操作
int d=a-b;
System.out.println("a(3)-b(2)="+d);//a(3)-b(2)=1
//乘法操作
int e=a*b;
System.out.println("a(3)*b(2)="+e);//a(3)*b(2)=6
//整数除法
int f=a/b;
System.out.println("a(3)/b(2)="+f);//a(3)/b(2)=1
//浮点数除法
double a_=3.0;
double g=a_/b;
System.out.println("a_(3.0)/b(2)="+g);//a_(3.0)/b(2)=1.5
//整数取模运算
int h=a%b;
System.out.println("a(3)%b(2)="+h);//a(3)%b(2)=1
//浮点数取模运算
double j=a_%b;
System.out.println("a_(3.0)%b(2)="+j);//a_(3.0)%b(2)=1.0
二、数学函数与常量
- 计算一个数值的平方根,可以用
sqrt
方法。例如:double x = 4; double y = Math.sqrt(x); System.out.println("4 的平方根:" + y);//4的平方根:2.0
- 幂运算:
pow
方法。例如:double y_ = Math.pow(x, 2); System.out.println("4 的 2 次方:" + y_);//4的2次方:16.0
- 静态导入方法:
import static java.lang.Math.*;
这样就不必在数学方法名和常量名前添加前缀Math
。
三、数值类型之间的转换
上图中有6个实现箭头,表示无信息丢失的转换(弱类型向强类型转换);另外3的虚线箭头,表示可能有精度损失的转换。例如123456789是一个大整数,它所包含的位数比float所能够表示的位数多。当将这个整数转换为float类型是,将会损失一些精度(点击此链接,详细解释精度缺失的原因)
当用一个二元运算符连接两个值时(例如n + f
,n
是整数,f
是浮点数),先要将两个操作数转换为同一种类型,然后再进行计算。
- 如果两个操作数中有一个是
double
类型,另一个操作数就会转换为double
类型; - 否则,如果其中一个操作数是
float
类型,另一个操作数就会转换为float
类型; - 否则,如果其中一个操作数是
long
类型,另一个操作数就会转换为long
类型; - 否则,两个操作数都将被转换为
int
类型。
四、强制类型转换
在 Java 中,允许进行将double
转换成int
这种数值之间的类型转换,当然,在这个过程中会丢失一些信息。这种可能损失信息的转换要通过强制类型转换(cast)来完成。强制类型转换的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名。例如:
double x = 9.998;
int nx = (int)x;
这样,变量nx
的值为 9,因为强制类型转换通过截断小数部分将浮点值转换为整数。
如果相对浮点数进行舍入运算,以便得到最接近的整数(在很多情况下,这种操作更有用),那就需要使用Math.round
方法。例如:
double x = 9.998;
int nx = (int)Math.round(x);
现在,变量nx
的值为 10。当调用round
的时候,仍然需要使用强制类型转换(int)
,因为round
方法返回的结果为long
类型。
警告:如果试图将一个数值从类型强制转换为另一个类型,而又超出了目标类型的表示范围,结果就会截断成一个完全不同的值。例如:(byte)300
的实际值为 44,byte
表示的最大值为 127。
五、结合赋值和运算符
- 可以在赋值中使用二元运算符,这是一种很方便的简写方式。例如
x += 4;
等价于x = x + 4;
。 - 如果运算符得到一个值,其类型与左侧操作数的类型不同,就会发生强制类型转换。例如,如果
x
是一个int
,则以下语句x += 3.5;
是合法的,将把x
设置为(int)(x + 3.5)
。
六、自增与自减运算符
- 后缀形式:
n++
(先用后加);前缀形式:++n
(先加后用)。 - 建议不要在表达式中使用
++
,因为这样的代码很容易让人困惑,而且会带来烦人的 bug。
七、关系和 boolean 运算符
==
:检查相等性;!=
:检查不相等。- 还有常用的
<
、>
、<=
、>=
、&&
(逻辑与)、||
(逻辑或)。 - 三元运算符:
condition? expression1 : expression2
。例如x < y? x : y
会返回x
和y
中较小的一个。
八、位运算符
&
(“and”,按位与),|
(“or”,按位或),^
(“xor”,按位异或),~
(“not”,按位否)。- 左移运算符:
<<
,右移运算符:>>
。注意<<
左移运算符会用 0 填充高位,这与>>
不同,它会用符号位填充高位。不存在<<<
运算符。 - 浮点型没有移位操作。
- 移位运算符的右操作数要完成模 32 的运算(除非左操作数是
long
类型,在这种情况下需要对右操作数模 64)。 - 左移31位出现的特殊情况—>
在 Java 中,int类型是 32 位有符号整数。
当你执行1<<31时,这是将数字 1 的二进制表示向左移动 31 位。1 的二进制表示为00000000000000000000000000000001
,向左移动 31 位后变为10000000000000000000000000000000
。在有符号整数中,最高位(即第 32 位)为符号位,1 表示负数,0 表示正数。所以这个结果被解释为负数。其具体的值可以通过对该二进制数进行补码转换得到,即按位取反再加 1,最终得到的结果是 - 2147483648。
例如:
// 左移操作
System.out.println("3 左移 1 位:" + (3 << 1));// 3*2
System.out.println("3 左移 2 位:" + (3 << 2));// 3*2*2
System.out.println("3 左移 3 位:" + (3 << 3));// 3*2*2*2
// 右移操作
System.out.println("48 右移 1 位:" + (48 >> 1));// 48/(2)
System.out.println("48 右移 2 位:" + (48 >> 2));// 48/(2*2)
System.out.println("48 右移 3 位:" + (48 >> 3));// 48/(2*2*2)
// 移位的右操作数过大导致的情况
System.out.println("1 左移 31 位:" + (1 << 31));// -2147483648
System.out.println("1 左移 32 位:" + (1 << 32));// 1
System.out.println("1 左移 34 位:" + (1 << 34));// 4
九、括号与运算符级别
如果不使用圆括号,就按照给出的运算符优先级次序进行计算。同一级别的运算符按照从左到右的次序进行计算