Scala 類和對(duì)象

如果類沒有內(nèi)容(body),可以省略空的花括號(hào),只寫一行語(yǔ)句

class User
val user1 = new User

類可以帶參數(shù),類名稱C之后圓括號(hào)內(nèi)的參數(shù),x稱為類參數(shù)class parameter,Scala編譯器會(huì)使用類參數(shù)創(chuàng)建出一個(gè)主構(gòu)造函數(shù)paimary constructor

class C(x: R)

私有主構(gòu)造函數(shù),只在被類本身以及伴生對(duì)象訪問

class class C(private x: R) 

Scala編譯器會(huì)將編譯類內(nèi)部的任何代碼,如果代碼不是字段定義和方法定義,則被編譯到主構(gòu)造函數(shù)中
可以用_對(duì)成員初始變量進(jìn)行初始化,對(duì)應(yīng)為0或者null

class C(var x: R) {
  assert(x > 0, "positive please") //對(duì)參數(shù)的合法性進(jìn)行檢驗(yàn)
  var y = x
  val readonly = 5
  private var secret = _
  def this() = this(42)
} 

assert 方法位于scala.Predef對(duì)象內(nèi)

輔助構(gòu)造函數(shù)
主構(gòu)造函數(shù)之外的構(gòu)造函數(shù)稱為輔助構(gòu)造函數(shù),輔助構(gòu)造函數(shù)的第一個(gè)條語(yǔ)句必須是調(diào)用同類的其他構(gòu)造函數(shù),所有每個(gè)Scala構(gòu)造器最終都會(huì)調(diào)用主構(gòu)造器

  def this() = this(42)

私有構(gòu)造函數(shù)
在類名稱和參數(shù)列表之間添加關(guān)鍵字private/protected,來聲明私有的或受保護(hù)的構(gòu)造函數(shù)

class C private (var x: R)

隱式轉(zhuǎn)換
implicit 修飾符告訴編譯器在某些情況下自動(dòng)應(yīng)用它,它必須定義在作用域范圍之內(nèi)

implicit def intToRational(x: Int) = new Rational(x)

創(chuàng)建一個(gè)隱式轉(zhuǎn)換,在需要時(shí)自動(dòng)將整數(shù)轉(zhuǎn)換為有理數(shù)


抽象類

使用abstract來聲明

abstract class D { ... }

繼承
子類擁有父類非private的方法,如果不顯示指明繼承,默認(rèn)繼承scala.AnyRef,與java.lang.Object等同

class C extends D { ... }

方法重載
override關(guān)鍵詞,進(jìn)行函數(shù)重載,如果子類重寫了父類的具體函數(shù),必須添加override修飾符,否則就會(huì)出現(xiàn)編譯錯(cuò)誤

在Scala中,字段和方法屬于同一個(gè)名稱空間,可以使用字段覆蓋無(wú)參數(shù)的方法

abstract class Element {
    def contents: Array[String]
}

class ArrayElement(conts: Array[String]) extends Element {
    val contents: Array[String] = conts
}

Java有四個(gè)名稱空間是字段,方法,類型和包,相比之下,Scala有兩個(gè)命名空間namespace

  • 值(字段,方法,包和單例對(duì)象)
  • 類型(類和特質(zhì)名稱)
    因此可以用字段覆蓋無(wú)參數(shù)的方法,同一類內(nèi)部的字段和方法名稱不能相同

調(diào)用超類的構(gòu)造函數(shù)
傳遞參數(shù)給超類的主構(gòu)造函數(shù),把參數(shù)放到超類名稱后的括號(hào)內(nèi)即可

class D(var x: R)
class C(x: R) extends D(x)

參數(shù)化字段 parametric field

一種簡(jiǎn)寫方式,用于組合參數(shù)和字段,同時(shí)定義同名的參數(shù)和字段

//這里的conts只是構(gòu)造函數(shù)的參數(shù),類沒有對(duì)應(yīng)的字段
class ArrayElement(conts: Array[String]) extends Element {  
    val contents: Array[String] = conts
}
// 簡(jiǎn)寫,自動(dòng)生成同名的字段
class ArrayElement(
    val contents: Array[String]
) extends Element

