代码之家  ›  专栏  ›  技术社区  ›  rcreswick

Java方法分派如何处理泛型和抽象类?

  •  7
  • rcreswick  · 技术社区  · 17 年前

    今天我遇到了一种情况,Java没有调用我所期望的方法——这是一个最小的测试用例:(很抱歉,这似乎是人为的——‘真实世界’的场景要复杂得多,而且从“你到底为什么要这样做”这一句话中可以看出这一点

    我特别感兴趣的是为什么会发生这种情况,我不关心重新设计的建议。我有一种感觉,这是在Java拼图,但我没有我的副本手边。

    请参阅测试中的具体问题<T>。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
    
    3 回复  |  直到 17 年前
        1
  •  6
  •   Darron    17 年前

    否,值的类型在编译时不可用。请记住,javac只编译一个代码副本,用于所有可能的T。鉴于此,编译器在getValue()方法中唯一可能使用的类型是Object。

    C++是不同的,因为它最终将根据需要创建多个编译版本的代码。

        2
  •  2
  •   cletus    17 年前

    因为关于什么的决定 makeString() 使用是在编译时进行的,基于T可以是任何东西的事实,必须是 Object 版本想想看。如果是的话 Test<String> 对象 版本因此,所有 Test<T> 将使用 makeString(Object) .

    public abstract class Test<T extends Integer> {
      ...
    }
    

    事情可能会有所不同。

        3
  •  2
  •   Joshua Goldberg    14 年前

    乔希·布洛赫的 通用程序设计 超载 方法——这个问题的主题——在编译时确定;选择 方法是在运行时完成的(因此获得对象特定类型的知识)

    这本书比我的评论要清楚得多:见 “第41项:明智地使用重载”