【正文】
ither have to write the tests in Groovy or JRuby (or some other language that doesn39。t also legitimate Java identifiers. A better Java Back when I was first learning C++, Bjarne Stroustrup suggested that one way to learn C++ was to see it as a better C (see Resources). In some ways, Java developers today might e to see Scala as a better Java, because it provides a more terse and succinct way of writing traditional Java POJOs. Consider the traditional Person POJO shown in Listing 11: Listing 11. (original POJO) public class JavaPerson { public JavaPerson(String firstName, String lastName, int age) { = firstName。 } public void setFirstName(String value) { 10 = value。 } public void setAge(int value) { = value。 private int age。s guide to Scala series has focused on Scala39。本文是 面向 Java開發(fā)人員的 Scala指南 系列 的第二期 , 作者 Ted Neward遵循對一種語言進(jìn)行評價(jià)的基本前提:一種語言的威力可以直接通過它集成新功能的能力衡量,在本文中就是指對復(fù)數(shù)的支持。 Scala 還提供了很多其他特性 , 本文將研究 Scala 編程中的一些較復(fù)雜方面。記住,其中的一些特性并不是直接對應(yīng),或者說,在某些情況下, “對應(yīng) ” 更像是一種類比,而不是直接的對應(yīng)。 用多少種方法構(gòu)造類? 15 現(xiàn)在,回顧一下 Rational 類定義中的第一行: 清單 class Rational(n:Int, d:Int) { // ... 您也許會認(rèn)為清單 3 中使用了某種類似于泛型的語法,這其實(shí)是 Rational 類的默認(rèn)的、首選的構(gòu)造函數(shù): n和 d是構(gòu)造函數(shù)的參數(shù)。如果要將 1/2與 2/4相加,那 Rational 類應(yīng)該足夠聰明,能夠認(rèn)識到 2/4和 1/2是相等的,并在將這兩個數(shù)相加之前進(jìn)行相應(yīng)的轉(zhuǎn)換。 然而,請注意 toString的語法:定義前面的 override 關(guān)鍵字是必需的,這樣 Scala才能確認(rèn)基類中存在相應(yīng)的定義。 一些重要值 接下來分別是 numer 和 denom的定義。 此時, Java 程序員可能會問: “n和 d各自的 ?setter?在哪里? ”Scala中不存在這樣的 setter。 當(dāng)然還有一個問題,如何操縱 Rational 呢?與 ,不能直接修改現(xiàn)有的 Rational 的值,所以惟一的辦法是根據(jù)現(xiàn)有類的值創(chuàng)建一個新 的 Rational,或者從頭創(chuàng)建。在上一篇 文章 中 , 您看到了函數(shù)本身也是對象這一原則的應(yīng)用,這使 Scala程序員可以將函數(shù)賦予變量,將函數(shù)作為對象參數(shù)傳遞等等。 在 Rational 類中,為有理數(shù)定義了 4種操作。同樣,這與,這是默認(rèn)的實(shí)現(xiàn),因?yàn)檫@樣可以產(chǎn)生線程安全的代碼(如果線程沒有修改共享狀態(tài) —— 默認(rèn)情況下,跨線程共享的對象的內(nèi)部狀態(tài)也屬于共享狀態(tài) —— 則不 會影響對那個狀態(tài)的并發(fā)訪問)。例如,假設(shè)提供一個 “求倒數(shù) ”操作符 , 這個操作符會將分子和分母調(diào)換 , 返回一個新的 Rational(即對于 Rational(2,5)將返 回 Rational( 5, 2)) 。這意味著您可以開發(fā)與 Scala語言 “內(nèi)置 ”的類型完全相同的類型。如果您需要證據(jù),那么只需注意編譯器生成以 0xCAFEBABE開頭的 .class 文件,就像 javac一樣。 public Rational(int, int)。 public Rational $times(Rational)。 public int numer()。 public int $tag()。 測試 Rational 類 一種著名的觀點(diǎn)認(rèn)為,優(yōu)秀的程序員編寫代碼,偉大的程序員編寫測試;到目前為止,我還沒有對我的 Scala代碼嚴(yán)格地實(shí)踐這一規(guī)則,那么現(xiàn)在看看將這個 Rational 類放入一個傳統(tǒng)的 JUnit測試套件中會怎樣,如清單 10所示: 清單 10. import .*。 assertTrue(() == 5)。 // 1 because of gcd() invocation during construction。 //r1.$plus(r2)。當(dāng)然,令人高興的是,您可以將 Java類遷移至 Scala類,同時不必更改支持這些類的測試,然后慢慢嘗試 Scala。我采用后一種方法,從 Scala的角度看這不是那么有趣,但是如果您有興趣的話,可以看看本文的代碼中包含的結(jié)果(參見 下載 )??紤]清單 11中顯示的傳統(tǒng) Person POJO: 清單 11. (原始 POJO) public class JavaPerson { public JavaPerson(String firstName, String lastName, int age) { = firstName。 } public void setFirstName(String value) { = value。 21 } public void setAge(int value) { = value。 private int age。 即使必須包含這些可變的 setter 方法, Scala版本仍然更加簡單,如清單 13所示: 清單 13。但是,由于原始的 Person沒有與這些可變 setter 相關(guān)的同步代碼,所以 Scala 版本使用起來更安全。 } private String firstName。 } public void setLastName(String value) { = value。 = age。 “更好的 ” Java 我學(xué)習(xí) C++的時候 Bjarne Stroustrup 建議,學(xué)習(xí) C++的一種方法是將它看作 “更好的C語言 ”(參見 參考資料 )?;仡櫼幌?javap的輸出, Scala顯然已經(jīng)將 +函數(shù)轉(zhuǎn)換為 JVM方法 $plus,但是 Java語言規(guī)范并不允許標(biāo)識符中出現(xiàn) $字符(這正是它被用于嵌套和匿名嵌套類名稱中的原因)。 assertTrue(() == 15)。 Rational r2 = new Rational(1, 3)。 assertTrue(() == 0)。 public class RationalTest { 19 Test public void test2ArgRationalConstructor() { Rational r = new Rational(2, 5)。類中定義了兩個構(gòu)造函數(shù):一個構(gòu)造函數(shù)帶有一個 int參 數(shù),另一個帶有兩個 int參數(shù)。 private int gcd(int, int)。 public Rational $plus(Rational)。 public toString()。 private int numer。注意,雖然 Rational 類并沒有顯式地定義 +=,下面的代碼仍然會正常運(yùn)行: 清單 8. Scala 推斷 var r5 = new Rational(3,4) r5 += r1 (r5) 打印結(jié)果時, r5的值為 [13 / 12],結(jié)果是正確的。因此,該語法將顛覆大多數(shù)對象語言中常見的傳統(tǒng) reference thenmethod語法。這使函數(shù)具有強(qiáng)大的可重用性,本系列 第一篇文章 對此作了探討。每種操作以它的數(shù)學(xué)符號命名: +、 、 * 和 /。在 Scala中,所有操作符都是類的函數(shù)。 與其外表相反,這并非操作符重載。但是,也可使用語法創(chuàng)建修改 Rational 內(nèi)部結(jié)構(gòu)的方法,但是這樣做會破壞該類固有的線程安全性。 16 在形式上, Scala 調(diào)用無參數(shù)的 numer 和 denom方法 , 這種方法用于創(chuàng)建快捷的語法以定義 accessor。還應(yīng)注意,這里沒有指定返回類型 —— 從方法體的定義很容易看出 ——返回值沒有用 return關(guān) 鍵字顯式地標(biāo)注,而在 Java中則必須這樣做。在 Scala中調(diào)用構(gòu)造函數(shù)時,將對整個類進(jìn)行計(jì)算,這意味著將 g初始化為 n和 d的最大公分母,然后用它依次設(shè)置 n和 d。如果需要 , 可以在一個 Rational 上定義更多的構(gòu)造函數(shù),例如: 清單 4. 構(gòu)造函數(shù)鏈 class Rational(n:Int, d:Int) { def this(d:Int) = { this(0, d) } 注意, Scala 的構(gòu)造函 數(shù)鏈通過調(diào)用首選構(gòu)造函數(shù)( Int,Int版本)實(shí)現(xiàn) Java構(gòu)造函數(shù)鏈的功能。 Scala和 Java一樣使用類 我們不對 Scala支持的類特性作冗長而抽象的討論,而是著眼于一個類的定義,這個類可用于為 Scala平臺引入對有理數(shù)的支持(主要借鑒自 “Scala By Example”,參見 參考資料 ): 清單 1. class Rational(n:Int, d:Int) { private def gcd(x:Int, y:Int): Int = { if (x==0) y else if (x0) gcd(x, y) else if (y0) gcd(x, y) else gcd(y%x, x) } private val g = gcd(n,d) val numer:Int = n/g val denom:Int = d/g 14 def +(that:Rational) = new Rational(numer* + *denom, denom * ) def (that:Rational) = new Rational(numer * * denom, denom * ) def *(that:Rational) = new Rational(numer * , denom * ) def /(that:Rational) = new Rational(numer * , denom * ) override def toString() = Rational: [ + numer + / + denom + ] } 從詞匯上看,清單 1的整體結(jié)構(gòu)與 Java代碼類似,但是 , 這里顯然還有一些新的元素。實(shí)際上, Scala 融合了函數(shù)概念和面向?qū)ο蟾拍睢? 在上一期 文章 中,您只是稍微了解了一些 Scala 語法,這些是運(yùn)行 Scala 程序和了解其簡單特性的最基本要求。ve learned so far, you can already start using Scala to reduce your programming workload. Among other things, you can use Scala to produce the very same POJOs needed for other programming environments, such as Spring or Hibernate. Hold on to your diving caps and scuba gear, however, because next month39。t a plete dropin replacement, given that the original Person had some mutable setters. But considering the original Person a