首先,我先讲一下Java运算符与可移植性。
Java语言中一个设计目标是可移植性。无论在哪个虚拟机上运行,同一个计算应该得到同样的结果。
对于浮点数的算术运算,实现这样的可移植性是相当困难的。double 类型使用 64 位存储一个 double 数值,
得到一个更为精确的计算结果,并且还能够避免产生指数溢出。但是,这个结果可能与始终在 64 位机器上计算的
结果不一样。因此,Java 虚拟机最初规范规定所有的中间计算都必须进行截断。这种行为遭到了数值计算团体的
反对。截断计算不仅可能导致溢出,而且由于截断操作需要消耗时间,所以在计算机速度上要比精确计算慢。为此,
Java 程序设计语言承认了最优性能与最理想结果之间的冲突,并予以了改进。在默认情况下,虚拟机设计者允许将
中间计算机结果采用扩展的精度。但是,对于使用 strictfp 关键字标记的方法来说,必须使用严格的浮点计算,以
后缀形式: n++
n--
前缀形式: ++n
--n
2)关系运算符与boolean运算符
Java包含各种关系运算符。
其中,使用两个等号==检测是否相等。
使用!=检测是否不相等。
另外,经常使用的运算符还有<,>,<=,>=。
Java沿用了C++的习惯,用&&表示逻辑“与”,用||表示逻辑“或”。&&和||是按照“短路”方式求值的。如果第一个
操作数已经能够确定表达式的值,第二个操作数就不必计算了。
最后,Java支持三元操作符?:。
condition ?expression1 : expression2
当条件condition为真时计算第1个表达式,否则计算第2个表达式。
3)位运算符
在处理整型数值时,可以直接对组成整型数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位。位
运算符包括:
&(与)、|(或)、^(异或)、~(非)
这些运算符在位模式下工作。
另外,“>>”和“<<”运算符将二进制位进行右移或左移操作。
最后,>>>运算符将用0填充高位,>>运算符用符号位填充高位。没有<<<运算符。
4)数学函数与常量
在Math类中,包含了各种各样的数学函数。
double y = Math.pow(x, a); //将y的值设置为x的a次幂
Math.sin
Math.cos
Math.tan
Math.atan
Math.atan2
还有指数函数以及它的反函数:
Math.exp
Math.log
Math.log10
最后,Java还提供了两个用于表示pi和e的近似值:
Math.PI
Math.E
注释:在Math类中,为了达到最快的性能,所有的方法都使用计算机浮点单元中的例程。如果得到一个完全可预测的结果
比运行速度更重要的话,那么就应该使用StrictMath类。它使用“自由发布的Math库”(fdlibm)实现算法,以确保在所
有平台上得到相同的结果。
5)数值类型之间的转换
如果两个操作数中有一个是double类型,另一个操作数就会转换为double类型。
否则,如果其中中有一个操作数是float类型,另一个操作数就会转换为float类型。
否则,如果其中中有一个操作数是long类型,另一个操作数就会转换为long类型。
否则,两个个操作数都被转换为int类型
6)强制类型转换
强制类型转换(cast)的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名。当然,有可能会
丢失一些信息。
如果试图将一个数值从一种类型强制转换为另一种类型,而又超出了目标类型的表示范围,结果就会截断成一个完全不
Java语言中一个设计目标是可移植性。无论在哪个虚拟机上运行,同一个计算应该得到同样的结果。
对于浮点数的算术运算,实现这样的可移植性是相当困难的。double 类型使用 64 位存储一个 double 数值,
而有些处理器使用 80 位浮点寄存器。这些寄存器增加了中间过程的计算精度。例如:
double w = x * y / z;
很多 Intel 处理器计算 x * y,并且将结果存储在 80 位的寄存器中,再除以 z 将结果截断为 64 位。这样可以得到一个更为精确的计算结果,并且还能够避免产生指数溢出。但是,这个结果可能与始终在 64 位机器上计算的
结果不一样。因此,Java 虚拟机最初规范规定所有的中间计算都必须进行截断。这种行为遭到了数值计算团体的
反对。截断计算不仅可能导致溢出,而且由于截断操作需要消耗时间,所以在计算机速度上要比精确计算慢。为此,
Java 程序设计语言承认了最优性能与最理想结果之间的冲突,并予以了改进。在默认情况下,虚拟机设计者允许将
中间计算机结果采用扩展的精度。但是,对于使用 strictfp 关键字标记的方法来说,必须使用严格的浮点计算,以
产生理想的结果。例如可以把 main 方法标记为
public static strictfp void main(String[] args){}
于是,在 main 方法中的所有指令都将使用严格的浮点计算。如将一个类标记为 strictfp ,这个类的所有方法都必须使用严格的浮点计算。
后缀形式: n++
n--
前缀形式: ++n
--n
下面用一段示例程序来展示一下前缀和后缀两种不同方式的差别。
图1
我们建议不要在其他表达式的内部使用++,这样编写的代码很容易令人困惑,并会产生烦人的bug。
2)关系运算符与boolean运算符
Java包含各种关系运算符。
其中,使用两个等号==检测是否相等。
使用!=检测是否不相等。
另外,经常使用的运算符还有<,>,<=,>=。
Java沿用了C++的习惯,用&&表示逻辑“与”,用||表示逻辑“或”。&&和||是按照“短路”方式求值的。如果第一个
操作数已经能够确定表达式的值,第二个操作数就不必计算了。
最后,Java支持三元操作符?:。
condition ?expression1 : expression2
当条件condition为真时计算第1个表达式,否则计算第2个表达式。
3)位运算符
在处理整型数值时,可以直接对组成整型数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位。位
运算符包括:
&(与)、|(或)、^(异或)、~(非)
这些运算符在位模式下工作。
另外,“>>”和“<<”运算符将二进制位进行右移或左移操作。
最后,>>>运算符将用0填充高位,>>运算符用符号位填充高位。没有<<<运算符。
4)数学函数与常量
在Math类中,包含了各种各样的数学函数。
要想计算一个数值的平方根,可以使用sqrt方法:
图2
注释:println()方法和sqrt方法存在微小的差异。pirntln()方法操作一个定义在System类中的System.out对象。但是,
Math类中的sqrt方法处理的不是对象,这样的方法被称为静态方法。有关静态方法的详细内容将会在后面进行讲解。
在Java中,没有幂运算,因此需要借助Math类的pow方法。语句:double y = Math.pow(x, a); //将y的值设置为x的a次幂
pow方法有两个double类型的参数,其返回结果也为double类型。
Math类提供了一些常用的三角函数:Math.sin
Math.cos
Math.tan
Math.atan
Math.atan2
还有指数函数以及它的反函数:
Math.exp
Math.log
Math.log10
最后,Java还提供了两个用于表示pi和e的近似值:
Math.PI
Math.E
注释:在Math类中,为了达到最快的性能,所有的方法都使用计算机浮点单元中的例程。如果得到一个完全可预测的结果
比运行速度更重要的话,那么就应该使用StrictMath类。它使用“自由发布的Math库”(fdlibm)实现算法,以确保在所
有平台上得到相同的结果。
5)数值类型之间的转换
在程序运行时,经常需要将一种数值转换为另一种数值类型,图3给出了数值类型之间的合法转换。
图3
在图3中有6个实心箭头,表示无信息丢失的转换;有3个虚箭头,表示可能有精度损失的转换。
如果两个操作数中有一个是double类型,另一个操作数就会转换为double类型。
否则,如果其中中有一个操作数是float类型,另一个操作数就会转换为float类型。
否则,如果其中中有一个操作数是long类型,另一个操作数就会转换为long类型。
否则,两个个操作数都被转换为int类型
6)强制类型转换
强制类型转换(cast)的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名。当然,有可能会
丢失一些信息。
如果试图将一个数值从一种类型强制转换为另一种类型,而又超出了目标类型的表示范围,结果就会截断成一个完全不
同的值。例如,(byte)300的实际值为44。
图4
观察图4的程序运行结果可知,系统在将一个int型值强制转为为byte时,采用了低位截断方式,发生了信息丢失。