未经检查实例化的泛型类

时间:2018-02-28 10:44:29

标签: java

我偶然发现了java编译器行为的违反直觉的例子(在this ru.so问题中)。鉴于javac 1.8.0_161及以下代码:

public class RuSo791351 {
    public static void main(String[] args) {
        List<Integer> payload = Arrays.asList(1, 2, 3);
        Consumer uncheckedConsumer = new Consumer();
        uncheckedConsumer.consume(payload);
        Consumer<?> wildcardConsumer = new Consumer<>();
        wildcardConsumer.consume(payload);
        Consumer<Integer> typedConsumer = new Consumer<>();
        typedConsumer.consume(payload);
    }

    private static class Consumer<T> {
        public <V> void consume(Collection<V> collection) {
            System.out.println("consume(Collection<T>) called");
        }

        public void consume(List<String> strings) {
            System.out.println("consume(List<String>) called");
        }
    }
}

编译器应该考虑将类型擦除考虑在内并采取简单的方法,每次都为consume(List<String>)调用发送字节码,或者采取艰难的方式并为consume(Collection<V>)发出字节码 - 再次,每一个时间。但是,编译器为uncheckedConsumer发出consume(List<String>),为其他情况发出consume(Collection<V>)

40: invokevirtual #7                  // Method me/etki/wtf/so/RuSo791351$Consumer.consume:(Ljava/util/List;)V
...
54: invokevirtual #8                  // Method me/etki/wtf/so/RuSo791351$Consumer.consume:(Ljava/util/Collection;)V
...
70: invokevirtual #8                  // Method me/etki/wtf/so/RuSo791351$Consumer.consume:(Ljava/util/Collection;)V

所以看来如果我根本没有为Consumer类指定<T>参数,编译器会忽略类中包含的所有通用信息 - 即使<V>是一个完全不同的方法参数 - 和编译器选择List over Collection作为更精确的类型。我几乎可以肯定这是对前通用时代代码的向后兼容性的影响,但在JLS中找不到任何特定的东西(说实话,我似乎甚至不知道如何向谷歌询问这个问题)。有人能指出我这种行为的规范吗?

0 个答案:

没有答案