您的位置:首页 > 其它

Scala之主构造函数

2016-03-15 19:10 302 查看

主构造函数

首先,我们必须要非常清晰明确的认识到:主构造函数不是你看到的class后面跟的参数列表,那怎么可能是主构造函数呢?那只是主构造函数的函数列表!那主构造函数的函数体在那里呢?答案是:class body里所有除去字段和方法声明的语句,剩下的一切都是主构造函数的,它们在class实例化时一定会被执行。本文原文出处: /article/3721988.html 严禁任何形式的转载,否则将委托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声明的才是可见性,只是说:对于类字段和类参数来说,如果没有特别指定,它们总是public的。

规则如下:

对于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,我们还是一样可以在外部改写他们。

示例代码

[code]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)
    }
}


程序输出:

[code]the constructor begins
HOME = /root
Tome White is 30 years old
still in the constructor
---------------------------------
30
40
male
---------------------------------
30
40
male
---------------------------------
30
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: