Java语言程序设计
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.6 表达式

表达式是由操作数和运算符按一定的语法形式组成的符号序列。每个表达式结果运算后都会产生一个确定的值,称为表达式的值。表达式的值是有类型的,该类型称为表达式类型。表达式类型由运算符和参与运算的数据的类型决定。可以是简单类型,也可以是复合类型。

一个常量或一个变量是最简单的表达式,表达式的值即该常量或变量的值。用运算符连接几个表达式构成的式子仍是表达式。

可以按表达式值的类型将表达式分类。

2.6.1 类型转换

在一个表达式中可能有不同类型的数据进行混合运算,这是允许的,但在运算时,Java将不同类型的数据转换成相同类型,再进行运算。

1.自动类型转换

整型、实型和字符型数据可以进行混合运算。在运算中,不同类型的数据先转换成相同类型,然后再进行运算。转换从低级到高级。可混合运算数据类型从低到高排列如下:

           (低)->byte,short,char,int,long,float,double ->(高)

不同类型数据之间的转换规则如表2.14。

表2.14 不同类型数据之间的转换规则

2.强制类型转换

高级数据要转换为低级数据时,需进行强制类型转换。例如:

                    int a;
                    char b;
                    b=(char)a;

加括号的char告诉编译器想把整型的a转换为字符类型并把它赋值给b。

由于整型和字符型变量位长是不同的,整型是32 位长,字符型是16 位长,所以从整型转换到字符型可能会丢失信息。同样,当把64 位的长整型数转换为整型时,由于长整型可能有比32 位更多的信息,也很可能会丢失信息。即使两个量具有相同的位数,比如整型和单精度实型数据(都是32位),在转换小数时也会丢失信息。当进行类型转换要注意使目标类型能够容纳原始类型的所有信息,不会丢失信息的类型转换见表2.15。

表2.15 不会丢失信息的类型转换

需要说明的是,当执行一个这里并未列出的类型转换时可能并不总会丢失信息,不过进行这样一个理论上并不安全的转换总是很危险的。

3.表达式求值中的自动类型提升

在表达式的求值过程中,运算中间值的精度有时会超出操作数的取值范围。例如:

              byte x = 30,y = 50,z = 100;
              int a = x * y / z;

在运算x*y项时,结果1500 已经超出了操作数byte类型的范围。为解决这类问题,Java语言在对表达式求值时,自动提升byte或short类型的数据为int类型的。Java语言对表达式求值的自动类型提升规则为:

(1)所有byte和short类型提升为int类型。

(2)若一个操作数是long类型,则整个表达式提升为long类型。

(3)若一个操作数是float类型,则整个表达式提升为float类型。

(4)若有double类型,则表达式值为double类型。

自动类型提升对数据的运算带来了方便,但也容易引起编译错误。例如:

              byte x = 30;
              x = - x;       // 编译错误!不能向byte变量赋已提升的int类型值

【例2.6】不同类型数据的混合运算。

              class Promote {
                public static void main(String args[]) {
                  byte b = 42;
                  char c = 'a';
                  short s = 1024;
                  int i = 50000;
                  float f = 5.67f;
                  double d = .1234;
                  double result = (f * b) + (i / c) - (d * s);
                  System.out.println((f * b) + " + " + (i / c) + " - " + (d * s));
                  System.out.println("result = " + result);
                }
              }

程序运行结果如下:

              238.14 + 515-126.3616
              result = 626.7784146484375

2.6.2 优先级

在一个表达式中可能有各种运算符,Java语言规定了表达式中出现各种运算符的时候,哪种运算符先进行运算,哪种运算符后进行运算的运算符的运算顺序,称为运算符的优先级,它指明了同一表达式中多个运算符被执行的次序,同一级里的操作符具有相同的优先级。在表达式中,优先级高的运算符先进行运算。例如对于表达式:

                    a = b + c * d / (c ^ d)

Java处理时将按照表2.16 所列从最高优先级到最低优先级的次序进行。在上例中,因为括号优先级最高,所以先计算c^d,接着是c*d,然后除以c^d,最后,把上述结果与b的和存储到变量a中。

不论任何时候,若一时无法确定某种计算的执行次序时,可以使用加括号的方法明确为编译器指定运算顺序,这也是提高程序可读性的一个重要方法。例如,对表达式:

              a | 4 + c >> b & 7 || b > a % 3

运算次序的理解就不如下面的表达式清晰,因为在下面的表达式中用括号()显式地表明了运算次序。

              (a | (((4 + c) >> b) & 7)) || (b > (a % 3))

表2.16按从高到低的优先级列出了运算符。同一行中的运算符优先级相同。

表2.16 运算符优先级

2.6.3 结合性

在表达式中出现多个相同优先级的运算符时,就需要考虑结合性。结合性确定同级运算符的运算顺序。运算符有左结合性和右结合性两种。左结合性指的是从左向右使用运算符。例如二元算术运算符具有左结合性,计算a + b - c时,操作数b的左、右运算符 +、-是同级运算符,计算时,b先与左边的 + 结合,计算a + b,其和再与c相减;而右结合性是从右向左使用运算符。例如,赋值运算符具有右结合性,计算a = b = c时,操作数b的左、右运算符都是同级的赋值运算符,所以,先执行b = c,再执行a = b。