Generic

The following is a generic type similar to java, with three classes Shape (shape), Rectangle (rectangle), and Square (square). Shape is the parent class of Rectangle, and Rectangle is the parent class of Square. So when we define a variable, we can declare it as a Shape type, and give it a specific type when new.
Draw1 has a generic type T. We can see that when defining variables, the type here cannot have a parent-child relationship.

object GenericDemo {
  def main(args: Array[String]): Unit = {
    val shape1: Shape = new Shape()
    var shape2: Shape = new Rectangle()
    var shape3: Shape = new Square()
    val draw1: Draw1[Shape] = new Draw1[Shape]()
    // val draw2: Draw1[Shape] = new Draw1[Rectangle]() // error
    // val draw3: Draw1[Shape] = new Draw1[Square]() // error
  }
}

class Shape {

}

class Rectangle extends Shape {

}

class Square extends Rectangle {

}

class Draw1[T]() {

}

Covariance and contravariance

The above cannot be compiled because Draw1[Shape] and new Draw1[Rectangle] have no parent-child relationship. Scala can make them have a parent-child relationship through covariance:
+ front of the generic T

class Draw2[+T]() {

}

Then it can be called in the main function:

val draw2: Draw2[Shape] = new Draw2[Rectangle]()
val draw3: Draw2[Shape] = new Draw2[Square]()

There is contravariance in scala, which is to reverse the parent-child relationship of Draw3[T]:
- front of the generic T

class Draw3[-T]() {

}

Then it can be called in the main function:

val draw4: Draw3[Rectangle] = new Draw3[Shape]()
val draw5: Draw3[Square] = new Draw3[Shape]()

Upper bound lower bound

The upper bound and the lower bound are the boundaries that define generics.
For example, Draw2 <: Shape2, and the parameters of Draw2 are the Shape2 class and subclasses. The printInfo method is a method of Shape2, so it can be called directly in printInfo. t.printInfo() method,
Draw3 uses >: Rectangle2 to define the lower bound of the generic type. The parameters of Draw3 are the Rectangle2 class and the parent class. At this time, he only has the Any method.

object GenericDemo2 {
  def main(args: Array[String]): Unit = {
    val draw1: Draw2[Shape2] = new Draw2(new Shape2())
    val draw2: Draw2[Shape2] = new Draw2(new Rectangle2())
    val draw3: Draw2[Shape2] = new Draw2(new Square2())
    draw1.printInfo() // 形状
    draw2.printInfo() // 长方形
    draw3.printInfo() // 正方形
    println("-------------")
    val draw4: Draw3[Shape2] = new Draw3(new Shape2())
    val draw5: Draw3[Rectangle2] = new Draw3(new Rectangle2())
    //val draw6: Draw3[Square2] = new Draw3(new Square2()) // error
    draw4.printInfo() // class com.scala.learn12.Shape2
    draw5.printInfo() // class com.scala.learn12.Rectangle2
    // draw3.printInfo()
  }
}

class Shape2 {
  def printInfo(): Unit = {
    println("形状")
  }
}

class Rectangle2 extends Shape2 {
  @Override
  override def printInfo(): Unit = {
    println("长方形")
  }
}

class Square2 extends Rectangle2 {
  @Override
  override def printInfo(): Unit = {
    println("正方形")
  }
}

class Draw2[T <: Shape2](t: T) {
  def printInfo(): Unit = {
    t.printInfo()
  }
}

class Draw3[T >: Rectangle2](t: T) {
  def printInfo(): Unit = {
    println(t.getClass())
  }
}

大军
847 声望183 粉丝

学而不思则罔,思而不学则殆


下一篇 »
Scala系列

引用和评论

0 条评论