【问题标题】:How to use sealed classes with generics?如何使用带有泛型的密封类?
【发布时间】:2021-10-08 06:06:19
【问题描述】:

我有一个父抽象类和采用泛型的子类。

public abstract sealed class Parent<T> permits ChildA, ChildB {}

public non-sealed class ChildA<T extends FileTypeA> extends Parent{}

public non-sealed class ChildB<T extends FileTypeB> extends Parent{}

在父类中,我收到警告:

ChildA is a raw type. References to generic type ChildA<T> 
       should be parameterized

ChildB is a raw type. References to generic type ChildB<T> 
       should be parameterized

在子类中,我收到警告:

Parent is a raw type. References to generic type Parent<T> 
       should be parameterized

让它们像这样参数化:

public abstract sealed class Parent<T> 
    permits ChildA<T extends FileTypeA>, ChildB<T extends FileTypeB> {}

甚至

public abstract sealed class Parent<T> 
    permits ChildA<T>, ChildB<T> {}

给出错误:

Bound mismatch: The type T is not a valid substitute for the 
    bounded parameter <T extends FileTypeA> of the type ChildA<T>

如何消除这些警告和错误?

【问题讨论】:

  • 假设您了解不应使用原始类型(第一次警告的原因),您需要确定的第一件事是extends Parent&lt;...&gt; 中的正确类型参数,并在此过程中回答质疑为什么Parent 是通用的。这与密封类无关。解决了这个问题后,您可以尝试回答有关在permits ChildA&lt;...&gt; 中设置什么类型参数的密封类问题。这是一个很好的问题,但我没有看到比... permits ChildA&lt;?&gt;, ChildB&lt;?&gt; 更有意义的东西。在 JLS 中找不到任何内容。
  • @ernest_k 我从语法中推断出意图。因为它首先不允许在 permits 之后使用参数化类型,所以 JLS 作者可能觉得没有必要讨论原始类型与参数化类型。
  • Eclipse 错误报告是here

标签: java eclipse java-17 java-sealed-type


【解决方案1】:

警告“Parent is a raw type”与密封类完全无关,因为当 Parent&lt;T&gt; 是泛型类时使用 extends Parent 会导致这样的警告,因为泛型存在。 p>

你很可能想要使用

public non-sealed class ChildA<T extends FileTypeA> extends Parent<T> {}

public non-sealed class ChildB<T extends FileTypeB> extends Parent<T> {}

另一个问题似乎是 Eclipse 错误,因为我只能在那里重现警告。当我将声明更改为 permits ChildA&lt;?&gt;, ChildB&lt;?&gt; 时,警告会消失,但您应该不要这样做。

Java Language Specificationpermits 子句定义为

ClassPermits:
    permits TypeName {, TypeName}

TypeName is linked to

TypeName:
    TypeIdentifier
    PackageOrTypeName . TypeIdentifier

PackageOrTypeName:
    Identifier
    PackageOrTypeName . Identifier

这显然会导致一系列点分隔标识符没有任何类型参数。始终如一地,javac 拒绝像 permits ChildA&lt;?&gt;, ChildB&lt;?&gt; 这样的构造。

换句话说,Eclipse 不应在此处生成警告,更重要的是,不应在 permit 子句中接受参数化类型。您最好的选择是等待 Eclipse 的 Java 17 支持修复。您可以在整个 Parent 类中添加 @SuppressWarnings("rawtypes") 以使警告消失,但由于这会影响整个类,我不建议这样做。

【讨论】:

  • 我建议permits ChildA&lt;?&gt;, ChildB&lt;?&gt; 的评论也是基于在 Eclipse 中完成的测试; javac 拒绝它。对于使用泛型类型的一般“最佳实践”,我只是不喜欢这个额外的例外。好答案,+1。
  • @ernest_k 不将此处的类型视为原始类型,但在必要时始终隐含 &lt;?&gt;List::add 形式的类似方法引用不是原始的,而是从上下文中推断出必要的类型。我认为,Java 应该有更多的地方应该暗示 &lt;?[,?]*&gt; 而不是退回到原始类型,例如o instanceof List l 的行为应该与 o instanceof List&lt;?&gt; l 相同,因为此构造不需要向后兼容预泛型代码。
  • 很公平...除了permits ChildA&lt;?&gt; 会导致错误而不是警告。但感谢您的洞察力。
  • @ernest_k 对,正如答案中所说,这是已经被语法排除的结果。对我来说,这是一件好事。由于这里ChildAChildA&lt;?&gt; 之间没有语义上的区别,因此只有一种有效的形式,更简单的一种,不再讨论前者还是后者,没有浪费时间教代码格式化程序转换一个形成另一个,以匹配偏好等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
相关资源
最近更新 更多