- Java程序设计与应用开发(第3版)
- 吴敏 於东军 李千目主编 成维莉 邵杰 姜小花副主编
- 3848字
- 2025-03-22 04:39:42
2.2 操作符
操作符可以对若干个操作数进行特定的运算。根据操作符需要操作数的不同,可以将操作符分为以下3类:
•一元操作符。
•二元操作符。
•三元操作符。
一元操作符只能对一个操作数进行运算。一元操作符可以用两种形式表述:前缀式和后缀式。前缀式是指操作符在前,操作数在后,例如:
++a;
++是一元操作符,a为操作数。
后缀式正好相反,操作符在后,操作数在前,例如:
a++;
二元操作符对两个操作数进行运算。加(+)、减(-)、乘(*)、除(/)、求模(%)以及赋值(=)都是二元操作符。例如:
a=7+8;
二元操作符“+”对7和8这两个操作数进行运算得到结果15。二元赋值操作符“=”再对15和a这两个操作数进行运算,结果就是将a赋值为15。
Java语言中还有一个特殊的三元操作符“?:”,对3个操作数进行运算。一般表示形式为:
condition ? result1:result2;
如果第一个操作数condition的值为true,那么取值result1;反之取值result2。例如:
min=x>y?y:x;
最终,min的值为x与y中较小的值。
注意:三元操作符中的第一个操作数必须为布尔类型的值。
下面按照操作符的功能分别加以分类讲解。
2.2.1 算术操作符
加(+)、减(-)、乘(*)、除(/)、求模(%)是Java编程语言中提供的算术操作符。算术操作符只能对浮点型和整型数据类型的操作数进行运算。算术操作符的功能如表2.5所示。
表2.5 算术操作符

例如:
int x; //变量声明 x=100+50; //赋值,该语句执行完毕后,x的值为150 x=x+100; //赋值,该语句执行完毕后,x的值为250
还可以使用如下语句对变量进行赋值:
x+=100;
它等价于:
x=x+100;
每个算术操作符在用于赋值运算时可以有其对应的简捷形式,如表2.6所示。
表2.6 算术操作符用于赋值运算时的简捷形式

在应用程序开发过程中,经常会用到的是让一个变量加1或是减1(例如在循环中)。当然可以使用如下语句:
i=i+1;
或是:
i+=1;
但Java语言中提供了一种更加简捷的操作符,称为递增操作符(++)和递减操作符(--)。因此,要让一个变量i加1,可以使用:
i++;
或是:
++i;
同样,让一个变量i减1,可以使用:
i--;
或是:
--i;
如前所述,i++是后缀方式,++i是前缀方式。虽然这两种方式最终都会使i的值加1,但还是存在不同之处的。下面的这段代码说明了它们的区别:
int a=100; int b=100; int c=++a; //a先增加1,然后将a的值赋给c int d=b++; //先将b的值赋给d,然后b的值再增加1 System.out.println("a="+a); System.out.println("b="+b); System.out.println("c="+c); System.out.println("d="+d);
观察这段代码的输出结果,可以发现a、b、c和d的值分别为101、101、101、100。也就是说,a和b的值确实都增加了1。但是c和d的值为何不同呢?
由于前缀方式的自增操作符是“先增加,后使用”,而后缀方式的自增操作符是“先使用,后增加”。这就产生了c和d值不同的结果。同样自减操作符具有类似的性质。
注意:由于自增(自减)操作符的特性,除了在循环中用于循环变量的自增(自减)操作,其他容易产生歧义的代码中尽量不要使用。
2.2.2 关系与条件操作符
关系操作符是二元操作符,用于比较两个操作数的值并确定它们之间的关系,关系操作符的运算结果是一个布尔值。Java编程语言中共有6个关系操作符,如表2.7所示。
表2.7 关系操作符

例如:100==101的值为false;100>=100的值为true。
关系操作符在程序中经常和条件操作符联合使用,用作条件判断以控制程序的执行流程。Java语言中提供了6种条件操作符(见表2.8),条件操作符只能对布尔类型的操作数进行运算,并且运算结果也是布尔类型的值。
表2.8 条件操作符

