1. 程式人生 > >Scala之主建構函式

Scala之主建構函式

主建構函式

首先,我們必須要非常清晰明確的認識到:主建構函式不是你看到的class後面跟的引數列表,那怎麼可能是主建構函式呢?那只是主建構函式的函式列表!那主建構函式的函式體在那裡呢?答案是:class body裡所有除去欄位和方法宣告的語句,剩下的一切都是主建構函式的,它們在class例項化時一定會被執行。本文原文出處: http://blog.csdn.net/bluishglc/article/details/50899077 嚴禁任何形式的轉載,否則將委託CSDN官方維護權益!

所以說,Scala的主建構函式包含這些部分:

  • The constructor parameters
  • Methods that are called in the body of the class
  • Statements and expressions that are executed in the body of the class

請看例項程式碼中的class Person1以及它的輸出。從這個例子上我們可以看出:主建構函式看上去和類的定義已經完全融合在了一起!它的引數列表放到了類名的後面(我們也可以直接叫它類引數列表),它的方法體就是整個類體,例項化一個類時,類體(主建構函式)中所有可行的部分都會被執行,不管是函式呼叫還是表示式等等,只是對於類的欄位和方法宣告而言是沒有什麼可執行的,它們只是宣告而已。

主建構函式的引數(類引數)

首先,我們還是要非常清晰明確的認識到:

  • 在主建構函式的引數列表中宣告的引數和在類體中宣告的變數本質上沒有任何不同!基於前面我們對主構造引數的理解,這就像是:在函式的引數列表中宣告的引數和方法體中宣告的變數本質上沒有任何不同一樣!

那麼接下來的問題就是要討論不管是主建構函式列表中的引數還是類體中的欄位,它們的可見性到底怎樣定義?

首先,要說明的是:var/val限定的是變數是否可讀寫,與可見性無關,即對外可見;public和private宣告的才是可見性,但是在省略這些關鍵字時還是有預設值的,情況如下:

  • 如果只有var/val修飾,則欄位總是對外可見的,即預設是public的
  • 如果連var/val也沒有,則欄位對外不可見,同時內部只讀,不可改寫,即預設是:private val
  • 第二條不適用於case class,case class的類引數在不指定val/var修飾時,會自動編譯為public val,即對外只讀,如果需要case class的欄位外部可寫,可以顯式地指定var關鍵字!

規則如下:

  • 對於var修飾的引數:外部可讀/可改寫 (實際上是:編譯器為該類引數(欄位)自動生成了getter和setter)
  • 對於val修飾的引數:外部可讀/不可改寫(實際上是:編譯器為該類引數(欄位)只生成了getter沒有生成setter)
  • 對於private var修飾的引數:內部可讀/可改寫 (編譯器不會為私有類引數(欄位)自動生成getter和setter)
  • 對於private val修飾的引數:內部可讀/不可改寫 (編譯器不會為該類引數(欄位)自動生成getter和setter)

對於主建構函式的引數列表中宣告的引數和在類體中宣告的變數是否地位一致以及它們的可見性,請看例項程式碼中的class Person2和Person3以及它們的輸出。

類欄位的getter/setter

雖然通過val/var,我們已經可以輕鬆地指定欄位的外部可訪問性了,但是我們還是要清楚的知道under the hood! 也就是說在scala裡getter和setter是怎麼寫的,雖然絕大多數情況下我們不會再像java那樣去手動地編寫getter與setter了。

示例程式碼中的Person4給我們一個很好的示例。雖然引數_age被宣告為了私有的,但是通過手動的新增getter和setter,我們還是一樣可以在外部改寫他們。

示例程式碼

object PrimaryConstructorDemo {
    //Person1 is to show: primary constructor consists of not only class args list but also all runnable part in class body.
    class Person1(var firstName: String, var lastName: String) {
        println("the constructor begins")
        // some class fields
        private val HOME = "/root"
        var age = 30
        // some methods
        override def toString = s"$firstName $lastName is $age years old"
        def printHome { println(s"HOME = $HOME") }
        def printFullName { println(this) } // uses toString
        printHome
        printFullName
        println("still in the constructor")
    }

