📄 chapter3.htm
字号:
<br>
2. 转型<br>
大家会发现假若对主数据类型执行任何算术或按位运算,只要它们“比int小”(即char,byte或者short),那么在正式执行运算之前,那些值会自动转换成int。这样一来,最终生成的值就是int类型。所以只要把一个值赋回较小的类型,就必须使用“造型”。此外,由于是将值赋回给较小的类型,所以可能出现信息丢失的情况)。通常,表达式中最大的数据类型是决定了表达式最终结果大小的那个类型。若将一个float值与一个double值相乘,结果就是double;如将一个int和一个long值相加,则结果为long。<br>
<br>
3.1.14 Java没有“sizeof”<br>
在C和C++中,sizeof()运算符能满足我们的一项特殊需要:获知为数据项目分配的字符数量。在C和C++中,size()最常见的一种应用就是“移植”。不同的数据在不同的机器上可能有不同的大小,所以在进行一些对大小敏感的运算时,程序员必须对那些类型有多大做到心中有数。例如,一台计算机可用32位来保存整数,而另一台只用16位保存。显然,在第一台机器中,程序可保存更大的值。正如您可能已经想到的那样,移植是令C和C++程序员颇为头痛的一个问题。<br>
Java不需要sizeof()运算符来满足这方面的需要,因为所有数据类型在所有机器的大小都是相同的。我们不必考虑移植问题——Java本身就是一种“与平台无关”的语言。<br>
<br>
3.1.15 复习计算顺序<br>
在我举办的一次培训班中,有人抱怨运算符的优先顺序太难记了。一名学生推荐用一句话来帮助记忆:“Ulcer
Addicts Really Like C A lot”,即“溃疡患者特别喜欢(维生素)C”。<br>
<br>
助记词 运算符类型 运算符<br>
<br>
Ulcer(溃疡) Unary:一元 + - + + - [[ 其余的 ]]<br>
Addicts(患者) Arithmetic(shift);算术(和移位) * / % + - << >><br>
Really(特别) Relational:关系 > < >= <= == !=<br>
Like(喜欢) Logical(bitwise):逻辑(和按位) && || & | ^<br>
C Conditional(ternary):条件(三元) A>B ? X:Y<br>
A Lot Assignment:赋值 =(以及复合赋值,如*=)<br>
<br>
当然,对于移位和按位运算符,上表并不是完美的助记方法;但对于其他运算来说,它确实很管用。<br>
<br>
3.1.16 运算符总结<br>
下面这个例子向大家展示了如何随同特定的运算符使用主数据类型。从根本上说,它是同一个例子反反复复地执行,只是使用了不同的主数据类型。文件编译时不会报错,因为那些会导致错误的行已用//!变成了注释内容。<br>
<br>
120-129页程序<br>
<br>
注意布尔值(boolean)的能力非常有限。我们只能为其赋予true和false值。而且可测试它为真还是为假,但不可为它们再添加布尔值,或进行其他其他任何类型运算。<br>
在char,byte和short中,我们可看到算术运算符的“转型”效果。对这些类型的任何一个进行算术运算,都会获得一个int结果。必须将其明确“造型”回原来的类型(缩小转换会造成信息的丢失),以便将值赋回那个类型。但对于int值,却不必进行造型处理,因为所有数据都已经属于int类型。然而,不要放松警惕,认为一切事情都是安全的。如果对两个足够大的int值执行乘法运算,结果值就会溢出。下面这个例子向大家展示了这一点:<br>
<br>
129页下程序<br>
<br>
输出结果如下:<br>
big = 2147483647<br>
bigger = -4<br>
<br>
而且不会从编译器那里收到出错提示,运行时也不会出现异常反应。爪哇咖啡(Java)确实是很好的东西,但却没有“那么”好!<br>
对于char,byte或者short,混合赋值并不需要造型。即使它们执行转型操作,也会获得与直接算术运算相同的结果。而在另一方面,将造型略去可使代码显得更加简练。<br>
大家可以看到,除boolean以外,任何一种主类型都可通过造型变为其他主类型。同样地,当造型成一种较小的类型时,必须留意“缩小转换”的后果。否则会在造型过程中不知不觉地丢失信息。<br>
<br>
3.2 执行控制<br>
Java使用了C的全部控制语句,所以假期您以前用C或C++编程,其中大多数都应是非常熟悉的。大多数程序化的编程语言都提供了某种形式的控制语句,这在语言间通常是共通的。在Java里,涉及的关键字包括if-else、while、do-while、for以及一个名为switch的选择语句。然而,Java并不支持非常有害的goto(它仍是解决某些特殊问题的权宜之计)。仍然可以进行象goto那样的跳转,但比典型的goto要局限多了。<br>
<br>
3.2.1 真和假<br>
所有条件语句都利用条件表达式的真或假来决定执行流程。条件表达式的一个例子是A==B。它用条件运算符“==”来判断A值是否等于B值。该表达式返回true或false。本章早些时候接触到的所有关系运算符都可拿来构造一个条件语句。注意Java不允许我们将一个数字作为布尔值使用,即使它在C和C++里是允许的(真是非零,而假是零)。若想在一次布尔测试中使用一个非布尔值——比如在if(a)里,那么首先必须用一个条件表达式将其转换成一个布尔值,例如if(a!=0)。<br>
<br>
3.2.2 if-else<br>
if-else语句或许是控制程序流程最基本的形式。其中的else是可选的,所以可按下述两种形式来使用if:<br>
<br>
if(布尔表达式)<br>
语句<br>
<br>
或者<br>
<br>
if(布尔表达式)<br>
语句<br>
else<br>
语句<br>
<br>
条件必须产生一个布尔结果。“语句”要么是用分号结尾的一个简单语句,要么是一个复合语句——封闭在括号内的一组简单语句。在本书任何地方,只要提及“语句”这个词,就有可能包括简单或复合语句。<br>
作为if-else的一个例子,下面这个test()方法可告诉我们猜测的一个数字位于目标数字之上、之下还是相等:<br>
<br>
131页程序<br>
<br>
最好将流程控制语句缩进排列,使读者能方便地看出起点与终点。<br>
<br>
1. return<br>
return关键字有两方面的用途:指定一个方法返回什么值(假设它没有void返回值),并立即返回那个值。可据此改写上面的test()方法,使其利用这些特点:<br>
<br>
131-132页程序<br>
<br>
不必加上else,因为方法在遇到return后便不再继续。<br>
<br>
3.2.3 反复<br>
while,do-while和for控制着循环,有时将其划分为“反复语句”。除非用于控制反复的布尔表达式得到“假”的结果,否则语句会重复执行下去。while循环的格式如下:<br>
<br>
while(布尔表达式)<br>
语句<br>
<br>
在循环刚开始时,会计算一次“布尔表达式”的值。而对于后来每一次额外的循环,都会在开始前重新计算一次。<br>
下面这个简单的例子可产生随机数,直到符合特定的条件为止:<br>
<br>
132下程序<br>
<br>
它用到了Math库里的static(静态)方法random()。该方法的作用是产生0和1之间(包括0,但不包括1)的一个double值。while的条件表达式意思是说:“一直循环下去,直到数字等于或大于0.99”。由于它的随机性,每运行一次这个程序,都会获得大小不同的数字列表。<br>
<br>
3.2.4 do-while<br>
do-while的格式如下:<br>
<br>
do<br>
语句<br>
while(布尔表达式)<br>
<br>
while和do-while唯一的区别就是do-while肯定会至少执行一次;也就是说,至少会将其中的语句“过一遍”——即便表达式第一次便计算为false。而在while循环结构中,若条件第一次就为false,那么其中的语句根本不会执行。在实际应用中,while比do-while更常用一些。<br>
<br>
3.2.5 for<br>
for循环在第一次反复之前要进行初始化。随后,它会进行条件测试,而且在每一次反复的时候,进行某种形式的“步进”(Stepping)。for循环的形式如下:<br>
<br>
for(初始表达式; 布尔表达式; 步进)<br>
语句<br>
<br>
无论初始表达式,布尔表达式,还是步进,都可以置空。每次反复前,都要测试一下布尔表达式。若获得的结果是false,就会继续执行紧跟在for语句后面的那行代码。在每次循环的末尾,会计算一次步进。<br>
for循环通常用于执行“计数”任务:<br>
<br>
133页下程序<br>
<br>
注意变量c是在需要用到它的时候定义的——在for循环的控制表达式内部,而非在由起始花括号标记的代码块的最开头。c的作用域是由for控制的表达式。<br>
以于象C这样传统的程序化语言,要求所有变量都在一个块的开头定义。所以在编译器创建一个块的时候,它可以为那些变量分配空间。而在Java和C++中,则可在整个块的范围内分散变量声明,在真正需要的地方才加以定义。这样便可形成更自然的编码风格,也更易理解。<br>
可在for语句里定义多个变量,但它们必须具有同样的类型:<br>
<br>
134页上程序<br>
<br>
其中,for语句内的int定义同时覆盖了i和j。只有for循环才具备在控制表达式里定义变量的能力。对于其他任何条件或循环语句,都不可采用这种方法。<br>
<br>
1. 逗号运算符<br>
早在第1章,我们已提到了逗号运算符——注意不是逗号分隔符;后者用于分隔函数的不同自变量。Java里唯一用到逗号运算符的地方就是for循环的控制表达式。在控制表达式的初始化和步进控制部分,我们可使用一系列由逗号分隔的语句。而且那些语句均会独立执行。前面的例子已运用了这种能力,下面则是另一个例子:<br>
<br>
134页下程序<br>
<br>
输出如下:<br>
<br>
135页上程序<br>
<br>
大家可以看到,无论在初始化还是在步进部分,语句都是顺序执行的。此外,尽管初始化部分可设置任意数量的定义,但都属于同一类型。<br>
<br>
3.2.6 中断和继续<br>
在任何循环语句的主体部分,亦可用break和continue控制循环的流程。其中,break用于强行退出循环,不执行循环中剩余的语句。而continue则停止执行当前的反复,然后退回循环起始和,开始新的反复。<br>
下面这个程序向大家展示了break和continue在for和while循环中的例子:<br>
<br>
135页下程序<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -