Java泛型.为什么编译?

Gro*_*xel 13 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
}
Run Code Online (Sandbox Code Playgroud)

该方法一般K型阴影类通用型K,所以<K>不匹配<K extends Number>use1().The编译器不知道什么有用的关于新的通用型<K>use2()use3(),但它仍然是合法的编译.为什么<? extends K>(或<? super K>)匹配<K extends Number>

Pet*_*rey 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
}
Run Code Online (Sandbox Code Playgroud)

在某些情况下,您必须提供编译器可以推断的重复信息,以及其他您不能提供的信息.在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);
    }
Run Code Online (Sandbox Code Playgroud)

  • @Fred原始问题也未使用类声明中定义的K. (2认同)
  • @Peter:我看不到哪里.在OP的代码中,use1没有编译,因为它的K没有扩展Number.在你的代码中,你通过添加`èxtendsNumber`来修复它.然而问题不是为什么use1没有编译,而是为什么use2和use3做编译,即使他们的Ks也没有扩展Number.即为什么是'Type <?当K`没有扩展数字时,即使`类型<K>`不是?我没有看到你的答案在哪里解决. (2认同)

mat*_*att 5

当您定义这样的方法时:

abstract <K> void use1(Type<K> k);
Run Code Online (Sandbox Code Playgroud)

您实际上是K在类定义中隐藏类型.您应该能够定义这样的方法:

abstract void use1(Type<K> k);
Run Code Online (Sandbox Code Playgroud)


axt*_*avt 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);   
}
Run Code Online (Sandbox Code Playgroud)

在第一个方法中K充当 的类型参数Type<N extends Number>,因此其值应符合 的Type界限N。然而,方法声明对 的值没有任何限制K,因此它是不合法的。如果您添加必要的限制,则是合法的K

abstract <K extends Number> void use1(Type<K> k);
Run Code Online (Sandbox Code Playgroud)

在下面的方法中, 的实际类型参数Type是未知的(?),并且K对其施加了额外的限制,因此这些声明中没有任何非法内容。

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

class MyList<N extends Number> extends ArrayList<N> {}

<K> void add1(MyList<K> a, K b) {
     a.add(b); // Given the method declaration, this line is legal, but it 
          // violates type safety, since object of an arbitrary type K can be
          // added to a list that expects Numbers
          // Thus, declaration of this method is illegal
}

<K> void add2(MyList<? extends K> a, K b) {
     // a.add(b) would be illegal inside this method, so that there is no way
     // to violate type safety here, therefore declaration of this method is legal
}

<K> void add3(MyLisy<? super K> a, K b) {
     a.add(b); // This line is legal, but it cannot violate type safey, since
          // you cannot pass a list that doesn't expect K into this method
}
Run Code Online (Sandbox Code Playgroud)