【问题标题】:Compilation differences between unspecified generic and <?> in java [duplicate]java中未指定的泛型和<?>之间的编译差异[重复]
【发布时间】:2013-05-16 08:03:57
【问题描述】:

我觉得这完全令人费解。出于某种原因,javac 似乎在类型安全方面以不同的方式处理具有未指定泛型和&lt;?&gt; 的引用。有谁知道这是为什么(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.
    */
  }
}

【问题讨论】:

  • 这完全是应该的。原始类型(没有泛型)消除了泛型将提供的 all 类型安全性,而 ? 表示可以推理的固定但未知的泛型类型。
  • 但是调用并没有以任何方式使用类的泛型成员类型。编译器错误是针对泛型方法的,它是处理程序指定的不同泛型。

标签: java generics


【解决方案1】:

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

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

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

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

--

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-17
    • 1970-01-01
    • 2020-10-16
    相关资源
    最近更新 更多