精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從Java走進(jìn)Scala:理解Scala的類語(yǔ)法和語(yǔ)義

開發(fā) 后端
Java開發(fā)人員可以將對(duì)象作為理解 Scala 的出發(fā)點(diǎn)。本文是面向 Java 開發(fā)人員的 Scala 指南 系列 的第二期,作者 Ted Neward 遵循對(duì)一種語(yǔ)言進(jìn)行評(píng)價(jià)的基本前提:一種語(yǔ)言的威力可以直接通過(guò)它集成新功能的能力衡量,在本文中就是指對(duì)復(fù)數(shù)的支持。跟隨本文,您將了解在 Scala 中與類的定義和使用有關(guān)的一些有趣特性。

Scala 的函數(shù)編程特性非常引人注目,但這并非 Java 開發(fā)人員應(yīng)該對(duì)這門語(yǔ)言感興趣的惟一原因。實(shí)際上,Scala 融合了函數(shù)概念和面向?qū)ο蟾拍睢榱俗?Java 和 Scala 程序員感到得心應(yīng)手,可以了解一下 Scala 的對(duì)象特性,看看它們是如何在語(yǔ)言方面與 Java 對(duì)應(yīng)的。記住,其中的一些特性并不是直接對(duì)應(yīng),或者說(shuō),在某些情況下,“對(duì)應(yīng)” 更像是一種類比,而不是直接的對(duì)應(yīng)。不過(guò),遇到重要區(qū)別時(shí),我會(huì)指出來(lái)。

Scala 和 Java 一樣使用類

我們不對(duì) Scala 支持的類特性作冗長(zhǎng)而抽象的討論,而是著眼于一個(gè)類的定義,這個(gè)類可用于為 Scala 平臺(tái)引入對(duì)有理數(shù)的支持:

清單 1. rational.scala

  1. class Rational(n:Int, d:Int)  
  2. {  
  3.   private def gcd(x:Int, y:Int): Int =  
  4.   {  
  5.     if (x==0) y  
  6.     else if (x<0) gcd(-x, y)  
  7.     else if (y<0) -gcd(x, -y)  
  8.     else gcd(y%x, x)  
  9.   }  
  10.   private val g = gcd(n,d)  
  11.     
  12.   val numer:Int = n/g  
  13.   val denom:Int = d/g  
  14.     
  15.   def +(that:Rational) =  
  16.     new Rational(numer*that.denom + that.numer*denom, denom * that.denom)  
  17.   def -(that:Rational) =  
  18.     new Rational(numer * that.denom - that.numer * denom, denom * that.denom)  
  19.   def *(that:Rational) =  
  20.     new Rational(numer * that.numer, denom * that.denom)  
  21.   def /(that:Rational) =  
  22.     new Rational(numer * that.denom, denom * that.numer)  
  23.  
  24.   override def toString() =  
  25.     "Rational: [" + numer + " / " + denom + "]" 
  26. }  
  27.    

從詞匯上看,清單 1 的整體結(jié)構(gòu)與 Java 代碼類似,但是,這里顯然還有一些新的元素。在詳細(xì)討論這個(gè)定義之前,先看一段使用這個(gè)新 Rational 類的代碼:

清單 2. RunRational

  1. class Rational(n:Int, d:Int)  
  2. {  
  3.   // ... as before  
  4. }  
  5.  
  6. object RunRational extends Application  
  7. {  
  8.   val r1 = new Rational(13)  
  9.   val r2 = new Rational(25)  
  10.   val r3 = r1 - r2  
  11.   val r4 = r1 + r2  
  12.   Console.println("r1 = " + r1)  
  13.   Console.println("r2 = " + r2)  
  14.   Console.println("r3 = r1 - r2 = " + r3)  
  15.   Console.println("r4 = r1 + r2 = " + r4)  
  16. }  

清單 2 中的內(nèi)容平淡無(wú)奇:先創(chuàng)建兩個(gè)有理數(shù),然后再創(chuàng)建兩個(gè) Rational,作為前面兩個(gè)有理數(shù)的和與差,最后將這幾個(gè)數(shù)回傳到控制臺(tái)上(注意, Console.println() 來(lái)自 Scala 核心庫(kù),位于 scala.* 中,它被隱式地導(dǎo)入每個(gè) Scala 程序中,就像 Java 編程中的 java.lang 一樣)。

用多少種方法構(gòu)造類?

現(xiàn)在,回顧一下 Rational 類定義中的第一行:

