Scala學習(五)類

1.簡單類和無參方法

Scala類最簡單的形式看上去和Java或C++中的很類似:ide

class Counter{

    private var value = 0  // 你必須初始化字段

    def increment() { value += 1 }   // 方法默認是公有的

    def current() = value // 定義時有(),所以調用時加不加()均可以

}

在解釋器中執行函數

在Scala中,類並不聲明爲public。Scala源文件能夠包含多個類,全部這些類都具備公有可見性。工具

--------------------------------this

建立對象:spa

val myCounter = new Counter  // 或者new Counter()

myCounter.increment()

println(myCount.current)  // 當你調用無參方法時,你能夠寫上園括號,也能夠不寫

對於改值器方法,使用(),而對於取值器方法,去掉()是不錯的風格。scala

上面的實例中:code

myCounter.increment() // 對改值器使用()

println(myCount.current)  // 對取值器不使用()

你能夠經過以不帶()的方式聲明current來強制這種風格:對象

class Counter{

    ...

    def current = value  // 定義中不帶(),所以調用時必定不能加()

}

完整實例:ip

2.帶getter和setter的屬性

Scala對每一個字段都提供getter和setter方法(自動生成不須要定義)。rem

class Count{

    var value= 0

}

咱們定義了一個共有字段age,對於私有字段而言,getter和setter方法也是私有的(因爲私有字段的getter和setter方法也是私有,所以私有字段若是須要對其進行操做,須要本身從新定義getter和setter方法)。

在Scala中,getter和setter分別叫作value 和 value=。

任什麼時候候咱們能夠本身從新定義getter和setter方法,例如:

此次咱們將value變成私有的,並新添加了getter和setter方法 v 和 v_=

針對上面setter方法的調用,咱們並無用c.v_=(20)這樣去作,而是c.v = 20 這兩種寫法是等效的。

將上面的Scala代碼編譯成class文件後查看

提示:Scala對每一個字段生成的getter和setter方法聽上去有些恐怖。不過你能夠控制這個過程。

  1. 若是字段是私有的,則getter和setter方法也是私有的。
  2. 若是字段是val,則只有getter方法生成。Scala會生成一個私有的final字段和一個getter方法。咱們在上面的Scala類中添加一個val age = 100;這個變量

    經過查看編譯後的class文件咱們能夠證實上面的結論,Scala這麼作是爲了保證val常量的只讀性。
  3. 若是你不須要任何getter和setter,能夠將字段聲明爲private[this]。

總結:實現屬性時你能夠有以下四個選擇:

  1. var foo:Scala自動合成一個getter和一個setter。
  2. val foo:Scala自動合成一個getter。
  3. 由你來定義foo和foo_=方法。
  4. 由你來定義foo方法

注:在Scala總,你不能實現只寫屬性(即帶有setter但不帶有getter的屬性)

3.對象私有字段

在Scala中,方法能夠訪問該類的全部對象的私有字段。例如:

class Count{
    private var value = 0;
    def increment(){ value += 1 }
    def isLess(other: Count) = value < other.value //能夠訪問另外一個對象的私有字段
}

之因此是合法的是由於other也是Count對象。Scala容許咱們定義更加嚴格的訪問限制,經過private[this]這個修飾符實現。

private[this] var value= 0; // 這樣該字段只能是本身的實例能訪問。

對於類私有的字段,Scala會生成getter和setter方法。但碎語對象私有的字段,Scala根本不會生成getter或setter方法。

說明:Scala容許你將訪問權限賦予指定的類。private[類名]修飾符能夠定義僅有指定類的方法能夠訪問給定的字段。這裏的類名必須是當前定義的類,或者是包含該類的外部類。

4.Bean屬性

正如以前看到的,Scala對於你定義的字段提供了getter和setter方法。可是並不符合JavaBeans規範,規範要求把Java的屬性定義爲getFoo/setFoo方法。需對Java工具都依賴這樣的習慣。

當你將Scala的字段用註解@BeanProperty標註時,你所期待的getter和setter方法將會自動生成:

import scala.beans.BeanProperty
class Count{
    @BeanProperty var name: String = _;
}

注:其中字段name後面的 _ 表示默認值

咱們來看下變異後的class文件

說明:若是你以主構造器參數(見第7節)的方式定義了某字段,而且你須要JavaBeans版的getter和setter方法,你能夠這樣來作:

class Person(@BeanProperty var name: String)

 5.構造器

和Java同樣,Scala也能夠有任意多的構造器。不過,Scala類有一個構造器比其餘全部構造器都更爲重要,他就是主構造器。除了主構造器以外,類還能夠有不少輔助構造器。

