2

我觉得这完全莫名其妙。出于某种原因,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.
    */
  }
}
4

1 回答 1

3

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

未从其超类或超接口继承的原始类型 C 的构造函数(第 8.8 节)、实例方法(第 8.4 节、第 9.4 节)或非静态字段(第 8.3 节)的类型是对应的原始类型在对应于 C 的泛型声明中擦除其类型。

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

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

--

这个问题/答案在 SO 中出现过几次,例如:

于 2013-05-15T23:56:30.687 回答