清單 3. Scala 的默認(rèn)構(gòu)造函數(shù)

  1. class Rational(n:Int, d:Int)  
  2. {  
  3.   // ... 

您也許會(huì)認(rèn)為清單 3 中使用了某種類似于泛型的語(yǔ)法,這其實(shí)是 Rational 類的默認(rèn)的、首選的構(gòu)造函數(shù):n 和 d 是構(gòu)造函數(shù)的參數(shù)。

Scala 優(yōu)先使用單個(gè)構(gòu)造函數(shù),這具有一定的意義 —— 大多數(shù)類只有一個(gè)構(gòu)造函數(shù),或者通過(guò)一個(gè)構(gòu)造函數(shù)將一組構(gòu)造函數(shù) “鏈接” 起來(lái)。如果需要,可以在一個(gè) Rational 上定義更多的構(gòu)造函數(shù),例如:

清單 4. 構(gòu)造函數(shù)鏈

  1. class Rational(n:Int, d:Int)  
  2. {  
  3.   def this(d:Int) = { this(0, d) } 

注意,Scala 的構(gòu)造函數(shù)鏈通過(guò)調(diào)用首選構(gòu)造函數(shù)(Int,Int 版本)實(shí)現(xiàn) Java 構(gòu)造函數(shù)鏈的功能。

#p#

實(shí)現(xiàn)細(xì)節(jié)

在處理有理數(shù)時(shí),采取一點(diǎn)數(shù)值技巧將會(huì)有所幫助:也就是說(shuō),找到公分母,使某些操作變得更容易。如果要將 1/2 與 2/4 相加,那么 Rational 類應(yīng)該足夠聰明,能夠認(rèn)識(shí)到 2/4 和 1/2 是相等的,并在將這兩個(gè)數(shù)相加之前進(jìn)行相應(yīng)的轉(zhuǎn)換。

嵌套的私有 gcd() 函數(shù)和 Rational 類中的 g 值可以實(shí)現(xiàn)這樣的功能。在 Scala 中調(diào)用構(gòu)造函數(shù)時(shí),將對(duì)整個(gè)類進(jìn)行計(jì)算,這意味著將 g 初始化為 n 和 d 的最大公分母,然后用它依次設(shè)置 n 和 d。

回顧一下 清單 1 就會(huì)發(fā)現(xiàn),我創(chuàng)建了一個(gè)覆蓋的 toString 方法來(lái)返回 Rational 的值,在 RunRational 驅(qū)動(dòng)程序代碼中使用 toString 時(shí),這樣做非常有用。

然而,請(qǐng)注意 toString 的語(yǔ)法:定義前面的 override 關(guān)鍵字是必需的,這樣 Scala 才能確認(rèn)基類中存在相應(yīng)的定義。這有助于預(yù)防因意外的輸入錯(cuò)誤導(dǎo)致難于覺察的 bug(Java 5 中創(chuàng)建 @Override 注釋的動(dòng)機(jī)也在于此)。還應(yīng)注意,這里沒有指定返回類型 —— 從方法體的定義很容易看出 —— 返回值沒有用 return 關(guān)鍵字顯式地標(biāo)注,而在 Java 中則必須這樣做。相反,函數(shù)中的最后一個(gè)值將被隱式地當(dāng)作返回值(但是,如果您更喜歡 Java 語(yǔ)法,也可以使用 return 關(guān)鍵字)。

一些重要值

接下來(lái)分別是 numer 和 denom 的定義。這里涉及的語(yǔ)法可能讓 Java 程序員認(rèn)為 numer 和 denom 是公共的 Int 字段,它們分別被初始化為 n-over-g 和 d-over-g;但這種想法是不對(duì)的。

在形式上,Scala 調(diào)用無(wú)參數(shù)的 numer 和 denom 方法,這種方法用于創(chuàng)建快捷的語(yǔ)法以定義 accessor。Rational 類仍然有 3 個(gè)私有字段:n、d 和 g,但是,其中的 n 和 d 被默認(rèn)定義為私有訪問(wèn),而 g 則被顯式地定義為私有訪問(wèn),它們對(duì)于外部都是隱藏的。

此時(shí),Java 程序員可能會(huì)問(wèn):“n 和 d 各自的 ‘setter’ 在哪里?” Scala 中不存在這樣的 setter。Scala 的一個(gè)強(qiáng)大之處就在于,它鼓勵(lì)開發(fā)人員以默認(rèn)方式創(chuàng)建不可改變的對(duì)象。但是,也可使用語(yǔ)法創(chuàng)建修改 Rational 內(nèi)部結(jié)構(gòu)的方法,但是這樣做會(huì)破壞該類固有的線程安全性。因此,至少對(duì)于這個(gè)例子而言,我將保持 Rational 不變。

當(dāng)然還有一個(gè)問(wèn)題,如何操縱 Rational 呢?與 java.lang.String 一樣,不能直接修改現(xiàn)有的 Rational 的值,所以惟一的辦法是根據(jù)現(xiàn)有類的值創(chuàng)建一個(gè)新的 Rational,或者從頭創(chuàng)建。這涉及到 4 個(gè)名稱比較古怪的方法:+、 -、* 和 /。

與其外表相反,這并非操作符重載。

操作符

記住,在 Scala 中一切都是對(duì)象。在上一篇 文章 中, 您看到了函數(shù)本身也是對(duì)象這一原則的應(yīng)用,這使 Scala 程序員可以將函數(shù)賦予變量,將函數(shù)作為對(duì)象參數(shù)傳遞等等。另一個(gè)同樣重要的原則是,一切都是函數(shù);也就是說(shuō),在此處,命名為 add 的函數(shù)與命名為 + 的函數(shù)沒有區(qū)別。在 Scala 中,所有操作符都是類的函數(shù)。只不過(guò)它們的名稱比較古怪罷了。

在 Rational 類中,為有理數(shù)定義了 4 種操作。它們是規(guī)范的數(shù)學(xué)操作:加、減、乘、除。每種操作以它的數(shù)學(xué)符號(hào)命名:+、-、 * 和 /。

但是請(qǐng)注意,這些操作符每次操作時(shí)都構(gòu)造一個(gè)新的 Rational 對(duì)象。同樣,這與 java.lang.String 非常相似,這是默認(rèn)的實(shí)現(xiàn),因?yàn)檫@樣可以產(chǎn)生線程安全的代碼(如果線程沒有修改共享狀態(tài) —— 默認(rèn)情況下,跨線程共享的對(duì)象的內(nèi)部狀態(tài)也屬于共享狀態(tài) —— 則不會(huì)影響對(duì)那個(gè)狀態(tài)的并發(fā)訪問(wèn))。

有什么變化?

一切都是函數(shù),這一規(guī)則產(chǎn)生兩個(gè)重要影響:

首先,您已經(jīng)看到,函數(shù)可以作為對(duì)象進(jìn)行操縱和存儲(chǔ)。這使函數(shù)具有強(qiáng)大的可重用性,本系列 第一篇文章 對(duì)此作了探討。

第二個(gè)影響是,Scala 語(yǔ)言設(shè)計(jì)者提供的操作符與 Scala 程序員認(rèn)為應(yīng)該 提供的操作符之間沒有特別的差異。例如,假設(shè)提供一個(gè) “求倒數(shù)” 操作符,這個(gè)操作符會(huì)將分子和分母調(diào)換,返回一個(gè)新的 Rational (即對(duì)于 Rational(2,5) 將返回 Rational(5,2))。如果您認(rèn)為 ~ 符號(hào)最適合表示這個(gè)概念,那么可以使用此符號(hào)作為名稱定義一個(gè)新方法,該方法將和 Java 代碼中任何其他操作符一樣,如清單 5 所示:

清單 5. 求倒數(shù)

  1. val r6 = ~r1  
  2. Console.println(r6) // should print [3 / 1], since r1 = [1 / 3] 

在 Scala 中定義這種一元 “操作符” 需要一點(diǎn)技巧,但這只是語(yǔ)法上的問(wèn)題而已:

清單 6. 如何求倒數(shù)

  1. class Rational(n:Int, d:Int)  
  2. {  
  3.   // ... as before ...  
  4.  
  5.   def unary_~ : Rational =  
  6.     new Rational(denom, numer)  
  7. }  

當(dāng)然,需要注意的地方是,必須在名稱 ~ 之前加上前綴 “unary_”,告訴 Scala 編譯器它屬于一元操作符。因此,該語(yǔ)法將顛覆大多數(shù)對(duì)象語(yǔ)言中常見的傳統(tǒng) reference-then-method 語(yǔ)法。

這條規(guī)則與 “一切都是對(duì)象” 規(guī)則結(jié)合起來(lái),可以實(shí)現(xiàn)功能強(qiáng)大(但很簡(jiǎn)單)的代碼:

清單 7. 求和

  1. 1 + 2 + 3 // same as 1.+(2.+(3))  
  2. r1 + r2 + r3 // same as r1.+(r2.+(r3)) 

當(dāng)然,對(duì)于簡(jiǎn)單的整數(shù)加法,Scala 編譯器也會(huì) “得到正確的結(jié)果”,它們?cè)谡Z(yǔ)法上是完全一樣的。這意味著您可以開發(fā)與 Scala 語(yǔ)言 “內(nèi)置” 的類型完全相同的類型。

