【问题标题】:Java: Raw anonymous class loses generic types in its methodsJava:原始匿名类在其方法中丢失了泛型类型
【发布时间】:2021-09-28 22:18:17
【问题描述】:

Java 编译器的这种行为让我有点不知所措。有人可以解释为什么会这样吗?考虑这个例子:

public static abstract class GenericClass<A extends GenericClass<A>> {
  protected abstract void method();
  protected <B> B getB(Class<B> bclass) {
    return null;
  }
}
// ...
GenericClass<?> gc = new GenericClass() {
  @Override
  protected void method() {
    String s = getB(String.class); // does not compile
  }
};
String s = gc.getB(String.class);  // compiles

由于new 中没有给出泛型参数,匿名类继承自原始类型GenericClass。即使方法getB 没有提及A,通用信息仍然丢失并且方法调用无法编译。为什么会这样?

此外,我无法为new 指定泛型参数的原因是因为它应该是匿名类本身,但我无法命名匿名类来传递它。我该如何正确地做到这一点?

【问题讨论】:

    标签: java generics anonymous-class raw-types


    【解决方案1】:

    存在原始类型是为了与泛型存在之前的代码兼容。它们被视为对所有通用事物的完全“退出”。如果您想要泛型,请不要使用原始类型。这就是语言设计的意图。

    这里的解决方案是给类命名。是的,类可以出现在方法和其他语句块中;这样的东西被称为本地类。匿名类基本上是一个没有名字的本地类——本地类可以做任何匿名类可以做的事情。

    String thisIsFine() {
        var cell = new Object() { String s; }; // example local variable to show local classes can access them
        class GenericImpl extends GenericClass<GenericImpl> {
           @Override
           protected void method() {
               cell.s = getB(String.class);
           }
        }
        new GenericImpl().method();
        return cell.s;
    }
    

    【讨论】:

    • 本地课程可以解决问题,谢谢。虽然我不拥有实现 GenericClass 的代码,但我可以推荐这个解决方案。同时我仍然不太明白为什么原始类型会关闭 all 泛型,即使是那些不直接参与类类型定义的泛型。
    • @NebehrGudahtt 因为您通常不会在方法调用中指定泛型。预泛型代码可能包含GenericClass g = ...; g.getB(...) 之类的内容,并且在调用getB 时不会检查泛型。在泛型之后,调用g.getB 的语法不会改变,因为我们通常会保留推断的方法泛型。所以大多数时候语法不会向编译器发出信号,无论我们想要方法的原始类型还是泛型类型。因此,为了兼容性,调用的原始性必须选择与接收者的原始性相同。
    • 但是为什么同样的调用在类方法之外起作用?
    • @NebehrGudahtt 因为接收者的类型不同。 GenericClass 是原始类型,为了兼容性,all 上的 all 泛型必须删除,但 GenericClass&lt;?&gt; 是普通泛型类型,具有“正确”类型为一切。
    猜你喜欢
    • 2019-05-26
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    相关资源
    最近更新 更多