我今天碰见的情况下的Java并没有调用我期望的方法 - 这是最小的测试用例:(对不起,这似乎做作 - 在“现实世界”的场景基本上是比较复杂的,和品牌从更多意义上的 “究竟为什么会怎么做的的?” 的立场。)

我在为什么出现这种情况特别感兴趣,我不在乎重新设计的建议。我有一种感觉,这是在Java中谜题,但我没有我的副本方便。

请参阅下面内测试 .getValue()中赞扬具体的问题:

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:使用超载明智”

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top