观察表2.8,可以发现&&和&都需要两个操作数的值均为true时,才取值true。但是这两个操作符还是有区别的,例如:
(x>y)&&(x>z);
如果x>y的值是false,那么x>z的值将不再计算,(x>y)&&(x>z)直接取值false;而:
(x>y)&(x>z);
即使x>y的值是false,但x>z的值仍需计算,尽管x>z的值已经不会影响x>y&x>z的结果。这就是为什么称&&为“条件与”的理由:只有在满足第一个操作数的值为true的条件下,才计算第二个操作数的值。类似的区别还存在于“||”和“|”之间。
下面的几个例子说明了条件操作符的应用:
!(4>3) //值为false; (4>3)^(5>6) //值为true; (3>4)&&(6>5) //值为false; 6>5的值不需计算 (4>3)||(5>6) //值为true; 5>6的值不需计算 (3>4)&(6>5) //值为false; 6>5的值仍需计算 (4>3)|(5>6) //值为true; 5>6的值仍需计算
注意:在操作数为布尔类型时,操作符&、|和^是作为条件操作符。但是当操作数为数值类型时,操作符&、|和^是作为位操作符,见2.2.3小节。
2.2.3 位操作符
在计算机内部,数据是以二进制编码存储的,Java编程语言允许我们对这些二进制编码进行位运算,位操作符如表2.9所示。
表2.9 位操作符

例如,12的编码是1100,7的编码是0111,那么:
12&7; // 结果的二进制编码为0100,对应的值为4 12|7; // 结果的二进制编码为1111,对应的值为15 12^7; // 结果的二进制编码为1011,对应的值为11
因为:

如果对12进行移位操作:
12>>2; //结果的二进制编码为11,对应的值为3 7<<2; //结果的二进制编码为11100,对应的值为28
注意:>>和>>>都是右移操作符,但是两者是有区别的。使用>>>时,前面的位填0;而使用>>时,前面填充的是符号位。
2.2.4 其他类型操作符
除了上面介绍的操作符外,Java还提供了如下类型的操作符,如表2.10所示。
表2.10 其他类型的操作符

这里只对这些操作符的功能进行简单介绍,更多内容请参见相关章节。
1. [ ] 操作符
操作符[ ]用于声明、创建数组。还可用于访问数组中的特定元素。例如:
double [ ]salary=new double[20];
其中第一个[ ]操作符声明salary是一个数组,而第二个[ ]操作符创建一个可以存储20个double类型数据的数组。再如下面这条语句:
salary[0]=22.2;
上面这条语句中的[ ]操作符用于访问数组中特定位置(这里是第一个元素,Java语言中数组标号是从0开始的,依次递增)的数组元素,这里是将数组salary中的第一个元素赋值为22.2。
2. 操作符
操作符用于访问类的类变量、对象的实例变量或方法。
3. (参数)操作符
操作符(参数)用于声明或是调用一个方法。
4. (数据类型)操作符
操作符(数据类型)称为转型(cast),将一种数据类型转化为另一种数据类型。例如:
double salary=23.45; int intSalary=(int)salary;
这样,通过将double型的salary强制转换成int型的intSalary, intSalary的值是23。
注意:()除了用作操作符的功能外,还可在表达式中用来指示操作数运算的执行顺序。
5. new操作符
new操作符用于创建对象,例如:
String aString=new String("This is a string");
6. instanceOf操作符
instanceOf操作符的用法是:
anObject instanceOf aClass
用于判断对象anObject是否为类aClass的一个实例,返回的是布尔类型的值。
2.2.5 数字类型转换
在实际的应用开发过程中,常常会需要在数字类型之间进行转换。一方面,使用算术操作符对数字进行运算时,系统在适当的时候会自动进行数字类型的转换;另一方面,程序开发人员还可以显式地进行数字类型之间的强制类型转换。
1. 自动数字类型转换
下面的代码片段会输出133.34:
int x=100; double y=33.34; System.out.println(x+y);
实际上,在运算过程中,x首先被自动转换成double数据类型,然后再进行相加,得到一个double类型的运算结果。因此,上述代码片段中,如果把x+y的值赋给一个整型变量,编译器就会报错。例如:
int x=100; double y=33.34; int c=x+y; //错误,不能将一个double类型的值赋给int类型的变量
使用算术操作符进行运算时,得到的数值类型取决于操作数的类型。在需要时,操作数会自动进行数据类型的转换,如表2.11所示。
表2.11 算术运算返回值类型与操作数类型之间的关系

