天天看點

scala 學習筆記(03) 參數預設值、不定個數參數、類的屬性(Property)、泛型初步

繼續學習,這一篇主要是通過scala來吐槽java的,同樣是jvm上的語言,差距咋就這麼大呢?

作為一個有.NET開發經驗的程式員,當初剛接觸java時,相信很多人對java語言有以下不爽(隻列了極小一部分):

1. 一堆的setter/getter方法,沒有c#中的property屬性概念

2. 方法的參數值,不能設定預設值

3. 不定個數參數的寫法太單一

...

然後java的擁護者講出一堆大道理,說這樣設計是如何如何有道理,各種洗腦,時間長了,也就被迫習慣了。要不是遇到scala,我還真就信了,你看看人家scala同學,2003/2004釋出的,早就把這些全實作了,而java同學作為jvm上的元老,這些年一直頑固不化,不思進取,已經被jvm上的其它同學遠遠甩在後面了,java你可長點心吧!進入正題,直接上碼:

一、參數預設值

 調用示例:

當然這裡有一個小小的限制,如果要用參數預設值,建議所有的參數全設定預設值,如果隻給部分參數設定預設值,函數定義不會有問題,調用時,上面的示例編譯就通不過了(大意是提供的參數不足之類),大家可以把msg參數的預設值去掉再試試。

那麼,最終編譯出來的class,到底是如何實作的呢?可以借助一些反編譯工具,比如JD-GUI還原成java一看究竟:

也就是說,scala中的def saySomething(person: String = "somebody", msg: String = "Hello") 如果用java實作的話,可以用3個方法來變相實作,每個預設參數,相當于一個獨立的版本,換言之,在編譯器層面,其實java的編譯器如果想做,是完全可以做到的,為什麼不做?懶!頑!

二、class的property

調用示例:

沒了setter/getter看起來倍兒清爽!還是反編譯class看看:

可以看到,myProperty自動生成了setter/gettter,仍然是在編譯器層面,就可以順手做掉的事情,java編譯器依然不肯做。

三、不定個數參數值

這個問題,java中雖然可以xxx(String[] args)用數組傳遞達到類似的效果,但是就算傳一個空數組,也至少也得寫一個xxx(null)吧,既然此時參數都為空了,為啥不直接xxx()更直接,看看scala:

 調用:

 明顯的更高端大氣上檔次,繼續反編譯,這個要略複雜點:

先是生成了這麼一個類:

然後是:

最終調用時,add()這裡雖然scala沒有傳任何參數,但從反編譯結果上看,最終還是變成了add(Nil..MODULE$)),編譯器自動加了一個參數,以滿足java的規範。

四、泛型初步

java中的泛型是一個"僞"泛型,其類型擦除機制隻是障眼法而已,是以帶來了很多使用上的限制,比如下面這個例子:

 這裡定義了一個泛型類,如果想建立一個該類的數組:

編譯器會直接報錯:Error: java: generic array creation,原因是:type erase後,内部已經是SampleClass[],按OOP的原則,可以向上轉型為Object[],這下可好了,Object是萬能類型,如果向這個萬能類型的數組裡加入一個不是SampleClass<String>的執行個體,理論上也是允許的,這就違背了泛型限制的初衷。

但是在scala中,卻是可以這樣做的,看下面的代碼:

然後可以這樣用:

編譯和運作一切正常,這是什麼情況?還是反編譯解密:

原來,對于java的僞泛型機制,scala早就看穿了這一切,是以它采用了一種略帶"極端"的做法,直接使用原始類型,無情的對java的泛型機制回應:『不約,我們不約』。

了解以上這些後,我不得不更加佩服堅持使用java語言寫出這麼多NB開源架構的達人們,硬是用一個要啥啥沒有的語言為開源世界做出這麼大的貢獻,這是一種什麼樣的精神,無禁讓我想起了《道士下山》中猿擊術中的精髓:"不離不棄,不嗔不恨!",我隻想說:這麼多年,你們是怎麼忍下來的!

So,Scala既然這麼好,就完美無缺了麼?當然不是,功能越強大,文法越靈活,自然學習成本也更高。另外,性能方面,它生成的位元組碼感覺比java略多,網上有很多關于scala與java的性能讨論,包括google也有類似的評測,有人說這二者差不多,但是多數人還是認為在jvm上,scala的性能整體來看要低于java,隻能達到java的8成上下(詳情可自行百度,有很多這類文章)