Scala 編譯器甚至?xí)L試推斷具有某種預(yù)定含義的 “操作符” 的其他含義,例如 += 操作符。注意,雖然 Rational 類并沒有顯式地定義 +=,下面的代碼仍然會(huì)正常運(yùn)行:

清單 8. Scala 推斷

  1. var r5 = new Rational(3,4)  
  2. r5 += r1  
  3. Console.println(r5) 

打印結(jié)果時(shí),r5 的值為 [13 / 12],結(jié)果是正確的。

#p#

Scala 內(nèi)幕

記住,Scala 將被編譯為 Java 字節(jié)碼,這意味著它在 JVM 上運(yùn)行。如果您需要證據(jù),那么只需注意編譯器生成以 0xCAFEBABE 開頭的 .class 文件,就像 javac 一樣。另外請(qǐng)注意,如果啟動(dòng) JDK 自帶的 Java 字節(jié)碼反編譯器(javap),并將它指向生成的 Rational 類,將會(huì)出現(xiàn)什么情況,如清單 9 所示:

清單 9. 從 rational.scala 編譯的類

  1. C:\Projects\scala-classes\code>javap -private -classpath classes Rational  
  2. Compiled from "rational.scala" 
  3. public class Rational extends java.lang.Object implements scala.ScalaObject{  
  4.     private int denom;  
  5.     private int numer;  
  6.     private int g;  
  7.     public Rational(intint);  
  8.     public Rational unary_$tilde();  
  9.     public java.lang.String toString();  
  10.     public Rational $div(Rational);  
  11.     public Rational $times(Rational);  
  12.     public Rational $minus(Rational);  
  13.     public Rational $plus(Rational);  
  14.     public int denom();  
  15.     public int numer();  
  16.     private int g();  
  17.     private int gcd(intint);  
  18.     public Rational(int);  
  19.     public int $tag();  
  20. }  
  21.  
  22.  
  23. C:\Projects\scala-classes\code>  

