开发者学堂课程【Scala 核心编程-基础:Scala 的超类构造分析】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/609/detail/8974
Scala 的超类构造分析
1、类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是间接调用)。
这里直接看一段代码,输出会是什么内容:
class Person{
var name = "zhangsan"
println(""Person...")
class Emp extends Person{
println( Emp ....")
def this(name : String){
thisⅡ必须调用主构造器
this.name = name
println( Emp 辅助构造器~)
}
}
举例:在 scala 中新创建一个 object 文件名为 scalabaseconstartor
将代码带入:
package com.atguigu.chaptero7.myextends
object scalaBaseconstrator
def main(args : Array [string]): unit = {
}
}
class Person700{
//这里有一个父类 person
var name = "zhangsan"
println("Person...")
class Emp700
()
extends Person700
()
{
//子类 emp 继承 person
println(
“
Emp ....")
def this(name : String){
//辅助构造器
thisⅡ必须调用主构造器
this.name = name
println( Emp 辅助构造器~)
}
}
现在在上方构建一个子类:
val emp = new Emp700()
它的执行流程是:
(1)因为 scala 遵守先构建父类部分 extends Person700()
(2)如果有参数也是可以通过父类传递进去,那么就会先输出 Person...
(3)执行完父类构造器后执行 Emp ....(emp 700的主构造器)
(4)执行下面的代码,进行赋值操作,完成后执行 Emp 辅助构造器~
这时执行会发现没有效果,因为没有传参数,直接调用的主构造器,没有调用 def this(name : String) 辅助构造器。
解决办法是将第4步删除后,在构建的子类下方写入:
val emp2 =new Emp700( "mary")
这样就会执行刚才的第4步,为了演示区别写入换行:
println("====================)
执行:
D: lprogram\jdk8\binljavaPerson. . .
Emp ....
=================
Person..
Emp ....
Emp 辅助构送器~
Process finished with exit code o
扩展:
如果将父类 person 改为:
c
lass Person700
(pname:string)
var
name
=
pname
println("Person...")
这样写马上就会报错,报错的原因是 class Emp700() extends Person700()
因为在调用的时候会先调用 extends Person700(),会发现没有,因为主构造器有参数。
解决方法是在父类中写入:
def this() {
this("默认的名字")
println(“默认的名字“)
这样代码就可以了,再举一个案例分析执行流程:
写入:val emp3 = new Emp70o("smith")
分析执行的顺序:
仍然是先执行 Person700()这段代码,虽然写的是构造器,但是找到 def this(name : String)辅助构造器时又会调用主构造器。
调用主构造器时会发现它是继承了 person,于是就会找这个 person 对应的构造器:
this("默认的名字")
println(“默认的名字“)
找的这里的时候知道这个地方也调用了父类的主构造器,于是会执行 person,person 执行完成后再去执行“默认的名字“,完成后执行自己的构造器:emp…,最后才执行 Emp 辅助构造器~。
因此,执行的顺序为:
(1)person…
(2)默认的名字
(3)emp…
(4)emp 辅助构造器
2、只有主构造器可以调用父类的构造器。
辅助构造器不能直接调用父类的构造器。
在 Scala 构造器中,不能调用 super(params)【案例演示+反编译】
也就是子类调用父类只能找一个,原先 java 可以选,在这里只有主构造器可以调用父类的构造器。
class Person(name: String){
//父类的构造器
}
class Emp (name: String) extends Person(name){
//将子类参数传递给父类构造器,这种写法是可以的
// super(name)(×)没有这种语法
def this(){
super("abc")
//(×)不能在辅助构造器中调用父类的构造器
}
这里有一个 person 是个父类,class Emp (name: String) extends Person(name)这里可以把子类构造的参数传给name,通过主构造器可以传给父类构造器,这个构造器可以选择。
比如:
class Emp700
()
extends Person700
()
{
//子类 emp 继承 person
println(
“
Emp ....")
def this(name : String){
//辅助构造器
thi
s
//必须调用主构造器
this.name = name
println( Emp 辅助构造器~)
}
}
在class Emp700() extends Person700()下调用 super 的构造器:super(),会直接报错。
辅助构造器也是不能调用的,它的出口只能从 extends Person700()开始,不能选择。
将参数传进去也是可以的,比如以第1部分代码为例:
给 pname 进行构造:
class Emp700
(ename:string)
extends Person700
(ename)
这样写的话在上方调用的时候emp会报错,是因为这时有两个相同的构造器了,所以为了以示区别,将代码改为:
class Emp700
(ename:string,eage:Int)
extends Person700
(ename)
这时用父类传参数是可以选择的,然后重新构建测试:
val emp4 = new Emp70o("terry",10
)
(1)这时直接运行到主构造器后调用 person(ename)之后运行到父类 person,这时就会先输出 person,输出person 后父类就完成了,name 已经是“terry“。
(2)运行自己的主构造器,输出 println(“emp…“)这时和辅助构造器是没有关系的。
最后输出一下:
def showInfo(): unit = {
println(“雇员的名字", name)
接着调用一下:
E
mp
.4showInfo( )
//这地方输出是雇员的名字为 terry
运行会出错,因为调用自己主构造器,主构造器已经有参数了,所以语法不通,所以为了语法通顺,修改为:
class Emp700
()
extends Person700
()
{
//子类 emp 继承 person
println(
“
Emp ....")
def this(name : String){
//辅助构造器
thi
s(name,1
00
)
//必须调用主构造器
this.name = name
println( Emp辅助构造器~)
}
}
执行:
Person...
Emp ....
(雇员的名字,terry)
Process finished with exit code o
没有问题。