如何Java方法分派工作,泛型和抽象类?
-
19-08-2019 - |
题
我今天碰见的情况下的Java并没有调用我期望的方法 - 这是最小的测试用例:(对不起,这似乎做作 - 在“现实世界”的场景基本上是比较复杂的,和品牌从更多意义上的 “究竟为什么会怎么做的是的?” 的立场。)
我在为什么出现这种情况特别感兴趣,我不在乎重新设计的建议。我有一种感觉,这是在Java中谜题,但我没有我的副本方便。
请参阅下面内测试
public class Ol2 {
public static void main(String[] args) {
Test<Integer> t = new Test<Integer>() {
protected Integer value() { return 5; }
};
System.out.println(t.getValue());
}
}
abstract class Test<T> {
protected abstract T value();
public String getValue() {
// Why does this always invoke makeString(Object)?
// The type of value() is available at compile-time.
return Util.makeString(value());
}
}
class Util {
public static String makeString(Integer i){
return "int: "+i;
}
public static String makeString(Object o){
return "obj: "+o;
}
}
从该代码的输出是:
obj: 5
解决方案
没有,的值的类型,不提供在编译时。请记住,javac的只会编译用于所有可能的T的代码的一个副本。鉴于此,唯一可能的类型的编译器在使用的getValue()方法是对象。
C ++是不同的,因为在需要它最终将创建代码的多个编译版本。
其他提示
由于什么makeString()
使用的决定是在编译时提出,并基于这样的事实是t可以是任何东西,必须是Object
版本。想想吧。如果你没有Test<String>
它会调用Object
版本。作为这种Test<T>
的所有实例将使用makeString(Object)
。
现在,如果你不喜欢的东西:
public abstract class Test<T extends Integer> {
...
}
的东西可能会不同。
乔希布洛赫的有效的Java 具有优异的讨论澄清的出现是因为调度的工作方式不同重载VS重写(在子类)的方法的混乱。中选择的过载方法---这个问题的主题---在编译时被确定;中选择的覆盖方法在运行时进行(并且因此得到特定类型的对象的知识。)
这本书比我的评论更清楚:见 “项目41:使用超载明智”
不隶属于 StackOverflow