La linealización de Scala es un proceso determinista que entra en juego cuando se crea un objeto de una clase que se define utilizando la herencia de diferentes rasgos y clases. la linealización ayuda a resolver el problema del diamante que ocurre cuando una clase o rasgo hereda una misma propiedad de 2 clases o rasgos concretos diferentes.
Sintaxis:
trait C{} trait B{} class A{} object a_obj= new class A extends B with C
La linealización se verá así: –
C-> AnyRef-> Any B-> AnyRef-> Any A-> AnyRef-> Any a_obj-> A-> C-> B-> AnyRef-> Any
Aquí Any es la superclase de todas las clases, también llamada clase superior. Define ciertos métodos universales como equals, hashCode y toString. AnyRef representa clases de referencia. Todos los tipos sin valor se definen como tipos de referencia. AnyRef corresponde a java.lang.object. Cada característica y clase de Scala extiende implícitamente estos objetos de Scala al final de la jerarquía de linealización.
Ejemplos:
// 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) } }
Producción :
class c
La linealización para la clase D sigue a la flecha oscura en negrita. La herencia para la clase D sigue la flecha de luz.
Como podemos ver en el diagrama anterior, la linealización no será igual a la estructura heredada. Los rasgos/clases de Scala se colocan dinámicamente en orden lineal en el que se aplicará la linealización como se muestra a continuación.
D-> C-> B-> A-> AnyRef-> Any
Se siguen las siguientes reglas para determinar la linealización:
- Tome el primer rasgo/clase extendido y escriba su jerarquía heredada completa en forma vertical, almacene esta jerarquía como X.
- Tome el siguiente rasgo/clase después de la cláusula with , escriba su jerarquía completa y cancele las clases o rasgos que se repiten en la jerarquía X. Agregue los rasgos/clases restantes al frente de la jerarquía X.
- Vaya al paso 2 y repita el proceso, hasta que no quede ningún rasgo/clase.
- Coloque la clase en sí misma frente a la jerarquía como encabezado para el cual se está escribiendo la jerarquía.
Entendamos algunos ejemplos.
Ejemplo :
// 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) } }
Producción :
new car-> Designing-> Add new part-> Repainting-> old car
Ejemplo :
// 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 ")) } }
Producción :
chocolate with jelly texture () vanilla with jelly in cone with cream texture ()
Puntos importantes sobre la linealización
- Scala resuelve la ambigüedad de rasgos/clases mediante el proceso de linealización.
- Scala utiliza la linealización cada vez que se crea una nueva clase. Tomando todos los rasgos/clases y formando un orden lineal que apunta a las superclases/rasgos correspondientes, por lo tanto, el método super conoce su método principal.
- Estas llamadas a supermétodos se realizan de forma apilable.
- La linealización puede o no ser la misma que la de los mixins heredados tal como están escritos.
- No podemos agregar explícitamente una clase a la herencia cuando ya se heredó implícitamente en una linealización; de lo contrario, dará como resultado un error como herencia dos veces .
- Ningún rasgo/clase se repite nunca en la linealización.