语句

public class test{	
	public static void main(String args[]){
		int i = 3;
		float f = 3.14f;
		
		{
			i++;
			float f2 = f + 1f;
			System.out.println(f + " + 1 = " + f2 + ".");
		}
		
		System.out.println("i = " + i + ".");
		//System.out.println("f2 = " + f2 + ".");
	}
}

编译,运行,会在标准输出看到:

3.14 + 1 = 4.1400003.
i = 4.

如果去掉//System.out.println("f2 = " + f2 + ".");的注释,也就是尝试在复合语句之外访问在复合语句内创建的变量,那么编译时会报错:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	f2 cannot be resolved to a variable

	at test.main(test.java:13)

关于java的流程控制语句,本文不做扩展,本文着重深入了解表达式。


表达式

表达式有两种功能:每个表达式都产生一个值( value ),同时可能包含副作用( side effect ),比如可能修改某些值。


算数运算符

算术运算符用在数学表达式中,它们的作用和在数学中的作用一样。下表列出了所有的算术运算符。
表格中的实例假设整型变量A的值为10,变量B的值为20:

操作符 描述 例子
+ 加法 - 相加运算符两侧的值 A + B等于30
- 减法 - 左操作数减去右操作数 A – B等于-10
* 乘法 - 相乘操作符两侧的值 A * B等于200
/ 除法 - 左操作数除以右操作数 B / A等于2
% 取模 - 右操作数除左操作数的余数 B % A等于0

需要说明的:


自增和自减运算符

自增、自减运算符都是单目运算符,可以放在操作数之前,也可以放在操作数之后。操作数必须是整型或浮点型变量

下面是一个例子test.java:

public class test{	
	public static void main(String args[]){
		int a = 4, b;
		b = ++a;
		System.out.println(b);
		b = a++;
		System.out.println(b);
	}
}

编译、运行,会在标准输出打印:

5
5

关系运算符

关系运算符属于二元运算符,用于程序中的变量和变量之间、变量和常量之间、其他类型的信息之间的比较。关系运算符的返回类型是boolean类型,当运算符对应的关系成立时,运算结果是true,否则结果是false。关系运算符通常用在条件语句中,来作为判断的依据。
关系运算符的种类和用法如下表:

运算符 作用 举例 操作数据 结果
> 比较左方是否大于右方 'a' > 'b' 整型、浮点型、字符型 false
< 比较左方是否小于右方 156<456 整型、浮点型、字符型 true
== 比较左方是否等于右方 'c' = = 'c' 基本数据类型、引用型 true
>= 比较左方是否大于等于右方 479 >= 426 整型、浮点型、字符型 true
<= 比较左方是否小于等于右方 12.45 <= 45.5 整型、浮点型、字符型 true
!= 比较左方是否不等于右方 "y" != "t" 基本数据类型、引用型 false

逻辑运算符

逻辑运算符包括:逻辑与(&&、&)、逻辑或(||、|)和逻辑非(!),返回值为boolean类型,操作数也必须是boolean类型的数据。在逻辑运算符中,除了逻辑非(!)是一元运算符之外,其余两个都是二元运算符,其用法和含义如下表:

运算符含义用法结合方向
&&、&逻辑与op1&&op2左到右
||、|逻辑或op1||op2左到右
!逻辑非!op右到左

使用逻辑运算符进行逻辑运算,运行结果如下表:

表达式1表达式2表达式1&&表达式2表达式1||表达式2!表达式1
truetruetruetruefalse
truefalsefalsetruefalse
falsefalsefalsefalsetrue
falsetruefalsetruetrue

从上表可以看出:

TIPS:
逻辑运算符“&&”和“&”都表示逻辑与,
逻辑运算符“||”和“|”都表示逻辑或,

“&&”和“||”是短路的:
“&&”在第一个表达式为false的时候,不会计算第二个表达式;
“||”在第一个表达式为true的时候,不会计算第二个表达式;

“&”和“|”是非短路的:
在任何情况下,都会计算第二个表达式。

下面看一个例子test.java:

public class test{
	public static boolean func1(){
		System.out.println("func1 is called.");
		return true;
	}
	
	public static boolean func2(){
		System.out.println("func2 is called.");
		return false;
	}

	public static void main(String args[]){
		boolean r;
		r = func2() && func1();
		r = func2() &  func1();
		r = func1() || func2();
		r = func1() |  func2();
	}
}

编译、运行,会在标准输出打印:

func2 is called.
func2 is called.
func1 is called.
func1 is called.
func1 is called.
func2 is called.

位运算符

位运算符用于处理整型和字符型的操作数,对其内存进行操作,数值在内存中一律以补码的方式存储。例如int型常量7的二进制表示是00000000 00000000 00000000 00000111(正数的原码,反码,补码相同),-8的二进制表示是11111111 11111111 11111111 11111000(负数的补码是在原码的基础上,符号位不变,其余各个未取反,再加1);最高位为符号位,0表示正数,1表示负数。java语言提供的位运算符如下表:

运算符含义用法
~按位取反~op1
&按位与op1 & op2
|按位或op1 | op2
^按位异或op1 ^ op2

下面看几个例子:


移位运算符

java提供的移位运算符如下表:

运算符含义用法
<<左移op1 << op2
>>右移op1 >> op2
>>>无符号右移op1 >>> op2

java中移位运算符有三种,操作数的类型只有byte、short、int、long和char五种。

TIPS:
移位能让用户实现整数乘以或除以2的n次方的效果。例如y<<2与y*4的结果相同;y>>1与y/2的结果相同。总之,一个数左移n位,就是将这个数乘以2的n次方;一个数右移n位,就是将这个数除以2的n次方。

三元运算符

三元运算符是java中唯一一个三目运算符,其操作数有三个,第一个是条件表达式,其余两个是值。条件表达式成立时,取第一个值;条件表达式不成立时,取第二个值。示例代码如下:
boolean b = 20 < 45 ? true : false;
因为条件表达式20 < 45成立,所以取第一个值,此例的结果是true。


赋值运算符

赋值运算符=是一个二元运算符,其功能是将右边的操作数所含的值赋给左边的操作数。语法格式如下:
[变量类型] 变量名 = 所赋的值;
左边的操作数必须是一个变量,右边的操作数可以是变量、常量或表达式。

赋值运算符是有返回值的。比如int x, y, z; x = y = z = 5;因为赋值运算符是右结合的,所以先计算z = 5,此时z的值为5,并且z = 5这个表达式的值为5,所以x = y = z = 5转换成了x = y = 5,然后计算y = 5,此时y的值为5,并且y = 5这个表达式的值是5,所以x = y = 5转换成了x = 5,此时x的值是5。所以最终x、y、z的值都是5。
混合赋值运算符包括:

运算符描述例子
+=加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数C + = A等价于C = C + A
-=减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 C - = A等价于C = C - A
*=乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 C * = A等价于C = C * A
/=除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 C / = A等价于C = C / A
%=取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 C%= A等价于C = C%A
<<=左移位赋值运算符C << = 2等价于C = C << 2
>>=右移位赋值运算符C >> = 2等价于C = C >> 2
&=按位与赋值运算符C&= 2等价于C = C&2
^ =按位异或赋值操作符C ^ = 2等价于C = C ^ 2
|=按位或赋值操作符 C | = 2等价于C = C | 2

instanceof运算符

instanceof运算符是一个二元运算符,只用于对象引用变量,它的作用是测试一个对象是否为特定类型(类类型或接口类型)的对象。用法:
( Object reference variable ) instanceof (class/interface type)
如果左侧的对象引用变量 是class的实例 或者是class或interface的子类的实例,那么返回true,否则返回false。

下面是一个例子test.java:

interface i{
}

class c implements i{
}

class c2 extends c{
}

public class test{
	public static void main(String args[]){
		c2 obj = new c2();
		System.out.println(obj instanceof c);
		System.out.println(obj instanceof c2);
		System.out.println(obj instanceof i);
	}
}

编译、运行,会在标准输出打印:

true
true
true

运算符的优先级和结合性

在同一个表达式中,先计算优先级高的运算符,再计算优先级低的运算符,对于优先级相同的运算符,按照结合性来确定计算顺序,如果运算符是左结合的,就先计算左边的运算符,如果运算符是右结合的,就先计算右边的运算符。

序列号

符号

名称

结合性(与操作数)

目数

说明

1

.

从左到右

双目

 

( )

圆括号

从左到右

 

 

[ ]

方括号

从左到右

 

 

2

+

正号

从右到左

单目

 

-

负号

从右到左

单目

 

++

自增

从右到左

单目

前缀增,后缀增

- -

自减

从右到左

前缀减,后缀减

~

按位非/取补运算

从右到左

单目

 

逻辑非

从右到左

单目

!”不可以与“=”联用

3

*

从左到右

双目

 

/

从左到右

双目

整数除法:取商的整数部分,小数部分去掉,不四舍五入

%

取余

从左到右

双目

 

4

+

从左到右

双目

 

-

从左到右

双目

 

5

<< 

左移位运算符

从左到右

双目

 

>> 

带符号右移位运算符

从左到右

双目

 

>>> 

无符号右移

从左到右

双目

 

6

小于

从左到右

双目

<=

小于或等于

从左到右

双目

 

大于

从左到右

双目

 

>=

大于或等于

从左到右

双目

 

instanceof

确定某对象是否属于指定的类

从左到右

双目

 

7

==

等于

从左到右

双目

!=

不等于

从左到右

双目

 

8

&

按位与

从左到右

双目

 

9

|

按位或

从左到右

双目

 

10

^

按位异或

从左到右

双目

 

11

&&

短路与

从左到右

双目

 

12

||

短路或

从左到右

双目

 

13

? :

条件运算符

从右到左

三目

 

14

=

赋值运算符

从右到左

双目

 

+=

混合赋值运算符

 

-=

 

*=

 

/=

 

%=

 

&=

 

|=

 

^=

 

<<=

 

>>=

 

>>>=

 

概括而言,优先级从高到低的顺序是:后缀运算符(点、圆括号、方括号)、单目运算符、算数运算符、移位运算符、关系运算符和instanceof、位运算符、逻辑运算符、条件运算符、赋值运算符、混合赋值运算符。
右结合的运算符有:所有的单目运算符、条件运算符、所有的赋值运算符。其余的运算符都是左结合的。


参考文档