    // Person2 is to show: the visibility of class fields
    class Person2 {
        var age = 30
        val gender = "male"
        private val healthy = false
    }

    // Person3 is to show: the visibility of primary constructor args
    class Person3(var age:Int,val gender:String,private val healthy:Boolean)

    // Person4 is to show: change visibility for primary constructor args
    class Person4(private var _age:Int) {
        def age = _age // this is getter
        def age_=(newAge: Int) = _age = newAge //this is setter
    }

    def main(args: Array[String]) {
        val p1 = new Person1("Tome","White")
        println("---------------------------------")
        val p2 = new Person2
        println(p2.age)
        p2.age = 40;
        println(p2.age)
        println(p2.gender)
        //error, no setter for gender.
        //p2.gender = false
        //error, invisible out of class.
        //println(p2.healthy)
        println("---------------------------------")
        val p3 = new Person3(30,"male",false)
        println(p3.age)
        p3.age = 40;
        println(p3.age)
        println(p3.gender)
        //error, no setter for gender.
        //p3.gender = false
        //error, invisible out of class.
        //println(p3.healthy)
        println("---------------------------------")
        val p4 = new Person4(30)
        println(p4.age)
        p4.age = 40
        println(p4.age)
    }
}

程式輸出:

the constructor begins
HOME = /root
Tome White is 30 years old
still in the constructor
---------------------------------
30
40
male
---------------------------------
30
40
male
---------------------------------
30

相關推薦

Scala建構函式

主建構函式 首先,我們必須要非常清晰明確的認識到:主建構函式不是你看到的class後面跟的引數列表,那怎麼可能是主建構函式呢?那只是主建構函式的函式列表!那主建構函式的函式體在那裡呢?答案是:class body裡所有除去欄位和方法宣告的語句,剩下的一切都是主

java高階反射獲取建構函式(二)

前提:Person類中有有參無參的建構函式,供測試用 package com.jk.fs; import java.lang.reflect.Constructor; /**  * 反射機制(獲取Class中的建構函式)  * @author sx123  

容器初始化FileSystemXmlApplicationContext建構函式

宅男Coder,沒有其他愛好,閒暇之餘抱著瞻仰的心態去閱讀一下Spring的原始碼,期許能收穫一支半解。要學習Spring的原始碼,第一步自然是下載和編譯Spring的原始碼,這個我在之前的博文中已經發表過了。具體可參考:《SpringFrame

C++拷貝建構函式和複製運算子過載

1、C++拷貝建構函式 拷貝建構函式是為了解決如神明物件時候就用一個已經存在的物件來初始化這個新的物件,如MyString A(B):這裡B是已經存在MyString物件。但是這裡需要注意拷貝建構函式裡面的內部實現細節。這裡面其實是在這個A物件類的定義中定義了拷貝建構函式的

黑馬程式設計師_java基礎學習筆記建構函式&構造程式碼塊&靜態程式碼塊)的區別

在基礎學習中,我常常會概念模糊,特作此學習筆記,進行一下對比,思路自然就清晰了。 建構函式 建構函式定義:建構函式是與類名相同,但沒有返回值的函式。 例子: class Person {     //建構函式     public Person() {} } 作用:

C++建構函式委託建構函式

                                                                                                   

Ndk學習JNI建構函式(java-->C-->Java)

1.在Java中定義建構函式(無參的不寫沒事,不被覆蓋就行)並獲取 public native Object accessConstaructor(); 2.javah生成標頭檔案 JNIEXP

Promise原始碼閱讀建構函式+then過程

前言 Promise是非同步程式設計的一種方案,ES6規範中將其寫入規範標準中,統一了用法。 考慮到瀏覽器的相容性,Vue專案中使用promise,就具體閱讀promise原始碼,看看內部的具體實現。 具體分析 通過具體例項來閱讀promise原始碼的實現,例項如下: new

JNI c/c++呼叫java建構函式

有時候c/c++是面向過程編碼,很多有用工具類都沒有,要編碼人員自己實現,如果可以呼叫java大量存在的類豈不是更省事更簡潔。 下面是通過呼叫java的Date類產生是時間戳。 public class JniConsTest { //c訪問java建構函式,並返回物件

HashMap原始碼建構函式--JDK1.8

建構函式 變數解釋 capacity,表示的是hashmap中桶的數量,初始化容量initCapacity為16,第一次擴容會擴到64,之後每次擴容都是之前容量的2倍,所以容量每次都是2的次冪 loadFactor,負載因子,衡量hashmap一個滿的程度,初始預設為0.75 thresho

QT---QDataStream的建構函式使用QByteArray物件注意事項

QDataStream 的建構函式關於使用QByteArray物件的注意事項 //先上測試程式碼: #include <QDataStream> #include <QByteArray> #include <QFile>   i

少說話多寫程式碼Python學習046——類的成員(建構函式

建構函式是一個類裡比較特殊的函式,一般即時不寫建構函式,類也會預設有一個預設建構函式,比如像下面這樣的, __init__ 其實是一個預設建構函式。   class Book:     bookName='書名'     def __init

少說話多寫程式碼Python學習047——類的成員(呼叫父類建構函式

前面我們知道了在Python中如何繼承。我們看下面的繼承關係,Bird類有一個eat方法。BigBird繼承了Bird,並且新增了sing方法。 class Bird:     def __init__(self):        

開發筆記詳述 JAVA 建構函式和程式碼塊本身及其執行細節

今天在JAVA的研究學習當中發現了建構函式這個神奇但是麻煩的東西, 他在給我感覺很像OC語言中的initWith..., 但是在細節上有很多的不同, 而程式碼塊這個東西更是讓我這個敲iOS的眼前一亮, 後來針對程式碼塊這個東西的功能和執行的順序深究了一番. 首先說說建構函式 開頭說道這個

javascript複用內建建構函式

有時,我們可能想要建立一個物件,該物件包含一組資料。如果僅僅是集合,我們可以使用陣列。但是有時,需要儲存 更多狀態,可能就需要儲存更多集合相關的元資料。 一種方式是建立這類物件的新版本,新增元資料屬性和方法,我們可以在物件上新增屬性和方法,包括陣列。然而這種方法效率低,且單調乏味。 我們如何

scala柯里化函式

定義         柯里化(Currying)指的是將原來接受兩個引數的函式變成新的接受一個引數的函式的過程。新的函式返回一個以原有第二個引數為引數的函式。也就是說,有多個引數列表的函式就是柯里化函式,所謂的引數列表就是使用小括號括起來的函式引數列表。         c

Scala 建構函式

 Scala預設主建構函式 在scala中,如果不指定主建構函式,編譯器將建立一個主建構函式的建構函式。 所有類的主體的宣告都被視為建構函式的一部分。它也被稱為預設建構函式。 Scala預設主建構函式示例 class Student{ println("He

程式碼-JS建構函式、原型物件、例項化的關係

/***************** 建構函式、原型物件、例項的關係 ********************/ function A(){ } function B(){ } //指定B的原型物件為A的一個例項 B.prototype = ne

spring深入學習(二十) IOC 建構函式例項化 bean

createBeanInstance() 用於例項化 bean,它會根據不同情況選擇不同的例項化策略來完成 bean 的初始化,主要包括: Supplier 回撥:obtainFromSupplier() 工廠方法初始化:instantiateUsingFactoryMet

C#建構函式

建構函式分為: 1.例項建構函式 2.私有建構函式 3.靜態建構函式 建構函式是一種特殊的方法,主要是為了給初始化物件賦初值。 1.例項建構函式 使用new 表示式建立某個類 的物件時,會使用例項建構函式建立和初始化所有例項成員變數。 public