2.4 运算符

运算符的作用是与一定的运算数据组成表达式来完成相应的运算。对不同的数据类型,有着不同的运算符。对运算符,有运算对象(操作数)个数及类型、运算优先级、结合性等特性。

根据运算对象的多少,Java的运算符可分为一元(或称单目)、二元(双目)和三元(三目)运算符。

运算符的优先级是指不同运算符在运算中执行的先后顺序。在Java语言中共有17种优先级,每个运算符分属确定的一个优先级别。Java语言严格按照运算符的优先级由高到低地顺序执行各种运算。

运算符的结合性确定同级运算符的运算顺序。左结合性规定,运算数据先与左边的运算符结合,然后与右边的运算符结合。右结合性刚好相反。

本节介绍一些基本的Java运算符。部分未介绍的运算符在以后的章节中陆续介绍。

2.4.1 算术运算符

算术运算符的操作数类型是数值类型。

1.一元算术运算符

表2.6列出了一元算术运算符。它们的结合性是右结合。

表2.6 一元运算符列表

+和-运算符使运算对象取正、负值,用得不多,但它们有提升操作数类型的作用。例如:

              byte i=10,j; j = -i;

上述语句将产生编译错误,原因是i经过 - 运算后,已经提升为int类型,直接向字节变量j赋值是不允许的。

++和--既可以是前置运算符也是后置运算符,这就是说,它们既可以放在运算对象(必须是变量)前面(如++ x),也可以放在后面(如x ++)。单独使用的时候,前置后置作用相同。但若在表达式中使用,前置后置的意义是不同的。前置时,变量的值先增1 或减1,然后用变量的新值参加表达式的计算;后置时,变量的值先参加表达式的计算,然后变量再增1或减1。例如:

设i = 5;

j = i ++;

执行后,j为5,i为6。

而i = 5;

j = ++ i;

执行后,j为6,i为6。

【例2.2】说明++和--运算符的使用。

              class IncrementDecrement {
                public static void main(String args[]) {
                  int i,j,k;
                  i = 1;
                  k=(j=i++);
                  System.out.println("i= "+i+" j="+j+" k= "+k);
                  k=(i=2)*j--;
                  System.out.println("i= "+i+" j="+j+" k= "+k);
                  k=++i+ ++i+ ++i;
                  System.out.println("i= "+i+" j="+j+" k="+k);
                  k=i-- + i-- + i--;
                  System.out.println("i= "+i+" j="+j+" k="+k);
                }
              }

程序运行结果如下:

              i= 2 j=1 k= 1
              i= 2 j=0 k= 2
              i= 5 j=0 k=12
              i= 2 j=0 k=12

2.二元算术运算符

二元算术运算符不改变运算对象的值,而是得到一个可以保存和输出的计算结果。表2.7列出了二元算术运算符。二元算术运算符具有左结合性。

表2.7 二元算术运算符

这些都是常用的运算,对二元算术运算符,有两点要注意:

(1)两个整数运算的结果是整数,5/2结果是2而不是2.5。

(2)取模运算是求两个数相除的余数,如17%3 的结果是2。可以对实数求余数。实数a%b的结果为a-(int)(a/b)*b,余数的符号与被除数a相同。如123.4%10的结果为3.4。

2.4.2 关系运算符

关系运算符都是双目运算符,用于确定一个数据与另一个数据之间的关系,即进行关系运算(比较运算,将两个值进行比较)。关系运算的结果值为true、false(布尔型)。表2.8列出了Java语言提供的6种关系运算符。

表2.8 关系运算符

在这里要指出的是,等于运算符==不要与赋值运算符=混淆,以致于关系运算变成了赋值运算。

关系运算符常用于if语句、循环语句的条件中。运算符“==”和“!=”的运算优先级低于另外四个关系运算符,同一优先级中遵循自左至右的执行顺序。

2.4.3 布尔运算符

布尔运算符可以对布尔类型的数据(布尔常量、布尔变量、关系表达式和布尔表达式等)进行运算,结果也为布尔类型。表2.9 列出了Java语言的布尔运算符,布尔运算规则见表2.10。