Scala 類中定義的 “操作符” 被轉(zhuǎn)換成傳統(tǒng) Java 編程中的方法調(diào)用,不過(guò)它們?nèi)允褂每瓷先ビ行┕殴值拿Q。類中定義了兩個(gè)構(gòu)造函數(shù):一個(gè)構(gòu)造函數(shù)帶有一個(gè) int 參數(shù),另一個(gè)帶有兩個(gè) int 參數(shù)。您可能會(huì)注意到,大寫的 Int 類型與 java.lang.Integer 有點(diǎn)相似,Scala 編譯器非常聰明,會(huì)在類定義中將它們轉(zhuǎn)換成常規(guī)的 Java 原語(yǔ) int。

測(cè)試 Rational 類

一種著名的觀點(diǎn)認(rèn)為,優(yōu)秀的程序員編寫代碼,偉大的程序員編寫測(cè)試;到目前為止,我還沒有對(duì)我的 Scala 代碼嚴(yán)格地實(shí)踐這一規(guī)則,那么現(xiàn)在看看將這個(gè) Rational 類放入一個(gè)傳統(tǒng)的 JUnit 測(cè)試套件中會(huì)怎樣,如清單 10 所示:

清單 10. RationalTest.java

  1. import org.junit.*;  
  2. import static org.junit.Assert.*;  
  3.  
  4. public class RationalTest  
  5. {  
  6.     @Test public void test2ArgRationalConstructor()  
  7.     {  
  8.         Rational r = new Rational(25);  
  9.  
  10.         assertTrue(r.numer() == 2);  
  11.         assertTrue(r.denom() == 5);  
  12.     }  
  13.       
  14.     @Test public void test1ArgRationalConstructor()  
  15.     {  
  16.         Rational r = new Rational(5);  
  17.  
  18.         assertTrue(r.numer() == 0);  
  19.         assertTrue(r.denom() == 1);  
  20.             // 1 because of gcd() invocation during construction;  
  21.             // 0-over-5 is the same as 0-over-1  
  22.     }      
  23.       
  24.     @Test public void testAddRationals()  
  25.     {  
  26.         Rational r1 = new Rational(25);  
  27.         Rational r2 = new Rational(13);  
  28.  
  29.         Rational r3 = (Rational) reflectInvoke(r1, "$plus", r2); //r1.$plus(r2);  
  30.  
  31.         assertTrue(r3.numer() == 11);  
  32.         assertTrue(r3.denom() == 15);  
  33.     }  
  34.       
  35.     // ... some details omitted  
  36. }  

SUnit

現(xiàn)在已經(jīng)有一個(gè)基于 Scala 的單元測(cè)試套件,其名稱為 SUnit。如果將 SUnit 用于清單 10 中的測(cè)試,則不需要基于 Reflection 的方法。基于 Scala 的單元測(cè)試代碼將針對(duì) Scala 類進(jìn)行編譯,所以編譯器可以構(gòu)成符號(hào)行。一些開發(fā)人員發(fā)現(xiàn),使用 Scala 編寫用于測(cè)試 POJO 的單元測(cè)試實(shí)際上更加有趣。

SUnit 是標(biāo)準(zhǔn) Scala 發(fā)行版的一部分,位于 scala.testing 包中(要了解更多關(guān)于 SUnit 的信息,請(qǐng)參閱 參考資料)。
 
除了確認(rèn) Rational 類運(yùn)行正常之外,上面的測(cè)試套件還證明可以從 Java 代碼中調(diào)用 Scala 代碼(盡管在操作符方面有點(diǎn)不匹配)。當(dāng)然,令人高興的是,您可以將 Java 類遷移至 Scala 類,同時(shí)不必更改支持這些類的測(cè)試,然后慢慢嘗試 Scala。

您惟一可能覺得古怪的地方是操作符調(diào)用,在本例中就是 Rational 類中的 + 方法。回顧一下 javap 的輸出,Scala 顯然已經(jīng)將 + 函數(shù)轉(zhuǎn)換為 JVM 方法 $plus,但是 Java 語(yǔ)言規(guī)范并不允許標(biāo)識(shí)符中出現(xiàn) $ 字符(這正是它被用于嵌套和匿名嵌套類名稱中的原因)。

為了調(diào)用那些方法,需要用 Groovy 或 JRuby(或者其他對(duì) $ 字符沒有限制的語(yǔ)言)編寫測(cè)試,或者編寫 Reflection 代碼來(lái)調(diào)用它。我采用后一種方法,從 Scala 的角度看這不是那么有趣,但是如果您有興趣的話,可以看看本文的代碼中包含的結(jié)果(參見 下載)。

注意,只有當(dāng)函數(shù)名稱不是合法的 Java 標(biāo)識(shí)符時(shí)才需要用這類方法。

#p#

“更好的” Java

我學(xué)習(xí) C++ 的時(shí)候,Bjarne Stroustrup 建議,學(xué)習(xí) C++ 的一種方法是將它看作 “更好的 C 語(yǔ)言”(參見 參考資料)。在某些方面,如今的 Java 開發(fā)人員也可以將 Scala 看作是 “更好的 Java”,因?yàn)樗峁┝艘环N編寫傳統(tǒng) Java POJO 的更簡(jiǎn)潔的方式。考慮清單 11 中顯示的傳統(tǒng) Person POJO:

清單 11. JavaPerson.java(原始 POJO)

  1. public class JavaPerson  
  2. {  
  3.     public JavaPerson(String firstName, String lastName, int age)  
  4.     {  
  5.         this.firstName = firstName;  
  6.         this.lastName = lastName;  
  7.         this.age = age;  
  8.     }  
  9.       
  10.     public String getFirstName()  
  11.     {  
  12.         return this.firstName;  
  13.     }  
  14.     public void setFirstName(String value)  
  15.     {  
  16.         this.firstName = value;  
  17.     }  
  18.       
  19.     public String getLastName()  
  20.     {  
  21.         return this.lastName;  
  22.     }  
  23.     public void setLastName(String value)  
  24.     {  
  25.         this.lastName = value;  
  26.     }  
  27.       
  28.     public int getAge()  
  29.     {  
  30.         return this.age;  
  31.     }  
  32.     public void setAge(int value)  
  33.     {  
  34.         this.age = value;  
  35.     }  
  36.       
  37.     public String toString()  
  38.     {  
  39.         return "[Person: firstName" + firstName + " lastName:" + lastName +  
  40.             " age:" + age + " ]";  
  41.     }  
  42.       
  43.     private String firstName;  
  44.     private String lastName;  
  45.     private int age;  
  46. }  
  47.   

現(xiàn)在考慮用 Scala 編寫的對(duì)等物:

清單 12. person.scala(線程安全的 POJO)

  1. class Person(firstName:String, lastName:String, age:Int)  
  2. {  
  3.     def getFirstName = firstName  
  4.     def getLastName = lastName  
  5.     def getAge = age  
  6.  
  7.     override def toString =  
  8.         "[Person firstName:" + firstName + " lastName:" + lastName +  
  9.             " age:" + age + " ]" 

這不是一個(gè)完全匹配的替換,因?yàn)樵嫉?Person 包含一些可變的 setter。但是,由于原始的 Person 沒有與這些可變 setter 相關(guān)的同步代碼,所以 Scala 版本使用起來(lái)更安全。而且,如果目標(biāo)是減少 Person 中的代碼行數(shù),那么可以刪除整個(gè) getFoo 屬性方法,因?yàn)?Scala 將為每個(gè)構(gòu)造函數(shù)參數(shù)生成 accessor 方法 —— firstName() 返回一個(gè) String,lastName() 返回一個(gè) String,age() 返回一個(gè) int。

即使必須包含這些可變的 setter 方法,Scala 版本仍然更加簡(jiǎn)單,如清單 13 所示:

清單 13. person.scala(完整的 POJO)

  1. class Person(var firstName:String, var lastName:String, var age:Int)  
  2. {  
  3.     def getFirstName = firstName  
  4.     def getLastName = lastName  
  5.     def getAge = age  
  6.       
  7.     def setFirstName(value:String):Unit = firstName = value  
  8.     def setLastName(value:String) = lastName = value  
  9.     def setAge(value:Int) = age = value  
  10.  
  11.     override def toString =  
  12.         "[Person firstName:" + firstName + " lastName:" + lastName +  
  13.             " age:" + age + " ]" 
  14. }  

注意,構(gòu)造函數(shù)參數(shù)引入了 var 關(guān)鍵字。簡(jiǎn)單來(lái)說(shuō), var 告訴編譯器這個(gè)值是可變的。因此,Scala 同時(shí)生成 accessor( String firstName(void))和 mutator(void firstName_$eq(String))方法。然后,就可以方便地創(chuàng)建 setFoo 屬性 mutator 方法,它在幕后使用生成的 mutator 方法。

結(jié)束語(yǔ)

Scala 將函數(shù)概念與簡(jiǎn)潔性相融合,同時(shí)又未失去對(duì)象的豐富特性。從本系列中您可能已經(jīng)看到,Scala 還修正了 Java 語(yǔ)言中的一些語(yǔ)法問(wèn)題(后見之明)。