參數(shù)前可以是val,var,private,protectedoverried之類的修飾符

class Cat {
  val dangerous = false
}
class Tiger(
    override val dangerous: Boolean,
    private var age: Int
) extends Cat
//等價(jià)于
class Tiger(param1: Boolean, param2: Int) extends Cat {
    override val dangerous = param1
    private var age = param2
}

實(shí)際上如在出構(gòu)造函數(shù)之外的地方使用構(gòu)造參數(shù),內(nèi)部依然會(huì)把它轉(zhuǎn)換為private val類型的字段

  class Foo(bar: Int){
    def funtion1(): Unit ={
      println(bar)
    }
  }

內(nèi)部包含字段private val bar: Int,與class Foo(private val bar: Int)的區(qū)別在于沒有對(duì)應(yīng)的私有g(shù)etter方法private int bar();生成


變量的Getter/Setter方法

Scal字段會(huì)自動(dòng)生成getter和setter方法,val類型沒有setter方法
Scala支持setter方法的名稱為getter函數(shù)名后加_=,使用時(shí)可以對(duì)getter函數(shù)名直接賦值

class Test{
  private var _x = 0

  def x = _x //get方法
  def x_= (newValue: Int): Unit = { //set方法
    _x = newValue
  }
}

//使用方法
val test = new Test
test.x = 5
val x = test.x

Singleton Objects

Scala沒有static成員,通過單例對(duì)象來實(shí)現(xiàn)類似功能,等同于把所有的靜態(tài)成員都放到了單例對(duì)象中,可以通過名稱直接調(diào)用它的方法,就像一個(gè)靜態(tài)方法的集合

  • 它的定義類似于一個(gè)類的定義,不同的是它的關(guān)鍵字是object
  • object是只有一個(gè)實(shí)例的類,本身可以看做是一個(gè)惰性加載的val類型
  • 實(shí)際實(shí)現(xiàn)是一個(gè)合成類(synthetic class)實(shí)例,被類成員中的一個(gè)靜態(tài)變量引用,編譯產(chǎn)生的類名是對(duì)象名稱加上美元符號(hào)SingletonObjectName$

單例對(duì)象和類的一個(gè)不同在于單例對(duì)象不能接收參數(shù),而類可以。因?yàn)椴荒苁褂?new 來實(shí)例化一個(gè)單例對(duì)象,因此沒有辦法給它傳遞參數(shù)

Companion object

單例對(duì)象的名字和類名稱一致的時(shí)候叫做伴生對(duì)象companion object,必須在同一個(gè)文件中定義類和它的伴生對(duì)象,他們可以互相訪問對(duì)方的私有成員

standalone object

沒有和類共享名稱的單例對(duì)象叫做獨(dú)立對(duì)象,為了運(yùn)行一個(gè)Scala程序,必須提供一個(gè)獨(dú)立對(duì)象,內(nèi)部包含一個(gè)程序執(zhí)行的入口函數(shù)def main(args: String) = {}

Scala每個(gè)源文件都默認(rèn)包含java.langscala包,以及scala.Predef的單例對(duì)象
Predef中包含了許多有用的方法, 例如,printlnassert方法
同時(shí)Scala不要求 .scala文件名稱對(duì)應(yīng)內(nèi)部的類,可以隨意命名

通過混入scala.App類型的trait,定義應(yīng)用程序?qū)ο?,即在?duì)象后添加extends App,放置在main方法中的代碼直接放在單體對(duì)象的花括號(hào)之間,通過args字符串?dāng)?shù)組訪問命令行參數(shù)即可


特質(zhì)trait

