從 Java 到 Scala(一):面向對象談起

本文由 KnewHow 發表在 ScalaCool 團隊博客。javascript

去年我加入水滴團隊,面試中,面試官問:「你瞭解 Scala 嗎?」java

「不瞭解(尷尬)。」面試

「你知道 Spark 嗎?它就是使用 Scala 編寫的,不過在咱們團隊中,Scala 主要做爲後端語言,咱們 90% 以上的業務代碼都是使用 Scala 編寫。Scala 在國內使用的比較少,可是在國外用的仍是蠻多的,如 Twitter 就是使用 Scala 寫的後端。」編程

自那之後,我便開始了 Scala 的學習之旅。後端

Scala 是由德國的計算機科學家和編程方法教授 Martin Odersky 設計出來的,它的設計原理嚴格遵循數學的邏輯推理。所以它是一門優秀的編程語言,它不只僅在工業界被普遍使用,在學術界也佔用很高的研究地位。bash

因爲以前的 Java 背景,我常常拿 Scala 與 Java 這兩門語言比較。 Scala 和 Java 都基於 JVM,所以 Java 的類庫,Scala 均可以直接使用。可是我對 Scala 印象最深的點,並非「面向對象」,而是它還擁抱「函數式」,尤爲是它的「高階」。編程語言

若是咱們把「面向對象」比做站在地面上觀察事物的原理,而且使用這些原理解決問題,那麼「高階」就是讓你站在山上去看待事物,對問題進行更高層次的抽象。函數

所以不論是解決實際問題,仍是提升對編程語言的認知,Scala 都是一們值得學習的語言。學習

我是從《快學 Scala》這本書開始學習 Scala 的,受此書啓發,我想能不能書寫一個「從 Java 到 Scala 系列」,尋找一棵從 Java 通往 Scala 的連續的知識樹,經過對知識樹的講解,來學習 Scala。this

好了,這就是本系列的第一篇,那麼咱們如何談起呢?

既然 Java 和 Scala 都是「面向對象」的,那咱們就來探索一下什麼是「面向對象」吧。

模板和對象

「模板」是在代碼層面描述一類對象的「行爲」或者「狀態」的代碼,它是抽象的。如 Java 中的類,C 語言中的結構體,它們都是「模板」。

「對象」是在運行期間經過模板在內存中生成的一個個實體,它是具體的。如 Java 在運行期間經過 new 在內存中產生的實體就叫作「對象」。

若是你說共享單車,那麼它就是一個「模板」;若是你說這輛共享單車和那輛共享單車,那它們就是「對象」。

在代碼層面,「對象」的行爲能夠定義爲「方法」,「對象」的狀態能夠定義爲「屬性」,那咱們如何去描述一類「對象」的方法或者屬性呢?-封裝

例如共享單車,它有車輪,二維碼等屬性,有開鎖和關鎖等行爲。那麼咱們能夠有三種方式來封裝共享單車。

基於對象的封裝

這種方式就是直接封裝,最典型的例子就是 C 語言中的結構體。 封裝共享單車的「模板」以下:

struct SharedBicycle{
  車輪;
  二維碼;
  開鎖;
  關鎖;
}; 
複製代碼

基於類的封裝

大多數「面向對象」的語言,如 Java,Scala,C++等,都使用這種方式封裝,「模板」以下:

class SharedBicycle{
  屬性:車輪;
  屬性:二維碼;
  方法:開鎖;
  方法:關鎖;
}
複製代碼

基於原型的封裝

JavaScript 就是使用這種封裝方式,「模板」以下:

function SharedBicycle(){
  this.車輪 = xxx;
  this.二維碼 = xxx;
}
//添加原型方法
SharedBicycle.prototype.開鎖 = function(){...};
SharedBicycle.prototype.關鎖 = function(){...};
複製代碼

純面向對象

咱們已經得知,能夠用多種實現面向對象的不一樣技術,那麼什麼是純面向對象的語言呢?

咱們知道 Java 是一門「面向對象」的語言,那麼在 Java 中是否真的「萬物皆對象」?

在 Java 中,咱們能夠寫這麼一段代碼 int a = 3; 而後咱們發現 a 並無封裝任何的屬性或者方法。