2. 强制类型转换
虽然系统在需要的时候会自动进行数字类型的转换,但有的时候,我们希望能够主动将一种数据类型转换为另一种数据类型。这时候就可以使用显式的强制类型转换,也称为转型(cast)。例如要知道一个double类型数据的整数部分的值是多少:
double salary=103.34; int intSalary=(int)salary; //intSalary的值为103
这样的结果是把salary小数部分的值截去,然后把整数部分的值赋给整型变量intSalary。
需要注意的是,在不同数值类型之间转换是有可能丢失信息的。例如将一个long类型的数值强制转化为int类型时,如果该long类型的值在int类型所能表示的范围之外,那么就不能进行正确的转换了。图2.3给出了数字类型之间的合法转换,该图中的实线箭头表示的转换不会丢失信息;虚线箭头表示的转换可能会丢失精度。

图2.3 数字类型之间的合法转换
注意:不仅数字类型之间可以进行类型转换(转型),对象之间也可以进行类型转换(转型)。但布尔类型不能进行任何类型的转换。
2.2.6 操作符优先级
不同的操作符具有不同的运算优先级,如表2.12所示。
表2.12 操作符优先级

注:第一行中的()是指用于方法调用时的操作符,第二行中的()是指用于强制类型转换时的操作符。
同一行上操作符的优先级别相同,但是优先次序从左至右递减(右结合的操作符除外);同一列上操作符的优先级从上至下递减。
注意:并不建议强记表2.12中操作符的优先级。在容易混淆的地方,建议在程序代码中使用圆括号明确指明运算的优先次序。
例如,不建议使用类似下面的语句:
c=x+++y/100+z;
因为这种语句容易给程序的阅读带来困难,并给日后的维护带来麻烦。
建议使用圆括号明确指出运算的执行次序,如:
((x++)+y)/(100+z);
或是:
(x+(++y))/(100+z);
2.2.7 表达式、语句和块
在前面讲述变量和操作符的过程中,已经涉及表达式、语句和块的概念。这里再进行综合性的阐述。
1. 表达式
表达式是由变量、操作符或是方法调用所组成的一个运算序列,并且返回一个值。表达式用作变量的赋值或是控制程序的执行流程,例如:
double salary=100; // ① String name="Tom"; // ② if(salary>50&&name.equals("Tom")){ // ③ ... } else{ ... }
上面的代码片段中,粗体部分(不包括分号)表示的是3个表达式:表达式①和②的作用是给变量赋值,表达式③的作用是控制程序的执行流程。
注意:表达式总是完成一定的运算,然后返回一个值。
例如表达式①先完成赋值运算,然后返回值100。而表达式③先运算salary>50,返回true;然后name.equals("Tom")是实例方法调用,判断name的值是否为Tom,返回值也是true;最后进行关系运算,得到结果true作为表达式③的返回值。
2. 语句
所谓语句,是指程序中的一个完整的执行单元。
表达式后面添加分号(;)可以构成一条语句,例如:
double salary=100; //声明语句,而salary=100是表达式 salary=200; //赋值语句,而salary=200是表达式 i--; //自减语句,而i--是表达式 i++; //自增语句,而i++是表达式
方法调用后面添加分号可以构成方法调用语句:
System.out.println("Hello World"); //方法调用语句
除此以外,还有控制流语句,例如if、for以及switch等,用于控制程序的执行流程,参见2.4节。
3. 块
块由一对花括号之间的零条或多条语句所构成。参见2.1.3小节“变量的作用域”。