y·c="2" 实际上会修改代()外面的对象。 expect()里面的输出可以印证这 Aliasing及其解决方案是个很复杂的课题。虽然我们要到附录A才会作 全面讲解,但是你现在就得知道有这个问题,这样才会注意到 阱 数学运算符 在绝大多数编程语言里面,基本的数学运算符都是相同的:加(+),减( ),除(/),乘(*),取模(%,它会返回整数相除之后的余数)。整数相 除,会把运算结果的小数点后面全部截掉,而不是作四舍五入 Java也有可以同时进行计算和赋值的简写符号。它用运算符加一个等号 来表示,在Java语言中,这种表示方法能一致地用于所有的运算符(只 要是有意义就行了)。比如,你要为变量x加4,然后再赋给x,就写:x 下面这个例程演示了数学运算符的用法: //: c03: Mathops. java / Demonstrates the mathematical operators mport com. bruceeckel. simpletest. import java.util public class Mathops static Test monitor new Test o // Shorthand to print a string and an int: c void printInt (stri int 1) System. out. println( / Shorthand to print a string and a float static void printFloat (string s, float f)t System. out. println(s+ public static void main(String[] args)t // Create a random number generator, / seeds with current time by default Random rand new Random()i / Choose value from 1 to 100 rand. nextInt(100)+ 1 k rand. nextInt(100)+1 printInt("i",3)i printInt ("k",k) Int("3+k",i ki printInt("3-k", i i =k,ii printInt("k/i", i i =k* ji printInt("k*i", i) i=k号j; printing("k号j",i) 第6页共48页
shhgs@wgqqh.com 6 ✁ ✂ 48 ✁ y.c = 'z'; ñJºïð f( )½¶(¥_expect( )˶(©!ÝEªÕ 3 C Al iasin g <§£Nµ>×Ö×(4dØ|W%g,5 A Ùº1 c¶©£¡íFÉm ×cd ¦Ùº¹g3ÌÍÚ ÛÏ FÂV"áâ˶G ("F Æ>(0ä(+)P(- )R(/)Q(*)ÜÝ(AºÞ¼¤">Ru(o")¤"> RºPOÅ(ß"C¶c{¹àX1àáât Java [mÝE(@~L()« SA ä3×-S QhF Java * hµ;3ãr)Dm( (ó %m¹ä, )8Ä¡% x ä 4|Á~¬ x«0x += 4 ¶ ×]â,"F (0 //: c03:MathOps.java // Demonstrates the mathematical operators. import com.bruceeckel.simpletest.*; import java.util.*; public class MathOps { static Test monitor = new Test(); // Shorthand to print a string and an int: static void printInt(String s, int i) { System.out.println(s + " = " + i); } // Shorthand to print a string and a float: static void printFloat(String s, float f) { System.out.println(s + " = " + f); } public static void main(String[] args) { // Create a random number generator, // seeds with current time by default: Random rand = new Random(); int i, j, k; // Choose value from 1 to 100: j = rand.nextInt(100) + 1; k = rand.nextInt(100) + 1; printInt("j", j); printInt("k", k); i = j + k; printInt("j + k", i); i = j - k; printInt("j - k", i); i = k / j; printInt("k / j", i); i = k * j; printInt("k * j", i); i = k % j; printInt("k % j", i); j %= k; printInt("j %= k", j);
/ Floating-point number tests float u, v, w; / applies to doubles, too Float ()i tFloat( printFloat(v,v) printFloat("w" u=v+ wi printEloat("v+ w", u) u=v-w; printFloat ("v-w",u) u=v* wi printFloat("v *w",u)i wi p / the following works for / char, by and double: u + vi printFloat ("u + v", u) i printFloat (u -=v", u) tFloat ("u * u/= v; printFloat("u/= v", u) monitor. expect (new string[] t 号号方 ?\\d+m 各k=-?\d+ 号号j\1+k d+", 告号j-k=-2\\d+ 号k/j=-?1\d+", 各号k\\ 号kj ?\\d+ 各号方=k ?\\d+m 号各 ?\\d+\.\d+(E-?\\d)?", 各号W=-?\d+\\.\d+(E-?\d)? 各号V+W=-?\d+.\d+(E-?\d)?? =-2\\d+\\.\\d+(E-?\\d)??", 号号V ?\\d+\\.\\d+(E-?\\d)??", ?\\d+\\.\\d+(E-?\\d)?? 号号u\\+=V=-?\d+\\.\d+(E-?\\d)?? V=-?\d+\.d+(E-?\\d)??", 号号u*=V=-?\d+\.\\d+(E-2\d)??”, 各号u/=V=-?\d+).\d+(E-?\hd)?? }); ///:~ 首先看到的是两个为节省敲键盘而定义的打印方法: printing()会先打 印一个 String,然后再接一个int:而 printFloat()会先打印一个 String,再打印一个 float 程序先创建一个 Random对象,以产生数字。由于创建过程中没有使用 参数,因此Java会用当前的时间作随机数生成器的种子。程序用 Random对象的 nextInt()和 nextFloat()方法生成了很多不同种 类的随机数(你也可以用 nextLong()或 nextDouble() 取模运算符( modulus operator)会将随机数生成器产生的数字限制在操 作数减一的范围之内(这里就是99) 正则表达式( Regular expressions) 第7页共48页
shhgs@wgqqh.com 7 ✁ ✂ 48 ✁ // Floating-point number tests: float u,v,w; // applies to doubles, too v = rand.nextFloat(); w = rand.nextFloat(); printFloat("v", v); printFloat("w", w); u = v + w; printFloat("v + w", u); u = v - w; printFloat("v - w", u); u = v * w; printFloat("v * w", u); u = v / w; printFloat("v / w", u); // the following also works for // char, byte, short, int, long, // and double: u += v; printFloat("u += v", u); u -= v; printFloat("u -= v", u); u *= v; printFloat("u *= v", u); u /= v; printFloat("u /= v", u); monitor.expect(new String[] { "%% j = -?\\d+", "%% k = -?\\d+", "%% j \\+ k = -?\\d+", "%% j - k = -?\\d+", "%% k / j = -?\\d+", "%% k \\* j = -?\\d+", "%% k % j = -?\\d+", "%% j %= k = -?\\d+", "%% v = -?\\d+\\.\\d+(E-?\\d)?", "%% w = -?\\d+\\.\\d+(E-?\\d)?", "%% v \\+ w = -?\\d+\\.\\d+(E-?\\d)??", "%% v - w = -?\\d+\\.\\d+(E-?\\d)??", "%% v \\* w = -?\\d+\\.\\d+(E-?\\d)??", "%% v / w = -?\\d+\\.\\d+(E-?\\d)??", "%% u \\+= v = -?\\d+\\.\\d+(E-?\\d)??", "%% u -= v = -?\\d+\\.\\d+(E-?\\d)??", "%% u \\*= v = -?\\d+\\.\\d+(E-?\\d)??", "%% u /= v = -?\\d+\\.\\d+(E-?\\d)??" }); } } ///:~ ~/<g(e×åæçèéàOä(]ªµ0prin tIn t( )º/] ª3× Strin g|Á3× in t à prin tFl oat( )º/]ª3× Strin gÁ]ª3× fl oat â/§¨3× Ran dom ¥_EJ0"`)§¨^â*mç "æò Java º (41¸ê"0¾(â Ran dom ¥_( nextIn t( ) nextFl oat( )µ0,VX e(¸ê" (¡[ÝE nextLon g( ) nextDou ble( )) ÜÝ (m odul us operator)º¸ê"0¾J0("ë!F 1"P3(ìíu ( Ë 99) ( Regu lar expression s)
由于程序用到了随机数,因此输出的结果会一次和一次不一样,所以 expect()就不能再像过去那样,一字不错地告诉你会输出些什么了。要 解决这个问题, expect()语句就得用到一种 Java JDK1.4所引入 的,被称为正则表达式的新的特性(但是在Per和 Python之类的语言 里,这已经是老特性了)。尽管我们要到第12章才会全面介绍这一无比 强大的工具,但如果这里不作介绍的话,你就没法看下去了。目前,你只 要能读懂 expect()就行了,要想全面了解这部分内容,请查阅JDK文 档的 javautil. regex. Pattern部分。 正则表达式是一种用通用术语描述字符串的方法,这样你就可以说:“如 果字符串里有这些东西,那么它同我正在找的东西相匹配。”比如,要表 示一个可能有也可能没有的负号,你可以在负号后面加一个问号,就像这 表示整数,就是表示一个或多个阿拉伯数字。在正则表达式中,阿拉伯数 字用“d’表示的,但是在Java的 String里,你必须再加一个反斜杠 才能把它“转义”成一个反斜杠:“\\d’。要在正则表达式里表示“ 个或多个前述的表达式”,你就得用“+’。所以要表示“前面可能有个 减号,后边跟着一串阿拉伯数字”,你得写: ?\\d+ 这就是上面那段程序的 expect()语句的第一行。 expect()语句的各行中,开头部分的‘%%’(注意一下,空格是为 增强可读性而加的),都不属于正则表达式。这是 simpletext所使用的 标记,它表示这行剩下来的部分是一个正则表达式。所以仅从 simpletext的 expect()语句,你是看不到普通的正则表达式的。 其它字符,只要它不属于正则表达式特有的专用字符,都要求完全匹配。 所以第一行: 各号j=-21\d+ =’会做精确匹配。但是在第三行,“j+k’里面的‘+’必须进行 转义,因为跟‘*’一样,在正则表达式里它也是一个特殊字符。作完这 些介绍之后,剩下几行你就应该能看懂了。如果本书后面的 expect() 里面又用到了正则表达式的新特性的话,我们会再作解释。 第8页共48页
shhgs@wgqqh.com 8 ✁ ✂ 48 ✁ `)âg,¸ê"æò©!(Oź3¨3¨X3¦DE expect( )X;Á}^+Y¦3Xîr#¡º©!ÌïZ,% £N ×cdexpect( )g3 Java JD K 1. 4 Dt (TUshi´(K(pð(F Perl Pyth on ue( Ë ôõñpð, )BòW%g 12 ûÙºc¶ 3Ü8 óÂ(yÄÄÅ ËX1(¡<+,A¡ó %;= expect( ),%|c¶,£ Rôõ JD K ²( java. u til .regex. Pattern shi´3±ö ÷(µ ¦¡ÝE$0ÍÄ Å ÷Ëm ÌøùYZAFú(øù>ûÏ8Ä%h 3×Ý;m[Ý;m(¿S¡ÝEF¿S¶ä3×cS} ¦0 -? h¤"h3× V×üýþ"Fshi´*üýþ" [\d\h(F Java ( Strin g Ë¡Áä3× Ù;PAÍäÏ3×0[\\d\%Fshi´ËhÍ3 × V×(hi´Ï¡[+\DE%hͶÝ;m× PS1.3÷üýþ"Ï¡«0 -?\\d+ J¶Yâ( expect( )(3 expect( )(*a([%%\(¹3è, óÝðàä()ÆX )shi´ simpletest Dç( YAh Q(3×shi´DE simpletest ( expect( )¡<XgM(shi´( §A ó%AX )shi´pm( Æ% cû DE30 %% j = -?\\d+ [j = \ºTxûFL[j + k\˶([+\( äæ[*\3¦Fshi´ËA[3×pq 1 Ìui¡vw;<=,ÄÅ ¶( expect( ) ˶üg,shi´(Kpð(WºÁ1£
单元的加号和减号运算符 单元的减号(-)和加号(+)与双元减号和加号完全相同。编译器会通过的表 达式来判断这个运算符到底是单元的还是双元的。例如,表达式 的意思就很明显。此外编译器也可以认出: 但是读代码的人就惨了,所以还是这样写更清楚: 单元减号表示负数。有单元减号就得有单元的正号,只是不起任何作用。 自动递增与递减 同C一样,Java里面到处都是简写。简写可以让程序写起来简单,至于 读取来怎么样,那得看情况。 递增和递减运算符(通常也被称作“自动递增auto- increment”和“自 动递减auto- decrement”运算符)是两种比较好的简写。递减的运算符 是一-,它的意思是“减小一个单位”。而递增得运算符是++,它的意 思是“增加一个单位”。比方说a是一个int,那么++a实际上同(a a+1)是等效的。递增和递减不但修改变量的值,而且会把这个值返 给变量。 这两个运算符还各有两个版本,也就是常提到的前置( prefix)和后置 ( postfix)。“前置递增(pre-iη crement)”的意思是+十运算符出现在 变量或者表达式的前面,而“后置递增(post- increment)”的意思是 ++运算符出现在变量或者表达式的后面。同样,“前置递减(pre decrement)”是指-运算符出现在变量或者表达式的前面,“后置递 减( post-decrement)”的意思是一-运算符出现在变量或者表达式的后 面。对于前置递增和前置递减,(也就是十+a和--a),操作过程是会先 计算再返回。对于后置递增和后置递减,(也就是a++和a-),操作步 骤是先返回再计算。下面就是举例 //: c03: AutoInc. java // Demonstrates the + and - operators mport com. bruceeckel. simpletest *i 第9页共48页
shhgs@wgqqh.com 9 ✁ ✂ 48 ✁ t(PS(-)äS(+ )PSäSc>Ὰ^(h i´Qno × ght((]Ähi´ x = -a; (¹}wò½á¾[ÝEÙ!0 x = a * -b; £(ª,DE ¦«¿Í0 x = a * (-b); tPSh¿"mtPSmt(SóX9^1 C 3¦Java ˶gÆ)«)«ÝEÇâ«9Q)t±) ÜQÕZ¦Y< P (·[TU1Íý auto-in crem en tÏÍý P auto-decrem en tÏ ) e8()«P( -- A(¹}ÍPß3×tÏà ++ A(¹ }Íä3×tÏ8µ$ a 3× in tYZ ++a ñJ( a = a +1 )-Ø(PXïð(LàºP ×LÞ ¼¬ e× me× [·g((p refix) (postfix)Í (pre-increment)Ï(¹} ++ !íF hi´(¶àÍ (post-increment)Ï(¹} ++ !íF hi´(¶¦ÍP(predecrement)Ïy -- !íF hi´(¶Í P(post-decrement)Ï(¹} -- !íF hi´( ¶¥)P([ ++a --a)1^âº/ @ÁÞ¼¥)P([ a++ a--)1à /Þ¼Á@¶]0 //: c03:AutoInc.java // Demonstrates the ++ and -- operators. import com.bruceeckel.simpletest.*;
public class AutoInc static Test monitor new Test( public static void main(String[] args)i System. out. println("i System. out. println("++i # +++i);//Pre Increment In( System. out. println("--i : "+--i);//Pre- decrement System. out. println("i "+i--);//Post decrement System. out. println("i monitor.expect (new String[] i "i++:2 i-11 }///:~ 你可以看到,运算符前置的时候,你所得到的是经过计算的值,但是运算 符后置的情况下,你所得到的是还未进行过处理的值。这是唯一一种(除 了赋值之外)还有其它附带用途的操作符。(也就是说,不是要用它来进行 计算,而是要用它来修改操作数。) 递增运算符也是C++命名的原因之一,它的寓意是“比C更进一步” 在早期的Java访谈中, Bill Joy(Sun的创建者之一)说,“Java C++-”(C++的递减)。他的意思是,Java是一种去除了C++中多余 的复杂性的语言,因此它是一种更为简单的语言。随着本书的进展,你会 看到很多地方都变得更简单了,但是Java还不到“比C++简单得多” 的地步。 关系运算符 关系运算符会产生 boolean类型的结果。它们会判断操作数的值的大小 关系。如果这种关系为真,则关系表达式返回true,如果这个关系为 假,则返回 false。关系运算符有小于(<),大于(>),小于等于(<=), 大于等于(>=),相等(==)以及不等(!=)。所有的内置数据类型都能比 较相等( equivalence)和不等( nonequivalence),但是对 boolean类 型,除了相等和不等的之外,其它比较是没意义的 测试对象的相等性 第10页共48页
shhgs@wgqqh.com 10 ✁ ✂ 48 ✁ public class AutoInc { static Test monitor = new Test(); public static void main(String[] args) { int i = 1; System.out.println("i : " + i); System.out.println("++i : " + ++i); // Preincrement System.out.println("i++ : " + i++); // Postincrement System.out.println("i : " + i); System.out.println("--i : " + --i); // Predecrement System.out.println("i-- : " + i--); // Postdecrement System.out.println("i : " + i); monitor.expect(new String[] { "i : 1", "++i : 2", "i++ : 2", "i : 3", "--i : 2", "i-- : 2", "i : 1" }); } } ///:~ ¡ÝE<g (M¡Dg(õ^@(L (¡Dg((^¢(L 33 (R ,~Lu½ )m§A,(1 ([$X%AQ( @à%AQïð1") [ C++Ñ(åæu3A(¹Í8 C (3ÃÏ F@( Java !*B il l Joy (Sun (§¨u3)$Í Java = C++--Ï(C++(P)G(¹}Java 3+R, C++*Vo (Ö×ð(æòA3)t(¸. (("¡º <gVrµÆ)t, Java XgÍ8 C++)tVÏ (rà # ºJ0 boolean e$(OÅAWºno1"(L(Âß #ÄÅ #%s#hi´Þ¼ trueÄÅ ×# sÞ¼ fal se# mß)(< )Â)(> )ß)-)(< =) Â)-)(> =)>-(==)E<X-(! =)Dm("#e$Æ;8 >-(equival en ce)X-(n on equival en ce)¥ boolean e $R,>-X-(u½§A8¹ä(