scala面向对象基础---类继承和特质
作者:互联网
一、类继承
传送门:Scala基础—类继承
- Scala的类继承
- 调用超类的构造方法
- 重写超类的成员
3.1.不被继承的成员
3.2.不可重写的成员
3.3.无参方法与字段- 子类型多态与动态绑定
- 抽象类
- 关于多重继承
- Scala类的层次结构
二、特质介绍
因为Scala没有多重继承,为了提高代码复用率提出了特质的概念,在定义上它主要有以下几个特点(结合单例对象):
- 特质用关键字
“trait”
为开头来定义的,它与单例对象很像,两者都不能有入参。但是,单例对象天生就是具体的,特质天生就是抽象的,不过不需要用“abstract”
来说明。 - 因为特质是抽象的,所以可以包含抽象成员(成员可以全是抽象,或者全是具体,或者有抽象也有具体),而单例对象却不行。
- 两者都不能用new来实例化,因为特质是抽象的,而单例对象已经是具体的对象。
- 类、单例对象和特质三者一样,内部可以包含字段和方法,甚至包含其他类、单例对象、特质的定义。
在混入特质时它有以下几个特点:
-
特质可以被其它类、单例对象和特质**“混入”**。这里使用术语“混入”而不是“继承”,是因为特质在超类方法调用上采用 线性化机制 ,与多重继承有很大的区别。其它方面,“混入”和“继承”其实是一样的。例如,某个类混入一个特质后,就包含了特质的所有公有成员,而且也可以用“override”来重写特质的成员。
-
Scala只允许继承自一个类,但是对特质的混入数量却没有限制,故而可用于替代多重继承语法。而且对于类的继承必须写在最前面,不能先混入特质,然后再继承类。
-
要混入一个特质,可以使用关键字
“extends”
。但如果“extends”
已经被占用了,比如已经拿去继承一个类或混入一个特质,那么后续则通过关键字“with”
来混入其他特质。也即混入特质既可以使用“extends”
,也可以使用with
。 -
extends
只能使用一次,且是用在最前面,但是with
可以使用多次。
class MyClass{
val c = "Alex"
val print = () => println(c)
}
trait A {
val absA : String
private val a = "Trait A"
}
trait B {
val b = "Trait B"
}
class sub extends MyClass with A with B{
val absA = "absA"//抽象成员加不加override都可以重写
override val a = "wzx"//出错,私有成员访问不到
val myprint = () => println(b,c)
}
再看一下几种错误的写法!!!
三、特质的层次
- 前面已经说过,不止
class、object
,trait
也可以继承自其他class
,或混入任意个trait
,这样该特质就是关键字“extends”引入的那个类/特质的子特质,注意只有使用extends
才能成为子特质,也即with
一个特质不能称为该特质的子特质。 - 如果没有继承和混入,那么这个
trait
就是AnyRef
类的子特质。当某个class、object或trait
混入一个trait
时,会隐式继承自这个trait
的超类。 - 也就是说,类/单例对象/特质的超类,都是由“extends”引入的类或混入的特质决定的。具体理解一下就是:
extends
引入类,那么这个类就是超类,这是肯定的;如果混入特质,并且特质使用extends
继承了一个类, 那么这个类会自动成为所有混入该特质的超类。
不过混入特质时有一个限制条件:那就是要混入该特质的类/单例对象/特质,它的超类必须是待混入特质的超类,或者是待混入特质的超类的子类。因为特质是多重继承的替代品,那就有“继承”的意思。既然是继承,混入特质的类/单例对象/特质的层次,就必须比待混入特质的层次要低。例如:
scala> class A
defined class A
scala> class B extends A
defined class B
scala> class C
defined class C
scala> trait D extends A
defined trait D
scala> trait E extends B
defined trait E
scala> class Test1 extends D
defined class Test1
scala> class Test2 extends A with D
defined class Test2
scala> class Test3 extends B with D
defined class Test3
scala> class Test4 extends C with D
<console>:13: error: illegal inheritance; superclass C
is not a subclass of the superclass A
of the mixin trait D
class Test4 extends C with D
^
scala> class Test5 extends A with E
<console>:13: error: illegal inheritance; superclass A
is not a subclass of the superclass B
of the mixin trait E
class Test5 extends A with E
- 类Test1直接混入特质D,这样隐式继承自D的超类——类A,所以合法。
- 类Test2继承自类A,A是D的超类,所以也允许混入特质D。
- 类Test3继承类A的子类B,A是D的超类,所以也允许混入特质D。
- 类Test4的超类是C,而C与A没有任何关系,所以非法。
- 类Test5的超类是A,特质E的超类是B,首先A不是E的超类B的子类;其次,虽然E的超类是B,B的超类是A,但是仍然没有符合A是E的超类这个条件。因为Scala没有多继承,所以你可以理解为超类的超类不能成为超类。
四、混入特质的简便方法
如果想快速构造一个混入某些特质的实例,可以使用如下语法:
new Trait1 with Trait2 ... { definition }
这其实是定义了一个匿名类,这个匿名类混入了这些特质,并且花括号内是该匿名类的定义。然后使用new构造了这个匿名类的一个对象,其等效的代码就是:
class AnonymousClass extends Trait1 with Trait2 ... { definition }
new AnonymousClass
除此之外,还可以在最前面加上一个想要继承的超类:
new SuperClass with Trait1 with Trait2 ... { definition }
四、子类型
一个类或者单例对象,如果混入了一个特质(extends和with
都行),那么它们就是该特质的子类型。凡是需要特质的地方,都可以由该特质的子类型来替换。
import scala.collection.mutable.ArrayBuffer
trait Pet {
val name: String
}
class animal
object Dog extends Pet {
val name: String = "Harry"
}
class Cat(val name: String) extends animal with Pet
val cat = new Cat("Sally")
val animals = ArrayBuffer.empty[Pet]
animals.append(Dog)
animals.append(cat)
animals.foreach(pet => println(pet.name)) // Prints Harry Sally
标签:特质,混入,scala,trait,---,面向对象,extends,超类,class 来源: https://blog.csdn.net/qq_39507748/article/details/119144579