Scala 中的特征线性化
Scala 线性化是一个确定性过程,当创建一个类的对象时发挥作用,该类对象是使用不同特征和类的继承定义的。线性化有助于解决当一个类或特征从 2 个不同的具体类或特征继承相同属性时出现的菱形问题。
句法 :
trait C{}
trait B{}
class A{}
object a_obj= new class A extends B with C
线性化将如下所示:-
C-> AnyRef-> Any
B-> AnyRef-> Any
A-> AnyRef-> Any
a_obj-> A-> C-> B-> AnyRef-> Any
这里Any是所有类的超类,也称为顶级类。它定义了某些通用方法,例如 equals、hashCode 和 toString。 AnyRef代表参考类。所有非值类型都定义为引用类型。 AnyRef 对应于Java.lang.object 。每个 Scala 特征和类都在线性化层次结构的末尾隐式扩展这些 Scala 对象。
例子 :
// Scala program defining trait A
trait A
{
def name: String
}
// defining trait B inheriting A
trait B extends A
{
override def name: String ="class b"
}
// defining trait C inheriting A
trait C extends A
{
override def name: String ="class c"
}
// defining class D inheriting B and C both
class D extends B with C
{
override def name: String = super.name
}
// Creating object
object GFG
{
// Main method
def main(args: Array[String])
{
var class_d = new D
// whose property will be inherited
println(class_d.name)
}
}
输出 :
class c
D 类的线性化遵循黑色粗体箭头。 D 类的继承遵循光箭头。
正如我们在上图中看到的那样,线性化与继承结构不同。 Scala 特征/类以线性顺序动态放置,线性化将如下应用。
D-> C-> B-> A-> AnyRef-> Any
确定线性化遵循以下规则:
- 取第一个扩展特征/类,并以垂直形式编写其完整的继承层次结构,将此层次结构存储为 X。
- 取with子句之后的下一个 trait/class,写下其完整的层次结构,并取消在层次结构 X 中重复的类或特征。将剩余的特征/类添加到层次结构 X 的前面。
- 转到第 2 步并重复该过程,直到没有特征/类被遗漏。
- 将类本身放在层次结构的前面,作为编写层次结构的头。
让我们理解一些例子。
例子 :
// Scala program for linearization
// defining old_car class
class old_Car
{
def method: String= "old car "
}
// defining new_Car_Designs trait
trait new_Car_Designs extends old_Car
{
override def method: String ="Designing-> "+ super.method
}
// defining new_Car_Part trait
trait new_Car_Part extends old_Car
{
override def method: String = "Add new part-> "+ super.method
}
// defining new_Car_Paint trait
trait new_Car_Paint extends old_Car
{
override def method: String = "Repainting-> "+ super.method
}
// defining new_Car class
class new_Car extends new_Car_Paint with
new_Car_Part with new_Car_Designs
{
override def method: String = "new car-> "+ super.method
}
// Creating object
object geekforgeeks
{
// Main method
def main(args: Array[String])
{
// new_Car object
var car1 = new new_Car
println(car1.method)
}
}
输出 :
new car-> Designing-> Add new part-> Repainting-> old car
例子 :
// Scala program for trait linearization
// defining classes and traits
class flavour
{
def make (flavour: String): Unit =
{
println(flavour)
}
}
// defining texture trait
trait texture extends flavour
{
abstract override def make (flavour : String)
{
super.make(flavour + "texture ")
}
}
// defining cream trait
trait cream extends texture
{
abstract override def make (flavour : String)
{
super.make(flavour + "with cream ")
}
}
// defining jelly trait
trait jelly extends texture
{
abstract override def make (flavour : String)
{
super.make(flavour + "with jelly ")
}
}
// defining cone trait
trait cone extends flavour
{
abstract override def make (flavour : String)
{
super.make(flavour + "in cone ")
}
}
// creating new ice-cream flovours
// with above traits and classes
// inheriting different traits and classes
class Myflavour extends flavour with jelly
{
override def make (flavour : String)
{
super.make(flavour)
}
}
class Myflavour2 extends flavour with cream with cone
{
override def make (flavour : String)
{
super.make(flavour)
}
}
// Creating object
object GFG
{
// Main method
def main(args: Array[String])
{
// creating new objects
var icecream1 = new Myflavour
var icecream2 = new Myflavour2 with jelly
println(icecream1.make("chocolate "))
println(icecream2.make("vanilla "))
}
}
输出 :
chocolate with jelly texture
()
vanilla with jelly in cone with cream texture
()
关于线性化的要点
- Scala 通过线性化过程解决了特征/类的歧义。
- 每当实例化一个新类时,Scala 都会使用线性化。获取所有特征/类并形成指向相应超类/特征的线性顺序,因此超方法知道其父方法。
- 这些超级方法调用是以可堆叠的方式完成的。
- 线性化可能与编写时继承的 mixin 相同,也可能不同。
- 当一个类已经在线性化中被隐式继承时,我们不能显式地将其添加到继承中,否则将导致两次继承错误。
- 线性化中不会重复任何特征/类。