本文是面向 Java 開發(fā)人員的 Scala 指南 系列中的第二篇文章,本文主要討論了 Scala 的對(duì)象特性,使您可以開始使用 Scala,而不必深入探究函數(shù)方面。應(yīng)用目前學(xué)到的知識(shí),您現(xiàn)在可以使用 Scala 減輕編程負(fù)擔(dān)。而且,可以使用 Scala 生成其他編程環(huán)境(例如 Spring 或 Hibernate )所需的 POJO。

【相關(guān)閱讀】

  1. Scala編程語(yǔ)言專題
  2. 面向 Java 開發(fā)人員的 Scala 指南: 面向?qū)ο蟮暮瘮?shù)編程
  3. Scala的類型系統(tǒng):取代復(fù)雜的通配符
  4. Scala的類型系統(tǒng) 比Java更靈活
  5. Java程序員,你為什么要關(guān)注Scala
責(zé)任編輯:yangsai 來(lái)源: IBMDW
相關(guān)推薦

2009-09-28 11:01:39

從Java走進(jìn)Scal

2009-08-21 16:17:25

ScalaTwitter API

2009-12-09 09:15:47

從Java走進(jìn)ScalTwitter API

2009-06-17 11:44:22

Scala控制結(jié)構(gòu)

2009-07-15 10:14:25

Scala并發(fā)性

2009-02-04 17:32:03

ibmdwJavaScala

2009-06-17 13:57:25

Scala元組數(shù)組

2009-10-14 11:14:38

ScitterScalaTwitter

2009-06-19 10:51:39

Scalapackage訪問(wèn)修飾符

2009-06-19 11:13:47

Scalacase類模式匹配

2009-06-16 17:09:17

Scala面向?qū)ο?/a>函數(shù)編程

2009-08-14 11:35:01

Scala Actor

2020-10-31 17:33:18

Scala語(yǔ)言函數(shù)

2009-06-17 13:26:06

scala繼承模型

2009-06-19 13:16:36

Scala計(jì)算器解析器組合子

2009-09-09 11:37:08

Scala的模式匹配

2009-07-20 16:56:51

Scala類的定義

2009-12-11 10:42:00

Scala講座類定義構(gòu)造函數(shù)

2009-07-08 12:43:59

Scala ServlScala語(yǔ)言

2009-07-22 07:41:00

Scala函數(shù)文本占位符語(yǔ)法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

