Java泛型。为什么编译?

时间:2011-09-26 13:14:22

标签: java generics

abstract class Type<K extends Number> {
    abstract <K> void use1(Type<K> k);           // Compiler error (Type parameter K is not within its bounds)
    abstract <K> void use2(Type<? extends K> k); // fine
    abstract <K> void use3(Type<? super K> k);   // fine
}

方法泛型类型K隐藏类泛型类型K,因此<K><K extends Number>中的use1()不匹配。编译器对新的泛型类型{<K>不知道任何有用的内容{在use2()use3()中{1}},但编译仍然合法。为什么<? extends K>(或<? super K>)匹配<K extends Number>

4 个答案:

答案 0 :(得分:9)

您遇到的问题是有两种K类型。如果重命名,可能会更清楚。

abstract class Type<N extends Number> {
    abstract <K extends Number> void use1(Type<K> k); // fine
    abstract <K> void use2(Type<? extends K> k); // fine
    abstract <K> void use3(Type<? super K> k);   // fine
}

在某些情况下,您必须提供编译器可以推断的重复信息,以及其他您不能提供的信息。在Java 7中,它添加了一个<>菱形符号,告诉编译器推断它以前没有的类型。


说明我的意思。以下是创建泛型类实例的不同方法。有些要求给出两次类型,其他只需要一次。编译器可以推断出类型。

通常,Java在大多数其他语言中都不会推断类型。

class Type<N extends Number> {
    private final Class<N> nClass;

    Type(Class<N> nClass) {
        this.nClass = nClass;
    }

    static <N extends Number> Type<N> create(Class<N> nClass) {
        return new Type<N>(nClass);
    }

    static void main(String... args) {
      // N type is required.
      Type<Integer> t1 = new Type<Integer>(Integer.class);

      // N type inferred in Java 7.
      Type<Integer> t2 = new Type<>(Integer.class); 

      // type is optional
      Type<Integer> t3 = Type.<Integer>create(Integer.class); 

      // type is inferred
      Type<Integer> t4 = create(Integer.class);
    }

答案 1 :(得分:5)

当你定义这样的方法时:

abstract <K> void use1(Type<K> k);

您实际上在类定义中隐藏了类型K。您应该能够定义如下方法:

abstract void use1(Type<K> k);

答案 2 :(得分:4)

首先,让我们重写它以避免阴影:

abstract class Type<N extends Number> {
    abstract <K> void use1(Type<K> k); 
    abstract <K> void use2(Type<? extends K> k); 
    abstract <K> void use3(Type<? super K> k);   
}

在第一种方法中,K充当Type<N extends Number>的类型参数,因此其值应符合Type的{​​{1}}的范围。但是,方法声明对N的值没有任何限制,因此它不合法。如果您在K上添加必要的限制,那将是合法的:

K

在以下方法中,abstract <K extends Number> void use1(Type<K> k); 的实际类型参数未知(Type),?对其施加了额外的限制,因此这些声明中没有任何违法行为。

这是一个更实际的例子,具有类似的声明:

K

答案 3 :(得分:0)

这是一个灰色区域; javac 7和6不同意; JLS3已经过时了;不知道新规格在哪里。