表2.9 布尔运算符

表2.10 布尔运算真值表

简洁与、或和非简洁与、或的结果有时不同。非简洁与、非简洁或运算时,运算符两边的表达式都先要运算执行,然后两表达式的结果再进行与、或运算。简洁与、简洁或运算时,若只运算左边表达式即可确定与、或结果时,则右边的表达式将不会被计算。

例如,int x = 2,y = 3,a = 4,b = 5;

                boolean b = x ++ > y++ && a ++ > b ++;

则运算结果为:b = false, x = 3, y = 4, a = 4, b = 5

而boolean b = x ++ > y++ & a ++ > b ++;

运算结果为:b = false, x = 3, y = 4, a = 5, b = 6

几个布尔运算符中,单目布尔运算符!的优先级最高,而&又高于|。运算符!又高于算术运算符和关系运算符,运算符&、|低于关系运算符。布尔运算符的执行顺序为自左至右。在一个布尔表达式中,使用的运算符种类可能较多,应注意运算符的运算优先级。

【例2.3】布尔运算符的使用。

              public class RelationAndConditionOp{
                public static void main( String args[] ){
                  int a = 25,b = 3;
                  boolean d = a < b; // d = false
                  System.out.println("a < b = " + d );
                  int e = 3;
                  if(e != 0 && a / e > 5)System.out.println( "a / e = " + a / e );
                  int f = 0;
                  if(f != 0 && a / f > 5)
                  System.out.println("a / f = " + a / f);
                  else
                  System.out.println("f = " + f );
                }
              }

程序运行结果为:

              a < b = false
              a / e = 8
              f = 0

熟练地掌握关系运算符和布尔运算符,可以用逻辑表达式描述复杂的条件。

【例2.4】布尔表达式的使用。

(1)用int变量a,b,c表示三个线段的长,它们能构成一个三角形的条件是:任意两边之和大于第三边。该条件的Java布尔表达式为:

              (a + b) > c && (b + c) > a && (a + c) > b
              或 !((a + b) <= c || (b + c) <= a || (a + c) <= b)

(2)用int变量y,表示年号y是闰年:

              y % 400 == 0 | y % 4 == 0 & y % 100 != 0

(3)用int变量age存放年龄,boolean变量sex存放性别(true为男)。表示20岁与25岁之间的女性:

              20 <= age & age <= 25 & !sex

2.4.4 位运算符

位运算符用来对二进制位进行运算,运算操作数应是整数类型,结果也是整数类型。Java中提供了表2.11 所示的位运算符。表中前四种称为位逻辑运算符,后三种称为移位运算符。

表2.11 位运算符列表

为了理解位运算符的功能,应掌握运算数据的二进制表示形式。Java使用补码表示二进制数,在补码表示中,最高位为符号位。正数的符号位用0 表示,其余各位代表数值本身。例如,+1的8位补码为00000001。负数的符号位用1表示,通常用将负数的绝对值的补码取反加1的方法来得到负数的补码。例如,-1的8位补码为11111111(-1的绝对值的8位补码00000001按位取反加1为11111110+1=11111111),-42的补码为11010110 (-42的绝对值的8位补码00101010按位取反加1为11010101 + 1 = 11010110 )。

若两个数据长度不同(如short和int型),对它们进行位运算时,则系统首先会将长度短的数据的左侧用符号位填满(称为符号位扩展)。

1.按位取反运算符(~)

按位取反运算符“~”是一元运算符,对数据的各个二进制位取反,即将0 变为1,1变为0。例如:

              int a=0x45 , b;
              b=~a;           // b = 0xba

2.按位与运算符(&)

参与运算的两个值,如果两个相应的位都为1,则该位的结果为1,否则为0。例如:

              0 & 0 = 0,0 & 1 = 0,1 & 0 = 0,1 & 1 = 1

