在Java这样的静态类型语言中,从我所学到的,类型声明主要用于编译时捕获错误,这是一种明显优于动态类型语言的优势.但是看看Java进行后期绑定的时候,我们会得到错误ClassCastException
,在运行时以某种方式显示声明的类型是如何相关的.但为什么声明的类型实际上很重要?
例如:
public class TestClass { public static void main(String[] args) { Animal d = new Animal(); ((Dog)d).bark(); //ClassCastException because an Animal is not a dog, which would make sense to throw at compile-time, but not at runtime. } } class Dog extends Animal{} class Animal { void bark() { System.out.println("Woof"); } }
我知道这是一个非常糟糕的例子,因为它是一个无人问津的演员,但我只是举了一个例子.我们总是试图避免运行时异常,那么为什么Java不能忽略bark
实际对象类型的强制转换和调用方法,在这种情况下是Animal
什么?我一直在阅读有关鸭子打字的内容,看起来这种类似的改编可能适用于Java(即如果这个对象是woofs,那么让它像狗一样对待!)或任何静态类型的语言,因为在运行时,Java似乎动态行动.
编辑:现在我正在考虑更多,这个问题是关于运行时类型检查的需要.为什么需要发生?静态类型语言在可以忽略的转换上暂停运行时异常似乎很糟糕.
为什么Java不能忽视对实际对象类型的强制转换和调用方法,在这种情况下是动物?
这在语义上是错误的.如果Dog
和Amimal
有不同的版本的Bark
方法是什么?
假设Bark
您的基类中有非虚方法.当你调用Bark
上Dog
它应该调用Dog.Bark
; 同样,当你调用Bark
上Animal
它应该调用Animal.Bark
.
如果编译器忽视了你所说的强制转换,它最终会调用错误的方法.
请注意,在C#中,默认情况下,所有方法都是非虚拟的,而不是java.所以这个论点在C#的上下文中更有意义.