从 Java 到 Scala(一):面向对象谈起
去年我加入水滴團隊,面試中,面試官問:"你了解 Scala 嗎?"
"不了解(尷尬)。"
"你知道 Spark 嗎?它就是使用 Scala 編寫的,不過在我們團隊中,Scala 主要作為后端語言,我們 90% 以上的業(yè)務代碼都是使用 Scala 編寫。Scala 在國內(nèi)使用的比較少,但是在國外用的還是蠻多的,如 Twitter 就是使用 Scala 寫的后端。"
自那以后,我便開始了 Scala 的學習之旅。
Scala 是由德國的計算機科學家和編程方法教授?Martin Odersky?設計出來的,它的設計原理嚴格遵循數(shù)學的邏輯推理。因此它是一門優(yōu)秀的編程語言,它不僅僅在工業(yè)界被廣泛使用,在學術界也占用很高的研究地位。
由于之前的 Java 背景,我經(jīng)常拿 Scala 與 Java 這兩門語言比較。 Scala 和 Java 都基于 JVM,因此 Java 的類庫,Scala 都可以直接使用。但是我對 Scala 印象最深的點,并不是「面向?qū)ο蟆?#xff0c;而是它還擁抱「函數(shù)式」,尤其是它的「高階」。
如果我們把「面向?qū)ο蟆贡茸髡驹诘孛嫔嫌^察事物的原理,并且使用這些原理解決問題,那么「高階」就是讓你站在山上去看待事物,對問題進行更高層次的抽象。
因此不管是解決實際問題,還是提高對編程語言的認知,Scala 都是一們值得學習的語言。
我是從《快學 Scala》這本書開始學習 Scala 的,受此書啟發(fā),我想能不能書寫一個「從 Java 到 Scala 系列」,尋找一棵從 Java 通往 Scala 的連續(xù)的知識樹,通過對知識樹的講解,來學習 Scala。
好了,這就是本系列的第一篇,那么我們?nèi)绾握勂鹉?#xff1f;
既然 Java 和 Scala 都是「面向?qū)ο蟆沟?#xff0c;那我們就來探索一下什么是「面向?qū)ο蟆拱伞?/span>
模板和對象
「模板」是在代碼層面描述一類對象的「行為」或者「狀態(tài)」的代碼,它是抽象的。如 Java 中的類,C 語言中的結構體,它們都是「模板」。
「對象」是在運行期間通過模板在內(nèi)存中生成的一個個實體,它是具體的。如 Java 在運行期間通過 new 在內(nèi)存中產(chǎn)生的實體就叫做「對象」。
如果你說共享單車,那么它就是一個「模板」;如果你說這輛共享單車和那輛共享單車,那它們就是「對象」。
在代碼層面,「對象」的行為可以定義為「方法」,「對象」的狀態(tài)可以定義為「屬性」,那我們?nèi)绾稳ッ枋鲆活悺笇ο蟆沟姆椒ɑ蛘邔傩阅?#xff1f;-封裝。
例如共享單車,它有車輪,二維碼等屬性,有開鎖和關鎖等行為。那么我們可以有三種方式來封裝共享單車。
基于對象的封裝
這種方式就是直接封裝,最典型的例子就是 C 語言中的結構體。
封裝共享單車的「模板」如下:
1 2 3 4 5 6 | struct SharedBicycle{ 車輪; 二維碼; 開鎖; 關鎖; }; |
基于類的封裝
大多數(shù)「面向?qū)ο蟆沟恼Z言,如 Java,Scala,C++等,都使用這種方式封裝,「模板」如下:
1 2 3 4 5 6 | class SharedBicycle{ 屬性:車輪; 屬性:二維碼; 方法:開鎖; 方法:關鎖; } |
基于原型的封裝
JavaScript 就是使用這種封裝方式,「模板」如下:
1 2 3 4 5 6 7 | function SharedBicycle(){ this.車輪 = xxx; this.二維碼 = xxx; } //添加原型方法 SharedBicycle.prototype.開鎖 = function(){...}; SharedBicycle.prototype.關鎖 = function(){...}; |
純面向?qū)ο?/span>
我們已經(jīng)得知,可以用多種實現(xiàn)面向?qū)ο蟮牟煌夹g,那么什么是純面向?qū)ο蟮恼Z言呢?
我們知道 Java 是一門「面向?qū)ο蟆沟恼Z言,那么在 Java 中是否真的「萬物皆對象」?
在 Java 中,我們可以寫這么一段代碼?int a = 3; 然后我們發(fā)現(xiàn)?a?并沒有封裝任何的屬性或者方法。
因此我們可以說?a?不是一個「對象」,Java 不是一門「純粹面向?qū)ο蟆沟恼Z言。
再看看 Scala ,不論是低階的?Int,Double,還是高階類型,都封裝有屬性或者方法,因此 Scala 才是一門「純粹面向?qū)ο蟆沟恼Z言。
那么是什么支持 Scala 一切皆為「對象」的呢?-Scala 的通用類型系統(tǒng)。
Scala 通用類型系統(tǒng)
頂類型
我們知道,在 Java 中,所有「對象」的「頂類型」都是?java.lang.Object,但是 Java 卻忽略了?int,double等 JVM 「原始類型」,它們并沒有繼承?java.lang.Object。
但是在 Scala 中,存在一個通用的「頂類型」- Any。
Scala 引入了Any?作為所有類型共同的頂類型。Any?是?AnyRef?和?AnyVal?的超類。
AnyRef?面向 Java(JVM)的對象世界,它對應?java.lang.Object?,是所有對象的超類。
AnyVal?則代表了 Java 的值世界,例如?int?以及其它 JVM 原始類型。
正是依賴這種繼承設計,我們才能夠使用?Any?定義方法,同時兼容?scala.int?以及?java.lang.String?的實例。
1 2 3 4 5 6 7 8 9 | class Person val allThings = ArrayBuffer[Any]() val myInt = 42 // Int, kept as low-level `int` during runtime allThings += myInt // Int (extends AnyVal) allThings += new Person() // Person (extends AnyRef), no magic here |
正是通過這種「通用類型系統(tǒng)」的設計,使得 Scala 擺脫「原始類型」這種邊緣情況的糾纏,從而實現(xiàn)「純粹的面向?qū)ο蟆埂?/span>
說完了「頂類型」,我們再來看看「底類型」。
底類型
我們知道在 Java 中比較鬧心的就是異常處理,當我們調(diào)用一個拋出異常的方法,我們必須拋出或者處理異常。
但是在 Scala 中,我們知道一切表達式皆有類型,難道「拋異常」也是有類型的?
1 2 | scala> val a = Try(throw new Exception("123")) a: scala.util.Try[Nothing] = Failure(java.lang.Exception: 123) |
我們發(fā)現(xiàn)「拋異常」竟然是?Nothing?類型,在 Scala 中,難道?Nothing?僅僅是作為「拋異常」的類型?
1 2 3 4 5 6 7 8 | scala> def fun(flag:Boolean)={ if(flag){ 1 // Int }else{ throw new Exception("123") //Nothing } } fun: (flag: Boolean)Int |
我們發(fā)現(xiàn)?fun?函數(shù)并沒有報錯,而且返回值類型竟然是?Int,這讓我們有一個大膽的猜測:Nothing?是?Int?的子類型。
1 2 | [Int] -> ... -> AnyVal -> Any Nothing -> [Int] -> ... -> AnyVal -> Any |
其實在 Scala 中,?Nothing?不僅僅是?Int?的子類型,它更是所有類型的子類型。?這讓我們又產(chǎn)生了一個大膽的猜測:難道?Nothing?繼承了所有的類型?咳咳,這個問題我們以后在討論。
在 Scala 中,還有一個類型?Null?遵循著和?Nothing?一樣的原理。
1 2 3 4 5 6 7 8 | scala> def fun2(flag:Boolean)={ if(flag){ "123" //String }else{ null //Null } } fun2: (flag: Boolean)String |
同理,我們可以得出?Null?是?String的子類型
1 2 | [String] -> AnyRef -> Any Null -> [String] -> AnyRef -> Any |
那我們看看?Null?是否可以兼容?Int。
1 2 3 4 5 6 7 8 | scala> def fun3(flag:Boolean)={ if(flag){ 123 //Int }else{ null //Null } } fun3: (flag: Boolean)Any |
我們發(fā)現(xiàn)?fun3?的返回值類型竟然是?Any,說明?Null?不能兼容 Scala 的「值類型」,其實從 Scala 的幫助手冊中我們就可以得出結論:Null?是所有引用類型的子類型
1 | abstract final class Null extends AnyRef |
正因如此,fun3?的返回值類型才是?Any,因為?Any?才是?AnyVal?和?AnyRef?公共的超類。
總結
本文以面向?qū)ο鬄橐?#xff0c;找到了一個 Java 和 Scala 共有的知識節(jié)點,從而引出 Scala 的通用類型系統(tǒng)。那么在下一篇文章中,我們由此展開進一步思考,到底什么是所謂的「類型」,以及 Scala 在類型方面存在哪些與 Java 不同的有趣的地方。
本文轉(zhuǎn)載自:https://scala.cool/2018/03/java-2-scala-1/
總結
以上是生活随笔為你收集整理的从 Java 到 Scala(一):面向对象谈起的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Play! Framework 系列(三
- 下一篇: 3月20日, Java 10 正式发布了