按位与可以用来把某些特定的位置0(复位),其他位不变。这时只需将要置0 的位同0与,而维持不变的位同1与。例如:

              int a = 0x45 , b = 0x31;
              b = a & b;            // b = 1

3.按位或运算符(|)

参与运算的两个值,如果两个相应的位都为0,则该位的结果为0,否则为1。即

              0 | 0 = 0,0 | 1 = 1,1 | 0 = 1,1 | 1 = 1

按位或可以用来把某些特定的位置1(置位),而不影响其他位。这时只需将要置1 的位同1或,而维持不变的位同0或。例如:

              int a = 0x45 , b = 0x31;
              b = a | b;              // b = 0x75

4.按位异或运算符(^)

参与运算的两个值,如果两个相应的位相同,则该位的结果为0,否则为1。例如:

              0 ^ 0 = 0,0 ^ 1 = 1,1 ^ 0 = 1,1 ^ 1 = 0

按位异或也称为按位加,可用于求反某些位。要求求反的位同1 异或,维持不变的位同0异或。这种运算有如下特性:(x^y)^y = x。例如:

              int a = 0x45,b = 0x31;
              b = a ^ b;              // b = 0x74

5.左移运算符(<<)

用来将一个数据的所有二进制位全部左移若干位。

在不产生溢出的情况下,数据左移1位相当于乘以2,而且用左移来实现乘法比乘法运算速度要快。例如:

              int a = 7 , b;
              b = a << 1;       // b = 14

6.算术右移运算符(>>)

用来将一个数据的所有二进制位全部右移若干位。移出的低位被舍弃,最高位用符号位补入。

右移1位相当于除以2取商,而且用右移来实现除法比除法运算速度要快。例如:

              int a = -20 , b;
              b = a >> 1;       // b = -10

但要注意,当移位数据为负且最低位有1 移出时,数据算术右移1 位与数据除以2 的结果不同。例如,-5(0xfb)右移1位等于-3,而(-5)/2的结果是-2。

7.逻辑右移运算符(>>>)

用来将一个数据的所有二进制位全部右移若干位。移出的低位被舍弃,最高位用0 补入。例如:

              int a = 0x88 , b;
              b = a >>> 2;      // b = 0x22(34)

2.4.5 赋值运算符

赋值运算符都是二元运算符,具有右结合性。

1.简单赋值运算符(=)

赋值运算符“=”用来将一个数据赋给一个变量。在赋值运算符两侧的类型不一致的情况下,若左侧变量的数据类型的级别高,则右侧的数据被转换为与左侧相同的高级数据类型,然后赋给左侧变量。否则,需要使用强制类型转换运算符。

2.复合赋值运算符

Java语言允许使用复合赋值运算符,即在赋值符前加上其他二元运算符。使用复合赋值运算符可简化表达式的书写。例如:a += 5等价于a = a + 5。复合赋值运算符有11种,见表2.12所示。

表2.12 复合赋值运算符

复合赋值运算符使用比较简单,但要注意下述两点。

(1)复合赋值运算符的右边是一整体,例如:

              a *= b + c;

等价于

              a = a * (b + c);

而不是

              a = a * b + c;

(2)表2.12中的等价是有条件的:即op1仅计算1次。例如:

设有int a[]={1,2},b=2,i=0; // a是一数组

则a[i++] += b; // 执行后i=1

不等价于a[i++]=a[i++] + b; // 执行后i=2

2.4.6 条件运算符

条件运算符是一种三元运算符,它的格式如下:

                    布尔表达式 ? 表达式1: 表达式2

在这个式子中,先计算布尔表达式的值,若为真,则计算并返回表达式1,若为假,则计算并返回表达式2。例如:

                    (a > b) ? a : b

这个表达式将返回a和b中较大的那个数值。

2.4.7 字符串运算符

运算符“+”可以实现两个或多个字符串的连接,也可实现字符串与其他类对象的连接,在连接时,其他类对象会被转换成字符串。另外,运算符“+=”把两个字符串连接的结果放进第一个字符串里,在前面的例子里,当想把几项输出内容输出在同一行里时使用的就是“+”运算符。