3.3 变量和常量
(1)变量
1)变量声明
在Java中,每一个变量属于一种类型,变量声明的示例:
double salary;
int age;
long earthPopulation;
boolean isYes,isNo;
格式:type var1 [,var2,var3…]; var1为变量名
虽然可在一行中声明多个变量,但不提倡这种风格,逐一声明每个变量可以提高程序可读性。
变量名命名的技巧:最好有实际意义,如果很难给变量取一个好名字,可将以前缀为a,后面跟类型名作为变量名,如Box aBox;
Java和C/C++不同,Java不区分变量的声明与定义,例如在C++中:
int i = 10;是定义一个变量
而 extern int i仅是声明一个变量。
在C/C++中变量的声明有两种情况: 一是需要建立存储空间的,例如int a在声明时就已经建立了存储空间; 另一种是不需要建立存储空间的,例如extern int a,其中变量a是在别的文件中定义的。 前者是“定义性声明”或称为“定义”,而后者是“引用性声明”;从广义的角度讲声明中包含着定义,定义仅是声明的一个特例。int a声明并定义了一个变量,而extern int i仅声明而不是定义。 |
2)变量赋值和变量初始化
声明一个变量后,必须用赋值语句对变量进行显式初始化,千万不要使用未被初始化的变量,防止程序的意外错误。
变量赋值:
int age; //声明变量
age = 12; //变量初始化(赋值)
也可以将变量的声明和初始化放在同一行中,如:
int age = 12; //推荐方式,方便程序阅读
在Java中,可以将变量声明放在代码中的任何地方,只要保证变量使用前必须先声明即可,最好将变量的声明尽可能靠近变量第一次使用的地方,这是一种良好的程序编写风格。
(2)常量
在Java中,利用关键字final声明常量。关键字final表示这个变量只能被赋值依次,一旦被赋值后就不能再改了。习惯上,常量名使用大写。
例如:final double CM_PER_INCH = 2.54;
常量除用十进制表示外,还可用十六进制表示(前缀为0x,如0xCAFE)或八进制表示(前缀0,如010),为避免混淆,尽量不采用八进制表示。
在java中,某个常量可以在一个类中的多个方法中使用,通常将这些常量成为类常量。类常量可以使用关键字static final修饰。例如:
public class FirstSample
{
public static final double CM_PER_INCH = 2.54;
… …
}
同一个类地其他方法都可以使用这个类常量,由于被声明为public,其他类地方法也可以使用这个常量。
注:const是java保留的关键字,目前没有使用。Java中,必须使用final定义常量。
3.4 Java运算符
(1)算术运算符
+、-、*、/、%分别表示加、减、乘、除和求余(取模)运算。当参与/运算的两个操作数都是整数时,表示整数除法;否则表示浮点除法。整数除法只保留整数部分而截断小数部分(不是四舍五入)。例如:
System.out.println(20/3); //输出的是6
需要注意:整数被0除将会产生一个异常,而浮点数被0除将会得到无穷大或Nan的结果(不会抛出异常)。
和C/C++一样,java也可以在赋值语句中采用一种简化的格式书写二元算术运算符,如
x +=4; 等价于 x=x+4;
和C/C++一样,java也可以使用自增自减运算符,如
int i =12;
i++;//或 ++i ;--i;i--;
—浮点运算与可移植性
可移植性是Java语言的设计目标之一,无论程序在何种环境运行,同一运算应该得到同样的结果。但是对于浮点型的算术运算,实现这样的移植并不简单。例如double类型使用64位存储一个浮点数,而有些处理器使用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,则这个类中的所有方法都要使用严格的浮点计算。
实际的计算方式将取决于处理器。在默认情况下,中间结果允许使用扩展的指数,但不允许使用扩展的尾数(Intel芯片在截断尾数时并不损失性能)。因此,这两种方式的区别仅仅在于采用默认的方式不会产生溢出,而采用严格的计算可能产生溢出。
(2)关系运算符与布尔运算符
关系运算符 | 作用 | 布尔运算符 | 作用 |
= = | 相等 | && | 逻辑与 |
!= | 不相等 | || | 逻辑或 |
<,<= | 小于,小于等于 | ! | 逻辑非 |
>,>= | 大于,大于等于 | cond1?exp1:exp2 | 三元操作符 |
其中,&&和||是按照“短路”方式求值的,如果第一个操作数已经能确定表达式的值,第二个操作数就不必计算了。
(3)位运算符
在处理整型数值时,可以直接对组成整型数值的各个位进行操作,这意味着可以使用屏蔽技术获得整数中的各个位。
位运算符 | 作用 | 位运算符 | 作用 |
& | 位与 | >> | 位算术右移 |
| | 位或 | >>> | 位逻辑右移 |
^ | 位异或 | << | 位左移 |
~ | 位非 |
|
|
|
|
|
|
注:
1)&和|运算符应用于布尔值,得到的结果也是布尔值,这两个运算符与&&和||的运算非常类似,只是不按“短路”方式计算,即在得到计算结果之前,一定要计算两个操作数的值。
2)>>>运算符将用0填充高位(逻辑右移);>>运算符用符号位填充高位(算术右移);没有<<<运算符。在C/C++中无法确定>>操作执行的算术移位(扩展符号位)还是逻辑移位(高位填0),在执行时将会选择效率较高的一种,这意味着在C/C++中>>运算符实际上只是为非负数定义的,Java消除了这种含糊性。
3)对移位运算符右侧的参数需要进行模运算(对于int型模采用32,对于long型模采用64),即1<<35与1<<3是相同的。
4) 当需要建立位模式屏蔽某些位时,使用位模式运算符十分方便。
例如需要检测int型变量n从右算起第4位是1还是0,可以利用以下表达式:
int bitForm=(n & 8) /8 ;//观察bitForm的值是1还是0即可
注解:1&任何值=这个值本身;0&任何值=0;首先n & 8(00001000)将n除了需要检测的位以外的其他位屏蔽为0,得到…0000x000,然后将结果右移三位(右移相当于整型除法),即>>3等价于/8,得到0000 000x这样的结果。