欧美放荡办公室videos4k| 欧美日本韩国一区二区三区视频| 国产高清精品一区二区三区| 国产免费av一区| 四季av在线一区二区三区| 精品免费日韩av| 青青草精品视频在线观看| 成人福利在线观看视频| 99精品欧美一区二区三区小说| 国产精品99久久久久久www| 日本a级片在线播放| 色窝窝无码一区二区三区| 美女视频一区免费观看| 久久国产精品久久精品| 人妻视频一区二区| 好吊妞国产欧美日韩免费观看网站| 在线观看视频欧美| 亚洲人成无码网站久久99热国产 | 久久激情视频| 欧美老少配视频| 精品无码人妻一区二区免费蜜桃| 精品一区二区三区亚洲| 欧美影院一区二区| 少妇高潮喷水在线观看| 黄av在线播放| 国产精品午夜在线| 久久亚洲免费| 高h调教冰块play男男双性文| 青青青爽久久午夜综合久久午夜| 久久久在线免费观看| 自拍偷拍第9页| 蜜桃a∨噜噜一区二区三区| 精品久久99ma| 天天操夜夜操很很操| 国产精品videossex撒尿| 精品久久久久久中文字幕一区奶水| 超碰在线免费观看97| 国产精品麻豆一区二区三区 | 日韩精品大片| 日本私人网站在线观看| 成人久久18免费网站麻豆 | 香蕉视频免费看| 国产69精品一区二区亚洲孕妇 | 日韩一级理论片| 松下纱荣子在线观看| 亚洲一级片在线观看| 欧美精品一区二区性色a+v| 在线a免费看| 国产精品午夜在线| 亚洲成人在线视频网站| 第一福利在线| 中文在线一区二区| 亚洲日本无吗高清不卡| 午夜老司机在线观看| 国产精品高潮久久久久无| 亚洲精品视频一二三| 69av亚洲| 国产精品国模大尺度视频| 亚洲免费视频一区| 免费网站成人| 一区二区三区国产精品| av一区二区三区免费观看| 国产网红在线观看| 精品久久中文字幕久久av| 欧美日韩性生活片| 欧美人体一区二区三区| 在线视频综合导航| 九九热99视频| 亚洲一区二区三区免费| 精品福利在线导航| 五月婷婷综合在线观看| 国产欧美亚洲精品a| 国产亚洲欧洲黄色| 黄色一级大片在线免费观看| 永久亚洲成a人片777777| 午夜精品久久久久久久白皮肤 | 欧美精品亚洲二区| 少妇性l交大片7724com| 久久动漫网址| 中文字幕日韩高清| 九九热国产精品视频| 极品中文字幕一区| 国产精品第一视频| av男人天堂av| 99久久精品免费| 亚洲精品国产一区| 超碰中文在线| 在线观看区一区二| 亚洲 自拍 另类 欧美 丝袜| 欧美日韩精品一区二区三区在线观看| 亚洲午夜av久久乱码| www.毛片com| 亚洲欧美激情诱惑| 91香蕉国产在线观看| 色婷婷av一区二区三区之红樱桃 | www..com国产| 激情深爱一区二区| 精品无码久久久久久久动漫| 3p在线观看| 午夜av一区二区| 亚洲另类第一页| 精品福利一区| 日韩中文字幕视频在线观看| 日产精品久久久久| 久久99精品久久久久久久久久久久 | www.av88| 99视频一区二区三区| 亚洲人一区二区| 日韩欧美一中文字暮专区| 欧美男人的天堂一二区| 91精品人妻一区二区| 综合久久99| 国产精品久久999| 人妻无码一区二区三区久久99| 国产精品色哟哟| 欧美 丝袜 自拍 制服 另类| 欧美黄色一级| 日韩天堂在线视频| 中文字幕在线看人| 成人美女视频在线看| 亚洲第一综合网站| 丰满少妇一区| 亚洲香蕉av在线一区二区三区| www.av视频在线观看| 久久国产福利国产秒拍| 欧洲精品一区色| 9i看片成人免费高清| 亚洲成人aaa| 九九久久免费视频| 国产精品综合在线视频| 亚洲啪啪av| 欧美aaa大片视频一二区| 日韩av在线电影网| 国产一级淫片免费| 国产精品一区二区三区99| 一个色的综合| 天天综合91| 色婷婷av一区二区三区久久| 中文永久免费观看| 国产欧美精品一区aⅴ影院| 99精品视频播放| 日本欧美高清| 人人澡人人澡人人看欧美| 五月婷婷深深爱| 欧美日韩激情美女| 国产精品无码网站| 男人的天堂亚洲| 欧美凹凸一区二区三区视频 | 欧美日韩在线大尺度| 91在线网站视频| 性爱视频在线播放| 欧美精品一区二区三区蜜桃| 日韩欧美亚洲视频| 久久综合久久鬼色中文字| av免费中文字幕| 精品国产一区二区三区| 国产精品久久在线观看| av在线电影播放| 欧美老女人在线| 中文字幕av免费在线观看| 国产99精品在线观看| 日韩一级性生活片| 台湾色综合娱乐中文网| 日韩美女中文字幕| jizz在线观看视频| 91精品国产综合久久久久| 免费一级a毛片夜夜看 | 久久国产精品无码网站| 在线精品亚洲一区二区| 日韩欧美另类中文字幕| 97碰碰碰免费色视频| 欧美成熟毛茸茸| 欧美人伦禁忌dvd放荡欲情| √天堂中文官网8在线| 成人黄色网址在线观看| 久久久精品在线视频| 成人在线免费视频观看| 亚洲精品免费av| 色老头在线一区二区三区| 永久555www成人免费| 国产剧情精品在线| 亚洲成人你懂的| 真实乱视频国产免费观看| 激情五月婷婷综合网| 性欧美大战久久久久久久| 精品国产一区二区三区小蝌蚪| 成人黄色av网站| 欧美日韩国产观看视频| 最近的2019中文字幕免费一页 | 亚洲 国产 日韩 欧美| 亚洲人成精品久久久久| 亚洲一区二区三区综合| 麻豆一区二区在线| r级无码视频在线观看| 精品高清久久| 国产99午夜精品一区二区三区| 欧美电影免费看| 欧美国产日韩在线| av一本在线| 日韩av一卡二卡| 国产人妻精品一区二区三区| 富二代精品短视频| 草视频在线观看| 久久精品亚洲麻豆av一区二区| 久久精品一二三四| 日本成人在线电影网| 免费一级特黄特色毛片久久看| 午夜激情久久| 日韩精品大片| 亚洲黄页网站| 国产欧美日韩一区二区三区| 综合久久伊人| 国产精品高潮呻吟久久av野狼| 136福利第一导航国产在线| 精品久久久91| 成人免费在线电影| 亚洲另类图片色| 人妻无码中文字幕免费视频蜜桃| 欧美一级日韩不卡播放免费| 97人妻一区二区精品视频| 午夜精品爽啪视频| 久久久精品国产sm调教网站| 国产精品久久久久久久午夜片| 久久久久久久久久久国产精品| 成人动漫一区二区在线| 在线播放国产视频| 精品一区二区三区日韩| 手机在线免费观看毛片| 久久久久久婷| 成人小视频在线看| 中文亚洲欧美| 欧美一区二区中文字幕| 在线日本成人| 国产一区二区四区| 狠狠干成人综合网| 久久综合亚洲精品| 中文一区一区三区免费在线观看| 亚洲最新在线| 国产精品久久久久久影院8一贰佰 国产精品久久久久久麻豆一区软件 | 日韩网站中文字幕| 国产精品久久久久久av| 日韩三区免费| 国产精品毛片a∨一区二区三区|国 | 国产精品一区亚洲| 欧美牲交a欧美牲交| 国产精品一国产精品k频道56| 777久久久精品一区二区三区 | 91综合久久| 综合国产精品久久久| 91精品天堂福利在线观看| 天堂v在线视频| 欧美在线视屏| 国产精品www在线观看| 亚洲福利免费| 2022亚洲天堂| 日韩av在线播放中文字幕| 在线免费视频a| 极品美女销魂一区二区三区免费| 中文字幕精品一区二区三区在线| 国产在线精品一区在线观看麻豆| 欧美专区第二页| 成人国产精品免费观看| 亚洲精品理论片| 国产精品免费丝袜| 一区二区在线观看免费视频| 午夜精品久久久久久久| 一级成人黄色片| 欧美日韩综合一区| 国产成人精品无码高潮| 亚洲国产小视频| 国产天堂素人系列在线视频| 久久精品免费电影| 国产美女一区视频| 欧洲中文字幕国产精品| 精品久久99| 国产成人精品免费视频大全最热| 亚洲人成网亚洲欧洲无码| 亚洲国产激情一区二区三区| 欧美福利专区| 无码人妻丰满熟妇区五十路百度| 精品一区二区免费视频| 日本中文字幕有码| 久久精品视频网| www青青草原| 欧美性jizz18性欧美| 91久久国语露脸精品国产高跟| 精品久久久久久久久久久久久久久久久| 久久久资源网| 久久国产精品亚洲| 日本免费久久| 成人av蜜桃| 久久高清精品| 国产白丝袜美女久久久久| 六月丁香婷婷久久| 久久久久麻豆v国产精华液好用吗| 国产精品久久久久久户外露出| 国产性xxxx高清| 在线不卡a资源高清| 男人av在线| 久久久久国产精品免费网站| 久久亚洲人体| 欧美日韩系列| 亚洲日本国产| 亚洲三级在线视频| 中文字幕欧美国产| 中文字幕激情小说| 日韩欧美中文字幕一区| porn视频在线观看| 日本精品久久久| jazzjazz国产精品久久| 亚洲一区二区三区精品在线观看| 久久国产高清| 欧美深性狂猛ⅹxxx深喉| 亚洲免费观看高清| 亚洲专区第一页| 亚洲视频在线免费看| 毛片在线导航| 亚洲一区制服诱惑| 久久高清免费| 久久久久国产一区| 国产亚洲欧美日韩日本| 一级aaa毛片| 日韩精品专区在线影院重磅| 黄a在线观看| 成人久久久久爱| 国产精品久久久久久麻豆一区软件 | 久久黄色级2电影| 国产精品成人在线视频| 一本色道久久加勒比精品| 色香蕉在线视频| 久久久久久久色| 中文字幕一区二区三区四区久久 | 一区二区三区四区国产| 日韩av在线免费观看不卡| 久久精品国产亚洲AV熟女| 狠狠躁夜夜躁人人躁婷婷91 | 国产精品色在线| 亚洲一卡二卡在线观看| 中文字幕欧美日韩va免费视频| 91天天综合| 亚洲精品国产一区| 久久精品久久99精品久久| 国产又粗又长又黄的视频| 欧美性大战久久久久久久蜜臀| 国产中文字幕在线播放| 国产精品扒开腿做爽爽爽男男| 国产探花一区| 三年中国国语在线播放免费| 日本一区二区三区国色天香 | 最新中文字幕久久| 国产真实乱偷精品视频免| 手机在线免费看毛片| 日韩午夜小视频| 丁香花在线影院| 久久国产精品亚洲va麻豆| 久久亚洲电影| 奇米网一区二区| 欧美一区二区三区在线看| 欧美xxxxhdvideosex| 国产一区二区三区无遮挡 | 不卡的一区二区| 五月天精品一区二区三区| 精品视频三区| 国产欧美在线视频| 午夜久久影院| jlzzjizz在线播放观看| 欧美无乱码久久久免费午夜一区| 日本电影全部在线观看网站视频| 亚洲已满18点击进入在线看片 | 亚洲色图视频免费播放| 亚洲国产欧美另类| 2019中文字幕在线免费观看| 国产欧美高清视频在线| 香蕉视频xxx| 亚洲aⅴ怡春院| lutube成人福利在线观看| 99国产高清| 久久婷婷亚洲| 青草草在线视频| 亚洲视频网站在线观看| avtt久久| 免费黄色福利视频| 综合久久久久久久| 免费国产羞羞网站视频| 国产精品久久久久久久av电影| 欧美黄色一区二区| 97超碰在线免费观看| 91精品国产色综合久久ai换脸| av漫画网站在线观看| 亚洲成人18| av中文字幕在线不卡| 一级片在线观看视频| 97精品国产97久久久久久免费 | 国产精品三p一区二区| 九色porny自拍| 欧美日韩日本国产| 成人日批视频| 色女孩综合网| www.在线欧美| 一区二区国产欧美|