封裝字段和方法定義,類似Java的接口,使用extends或者with關(guān)鍵字,混入(mixin)到類中,數(shù)量沒有限制
使用extends關(guān)鍵詞,類隱式繼承特質(zhì)的超類(特質(zhì)沒有聲明超類時(shí),默認(rèn)為AnyRef
如果類已經(jīng)顯示擴(kuò)展超類,使用with

  • trait不能有類參數(shù)(傳遞到類的主構(gòu)造函數(shù)的參數(shù))
  • 超類調(diào)用是不確定的,動(dòng)態(tài)變化的(trait超類的調(diào)用方式)
trait T1; trait T2
class C extends T1 with T2
class C extends D with T1 with T2

特質(zhì)不僅可以有抽象方法,也可以包含具體方法

trait Ordered[A] extends Any with java.lang.Comparable[A] {
  def compare(that: A): Int
  def <  (that: A): Boolean = (this compare that) <  0
  def >  (that: A): Boolean = (this compare that) >  0
  def <= (that: A): Boolean = (this compare that) <= 0
  def >= (that: A): Boolean = (this compare that) >= 0
  def compareTo(that: A): Int = compare(that)
  def compareTo(that: A): Int = compare(that)
}

stackable modification 可堆疊的變化

特點(diǎn)

  • 特質(zhì)指定超類,那么只能用于同樣擴(kuò)展該超類的類
  • 特質(zhì)的抽象方法調(diào)用超類,特質(zhì)中的super調(diào)用是動(dòng)態(tài)綁定的,混入另一個(gè)特征或類后,才有具體的定義

abstract override修飾符組合,只能由于特質(zhì),它表明特質(zhì)必須混入到有具體方法定義的類中

abstract class IntQueue {
  def get(): Int
  def put(x: Int)
}

import scala.collection.mutable.ArrayBuffer
class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]
  def get() = buf.remove(0)
  def put(x: Int) = { buf += x }
}

trait Doubling extends IntQueue {
  abstract override def put(x: Int) = { super.put(2 * x) }
}

trait Incrementing extends IntQueue {
  abstract override def put(x: Int) = { super.put(x + 1) }
}
trait Filtering extends IntQueue {
  abstract override def put(x: Int) = {
    if (x >= 0) super.put(x)
  }
}

val queue = (new BasicIntQueue with Filtering with Incrementing)

多個(gè)traits重載同一個(gè)方法,不同的次序會(huì)產(chǎn)生不同的類,優(yōu)先級(jí)是從右向左,以類似棧的形式調(diào)用函數(shù)
類似多重繼承,是利用線性化linearization算法解釋超類

當(dāng)用new實(shí)例化一個(gè)類時(shí),Scala把這個(gè)類及其所有繼承的類和特質(zhì)以線性次序放在一起。 然后,每當(dāng)其中一個(gè)類中調(diào)用super時(shí),被調(diào)用的方法就是鏈中的下一個(gè)。 如果除最后一次調(diào)用之外的所有方法都調(diào)用super,那么最終結(jié)果就是是可堆疊行為

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Scala與Java的關(guān)系 Scala與Java的關(guān)系是非常緊密的?。?因?yàn)镾cala是基于Java虛擬機(jī),也就是...
    燈火gg閱讀 3,606評(píng)論 1 24
  • 類是對(duì)象的抽象,而對(duì)象是類的具體實(shí)例。類是抽象的,不占用內(nèi)存,而對(duì)象是具體的,占用存儲(chǔ)空間。類是用于創(chuàng)建對(duì)象的藍(lán)圖...
    Bloo_m閱讀 346評(píng)論 0 0
  • 前面提到Scala比Java更加面向?qū)ο螅@是因?yàn)镾cala不允許類保護(hù)靜態(tài)元素(靜態(tài)變量或靜態(tài)方法)。在Scal...
    MaLiang閱讀 347評(píng)論 0 2
  • 有了前面的Scala基礎(chǔ),從本篇開始由淺到易逐步介紹Scala編程的各個(gè)方面,博客不可能做到面面俱到,還是希望你有...
    MaLiang閱讀 259評(píng)論 0 2
  • 今天小巍一個(gè)人在醫(yī)院,我卻在上班,對(duì)不起.............. 2017年12月18,家里的小家伙,病理性骨...
    趙東偉同學(xué)閱讀 74評(píng)論 0 0

友情鏈接更多精彩內(nèi)容