java中未指定泛型和<! - ? - >之间的编译差异

时间:2013-05-15 23:16:27

标签: java generics

我觉得这完全莫名其妙。出于某种原因,javac似乎用未指定的泛型来处理引用,并且在类型安全方面不同<?>。有没有人知道为什么会这样(Java 1.6)?

public abstract class ClassWithGenericMember<GenMember> {

  GenMember getMember() {
    return (GenMember) null;
  }

  <GenReturn> GenReturn handle(Handler<GenReturn> handler) {
    return handler.handle();
  }

  interface Handler<GenHandled> {
    public GenHandled handle();
  }

  static class ClassWithMember extends ClassWithGenericMember<MemberType> {
  }

  static class MemberType {
  }

  static class HandledType {
  }

  public static void main(String[] argv) {
    HandledType handled = null;
    Handler<HandledType> handler = new Handler<HandledType>(){
      public HandledType handle() {
        return (HandledType) null;
      }
    };

    ClassWithMember concrete = new ClassWithMember();
    ClassWithGenericMember<?> bracket = concrete;
    ClassWithGenericMember noBracket = concrete;

    handled = concrete.handle(handler); //compiles
    handled = bracket.handle(handler); //compiles
    handled = noBracket.handle(handler); //fails:
    /*
ClassWithGenericMember.java:38: incompatible types
found   : java.lang.Object
required: ClassWithGenericMember.HandledType
    handled = noBracket.handle(handler);
                              ^
Note: ClassWithGenericMember.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
    */
  }
}

1 个答案:

答案 0 :(得分:2)

看起来很奇怪,当你使用原始类型时,所有泛型类型(所有它们,而不仅仅是类的参数化类型)都会从类中的声明中删除(JLS 4.8):

  

构造函数的类型(第8.8节),实例方法(第8.4节,第9.4节),或者   非静态字段(第8.3节)未从中继承的原始类型C的M.   它的超类或超接口是对应的原始类型   在相应的通用声明中擦除其类型   下进行。

当您使用ClassWithGenericMember noBracket(“原始类型C”)时,noBracket.handle()的类型是“与其类型的擦除相对应的原始类型”,即Object handle(HandlerType handler)。 (正如你在评论中所说的那样)“调用不以任何方式使用类的通用成员类型”并不重要。

请注意,这仅适用于直接在类中声明的构造函数,实例方法和非静态字段的类型(例如,不是类方法,静态字段,继承方法),并且不影响实现的声明(例如,方法中的声明)。

-

这个问题/答案在SO中出现了几次: