[英]Difference of Upper Bounded Type and normal class behavior
I am studying Generics in Scala and I can't understand the difference between a "normal" class hierarchy and the Upper Bound type.我正在研究 Scala 中的 Generics ,我无法理解“正常” class 层次结构和上界类型之间的区别。
Looking at the example below: Cage can receive the class Animal, which means that I can pass either the class Animal or the class Dog.看下面的例子:Cage 可以接收 class Animal,这意味着我可以通过 class Animal 或 class Dog。 The same is valid for the upper bound parameter.上限参数也是如此。 What is the practical difference between them?它们之间的实际区别是什么? When should I use one or the other?我什么时候应该使用其中一种?
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)
One difference is in the static type of animal
parameter where in the former case it is typed as Animal
whilst in latter case it is typed as Dog
because the type parameter A
is substituted with concrete type Dog
.一个区别在于static类型的animal
参数,在前一种情况下,它被键入为Animal
,而在后一种情况下,它被键入为Dog
,因为类型参数A
被替换为具体类型Dog
。 To see the difference try adding a sound
method to Dog
like so要查看差异,请尝试像这样向Dog
添加sound
方法
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
Note how compiler is not aware of sound
method in the first case despite the fact that the runtime class referenced by animal
argument is Dog
.请注意,尽管animal
参数引用的运行时 class 是Dog
,但编译器在第一种情况下如何不知道sound
方法。
Parameterized types can provide stronger type-safety and help avoid the need for type casting with asInstanceOf
.参数化类型可以提供更强的类型安全性,并有助于避免使用asInstanceOf
进行类型转换。 For example, let's say we have a Dog
and a Cat
例如,假设我们有一只Dog
和一只Cat
class Animal
class Dog extends Animal
class Cat extends Animal
and we define a method that opens only cages containing Dog
s我们定义了一个只打开包含Dog
的笼子的方法
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
but erroneously provide a cage with a Cat
但错误地提供了一个有Cat
的笼子
val dog: Dog = openDogCage(new Cage(new Cat)) // runtime error
val dog: Dog = openAnotherDogCage(new AnotherCage(new Cat)) // compile-time error
then notice how parameterzied types caught the error at compile-time before the program even ran.然后注意参数化类型是如何在程序运行之前在编译时捕获错误的。 Also notice how in definition of openDogCage
when using just subtyping we had to manually perform a type cast with asInstanceOf
to convince the compiler that method returns a Dog
.还要注意在openDogCage
的定义中,当仅使用子类型时,我们必须手动使用asInstanceOf
执行类型转换,以使编译器相信该方法返回Dog
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.