考虑:
public class Types { @Override public boolean equals(Object obj){ System.out.println("in class Types equals()"); return false;//Shut-up compiler! } public static void main(String[] args){ Object typ = new Types(); typ.equals("Hi");//can do this as String is a subclass of Object } }
第一:参考变量typ是类型类型,不是吗?!
那么,为了方法覆盖,打包有静态类型对象和动态类型类型的原因是什么?
第二:编译器是否有足够的信息来调用正确的equals()?
如果类类型没有重写的equals(),那么它可以调用Object.equals()方法.
在这种情况下类类具有,并且编译器知道它.
为什么这不能像重载一样早期绑定?为什么要把它留给JVM?
解决方法
它引用的对象是类型类型.
编译器没有足够的信息来知道该对象实际上是Types并使用Type.equals(Object).
这可能令人困惑.如果你写
Object typ = new Types();
然后肯定编译器知道typ中有什么是类型.它只是将这些信息编译成代码!
但是,如果您决定将该行更改为,该怎么办?
Object type = new ObjectFactory().choose(choice).use(decision).build();
好吧,现在你实际上并不知道构建的内容.在ObjectFactory决定如何处理选择和决策的值之后,这将仅在运行时才知道.
所以在这种情况下,编译器不知道.唯一可用的信息是变量的静态类型.如果编译器在使用new时的行为与使用上述工厂时的行为不同,那将是非常糟糕的.
现在看看这个场景:
public class Types { public boolean equals( Object obj ) { // something } public boolean equals( String str ) { return false; } } public class Main { public static void main(String[] args) { Object typ = new Types(); System.out.println( typ.equals("foo" ) ); } }
现在,在这种情况下,Types和Main是两个独立的编译单元(不同的文件等).假设编译器决定根据typ是Types的事实.然后它将使用Types.equals(String).
但现在您可以编辑类型,删除equals(String),并仅重新编译类型.当你运行程序时,你会得到一个“没有这样的方法异常”,因为编译器假定Types有一个equals(String)方法.所以你的程序失败了,尽管它是一个完全合法的Java程序,尽管在新类型中有一个正确的匹配方法equals(Object).
因此,真正的编译器使用静态类型来确定方法是否存在并且对于给定的静态参数是合法的,并且仅在运行时,JVM将能够找到实际类型的内容,并调用该方法的适用覆盖.