--------------------------------

咱們首先講輔助構造器:

  1. 輔助構造器的名稱爲this。
  2. 每個輔助構造器都必須以一個對先前已經定義的其餘輔助構造器或主構造器的調用開始。
class Count {
    private var name = ""
    private var age = 0

    def this(name: String){                 //一個輔助構造
        this()                                         //調用主構造
        this.name = name
    }

    def this(name: String, age: Int){     //另外一個輔助構造
        this(name)                                 //調用前一個輔助構造
        this.age = age
    }
}

6.主構造器

在Scala中,每一個類都有主構造器。主構造器並不以this方法定義,而是與類定義交織在一塊兒。

    1.主構造器的參數直接放置在類名以後。   

class Count(name: String, age: Int) {   //此處定義主構造

        ....

    }

    2.一個類若是沒有顯示的定義主構造器則自動擁有一個無參的的主構造器。這樣一個構造器僅僅是簡單的執行類體中的全部語句而已。

    3.主構造器的參數會被編譯成字段

    4.主構造器會執行類定義中的全部語句,下面的println語句是主構造器的一部分。每當有對象構造出來,上述代碼將會執行。咱們能夠理解爲Scala將Java類中的構造函數和類定義結合到了一塊兒。            

class Person(val name: String,var age){
            println("hello world")
            def description = name + "is" + age + "years old"

        }

    5.若是你以主構造器參數(見第7節)的方式定義了某字段,而且你須要JavaBeans版的getter和setter方法,你能夠這樣來作:

class Person(@BeanProperty var name: String)

    6.你一般能夠經過在主構造函數中使用默認參數來避免過多的使用輔助構造器。例如:class Person(val name:String = "",val age: Int =0)

--------------------------------

主構造器的參數能夠試任意種形態,他們有什麼區別呢?,例如:

class Count(val name: String, var age: Int,private var add: String , id: Int) { }

咱們經過觀察編譯後的class文件來看他們之間的區別:

  1. val 、var、private修飾的主構造函數中的參數最後都會被便覺得類中的字段
  2. 若是不帶val 或 var的參數至少被一個方法鎖使用,它將升級爲字段。

    class Count(val name: String,age: Int ) { 
        def out {print(age)}
    }

    咱們看到上述示例的age字段升級爲了字段。

說明:若是你想主構造器變成私有,能夠這樣:

class Person private(val id: Int){...}

7.嵌套類

在Scala中你幾乎能夠在任何語法中內嵌任何語法結構。你能夠在類中定義類,在函數中定義函數:

下面示例是一個類中定義類的示例:

import scala.collection.mutable.ArrayBuffer
class School{ 
    class Student(val name:String,var age:Int){
        val content = new ArrayBuffer[Student]
    }

    private val students = new ArrayBuffer[Student]

    def stu() = {
        var m = new Student("HYC",26)
        students += m
        m
    }
}

在Scala中,每一個實例中的嵌套類,就像它們本身的字段同樣,所以同一個類的不一樣實例,嵌套類也不是同一個類。

例如:

var school1 = new School();

var school2 = new School();

//這裏school1.Student  與 school2.Student是不一樣的類。

說明:這裏和Java不一樣,在Java中內部類從屬於外部類,而且訪問方式也不一樣。Scala訪問爲new School.Student,而Java中爲School.new Student。

因爲上面的Scala內嵌類的特性,爲此咱們須要注意一個問題,同一個類的不一樣實例,嵌套類不能相互傳遞,由於他們是不一樣的類。

例如:

var school1 = new School();

var school2 = new School();

var student1 = school1.stu;

var student2 = school2.stu;

student1.content += student2; //不能夠這樣作student1和student2 是兩個不一樣的對象!

這樣的狀況在邏輯上來說是說的通的,由於畢竟是兩種類型。可是對於數字Java的同窗好像又說不通,畢竟都是Student類型,面對這種狀況,咱們有兩種解決方案:

  1. 採用伴生對象的方式。
  2. 增長類型投影School#Student,其含義是任何School類型的Student,例如:
    class School{ 
        class Student(val name:String,var age:Int){
            val content = new ArrayBuffer[School#Student]
        }
    
    }

     

嵌套類訪問外部類:

Scala中你能夠採用 外部類.this 的方式方位外部類的this引用,你也可使用以下語法創建一個指向外部引用的別名:

class Outer(val name:String){ outer =>
   class Insider(val name:String){
      val str = name + " Inside " + outer.name
   }
}
相關文章
相關標籤/搜索