所以咱們能夠說 a 不是一個「對象」,Java 不是一門「純粹面向對象」的語言。

再看看 Scala ,不管是低階的 IntDouble,仍是高階類型,都封裝有屬性或者方法,所以 Scala 纔是一門「純粹面向對象」的語言。

那麼是什麼支持 Scala 一切皆爲「對象」的呢?-Scala 的通用類型系統。

Scala 通用類型系統

頂類型

咱們知道,在 Java 中,全部「對象」的「頂類型」都是 java.lang.Object,可是 Java 卻忽略了 intdouble等 JVM 「原始類型」,它們並無繼承 java.lang.Object

可是在 Scala 中,存在一個通用的「頂類型」- Any。

Scala 引入了Any 做爲全部類型共同的頂類型。AnyAnyRefAnyVal 的超類。

AnyRef 面向 Java(JVM)的對象世界,它對應 java.lang.Object ,是全部對象的超類。

AnyVal 則表明了 Java 的值世界,例如 int 以及其它 JVM 原始類型。

正是依賴這種繼承設計,咱們纔可以使用 Any 定義方法,同時兼容 scala.int 以及 java.lang.String 的實例。

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
複製代碼

正是經過這種「通用類型系統」的設計,使得 Scala 擺脫「原始類型」這種邊緣狀況的糾纏,從而實現「純粹的面向對象」。

說完了「頂類型」,咱們再來看看「底類型」。

底類型

咱們知道在 Java 中比較鬧心的就是異常處理,當咱們調用一個拋出異常的方法,咱們必須拋出或者處理異常。

可是在 Scala 中,咱們知道一切表達式皆有類型,難道「拋異常」也是有類型的?

scala> val a = Try(throw new Exception("123"))
a: scala.util.Try[Nothing] = Failure(java.lang.Exception: 123)
複製代碼

咱們發現「拋異常」居然是 Nothing 類型,在 Scala 中,難道 Nothing 僅僅是做爲「拋異常」的類型?

scala>  def fun(flag:Boolean)={
          if(flag){
            1                          // Int
          }else{
           throw new Exception("123") //Nothing
          }
        }
fun: (flag: Boolean)Int

複製代碼

咱們發現 fun 函數並無報錯,並且返回值類型居然是 Int,這讓咱們有一個大膽的猜想:NothingInt 的子類型。

[Int] -> ... -> AnyVal -> Any
Nothing -> [Int] -> ... -> AnyVal -> Any
複製代碼

其實在 Scala 中, Nothing 不只僅是 Int 的子類型,它更是全部類型的子類型。 這讓咱們又產生了一個大膽的猜想:難道 Nothing 繼承了全部的類型?咳咳,這個問題咱們之後在討論。

在 Scala 中,還有一個類型 Null 遵循着和 Nothing 同樣的原理。

scala> def fun2(flag:Boolean)={
          if(flag){
            "123"  //String
          }else{
            null   //Null
          }
        }
fun2: (flag: Boolean)String
複製代碼

同理,咱們能夠得出 NullString的子類型

[String] -> AnyRef -> Any
Null -> [String] -> AnyRef -> Any
複製代碼

那咱們看看 Null 是否能夠兼容 Int

scala>  def fun3(flag:Boolean)={
          if(flag){
            123  //Int
          }else{
            null   //Null
          }
        }
fun3: (flag: Boolean)Any
複製代碼

咱們發現 fun3 的返回值類型居然是 Any,說明 Null 不能兼容 Scala 的「值類型」,其實從 Scala 的幫助手冊中咱們就能夠得出結論:Null 是全部引用類型的子類型

abstract final class Null extends AnyRef
複製代碼

正因如此,fun3 的返回值類型纔是 Any,由於 Any 纔是 AnyValAnyRef 公共的超類。

總結

本文以面向對象爲引子,找到了一個 Java 和 Scala 共有的知識節點,從而引出 Scala 的通用類型系統。那麼在下一篇文章中,咱們由此展開進一步思考,到底什麼是所謂的「類型」,以及 Scala 在類型方面存在哪些與 Java 不一樣的有趣的地方。

Scala 類型的類型(一)。

相關文章
相關標籤/搜索