我正在Scala中学习泛型,但我无法理解“正常”类层次结构和上界类型之间的区别。
看下面的示例:笼子可以收到Animal类,这意味着我可以通过Animal类或Dog类。上限参数同样有效。它们之间的实际区别是什么?什么时候应该使用其中一个?
class Animal
class Dog extends Animal
class Cage(animal: Animal)
val cage = new Cage(new Dog)
class AnotherCage[A <: Animal](animal: A)
val anotherCage = new AnotherCage(new Dog)
一个区别是参数的静态类型,animal
在前一种情况下,其类型为,Animal
而在后一种情况下,其类型为,Dog
因为类型参数A
被具体类型替代Dog
。要了解差异,请尝试添加一个这样的sound
方法Dog
class Animal
class Dog extends Animal {
def sound = "woof"
}
class Cage(val animal: Animal)
val cage = new Cage(new Dog)
class AnotherCage[A <: Animal](val animal: A)
val anotherCage = new AnotherCage(new Dog)
cage.animal.sound // error
anotherCage.animal.sound // ok
注意编译器怎么不知道sound
在第一种情况的方法尽管被引用的运行时类animal
的说法是Dog
。
参数化类型可以提供更强的类型安全性,并有助于避免使用进行类型转换asInstanceOf
。例如,假设我们有一个Dog
和一个Cat
class Animal
class Dog extends Animal
class Cat extends Animal
并且我们定义了一种仅打开包含Dog
s的笼子的方法
def openDogCage(cage: Cage): Dog =
if (cage.animal.isInstanceOf[Dog]) cage.animal.asInstanceOf[Dog]
else throw new IllegalArgumentException
def openAnotherDogCage(cage: AnotherCage[Dog]): Dog = cage.animal
但错误地为笼子提供了 Cat
val dog: Dog = openDogCage(new Cage(new Cat)) // runtime error
val dog: Dog = openAnotherDogCage(new AnotherCage(new Cat)) // compile-time error
然后注意在程序运行之前,参数化类型是如何在编译时捕获错误的。还要注意,在定义openDogCage
仅使用子类型时,我们必须手动执行类型转换,asInstanceOf
以使编译器确信该方法返回a Dog
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句