【问题标题】:Why can't I recur in a java java.lang.Enum generic type definition?为什么我不能在 java java.lang.Enum 泛型类型定义中重复出现?
【发布时间】:2021-03-28 10:04:42
【问题描述】:

这是一个学术问题,旨在更好地理解泛型在这种情况下的行为。

Enum 类型被描述为“所有 Java 语言枚举类型的公共基类”。它的定义是:

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

} 

现在,我可以用这个定义定义一个字段:

public class MyClass { 
   public Enum<MyEnum> field;
}

一切都好。现在,更进一步。因为Enum&lt;MyEnum&gt; 显然等同于MyEnum,所以我相信根据定义我也可以这样写:

public class MyClass { 
   public Enum<Enum<MyEnum>> field;
}

但是现在编译器实际上阻止了我:Type parameter 'java.lang.Enum' is not within its bound; should extend 'java.lang.Enum&lt;MyEnum&gt;&gt;,它根据定义执行它,因为它仍然满足:E extends Enum&lt;E&gt;。当然,你不允许这种重复(或者可能更好,招致)构造的原因有很多,但给定的一个对我来说确实是错误的。

另一方面,如果我要定义这样的类(类似于Enum 的定义)

public class Wrapper<T extends Number> { 
} 

我可以写一个类:

public class MyClass { 
   // satisfies the upper bound
   public Wrapper<Integer> field1;

   // also satisfies the upper bound
   public Wrapper<Number> field2;
}

是我忽略了什么还是我的分析被误导了?

【问题讨论】:

  • 对不起,如果我误解了这个问题,public MyEnum field 可以为你工作吗?
  • "我可以用这个定义定义一个字段:public Enum&lt;MyEnum&gt; field" --- 你为什么要这样?为什么不把它定义为public MyEnum field,因为MyEnum extends Enum&lt;MyEnum&gt;,并且将是唯一类这样做。
  • 这与实际解决方案无关。这是为了更好地理解语言。

标签: java generics enums


【解决方案1】:

我认为这是一个学术问题。您实际上并没有编写这样的代码,您只是想更好地理解语言,对吗?因为在实际代码中你当然会简单地写:

public MyEnum myField;

本着这种精神——

因为Enum&lt;MyEnum&gt; 显然等同于MyEnum...

它们不相等。 MyEnumEnum&lt;MyEnum&gt;子类。自动生成的类是这样的:

public final class MyEnum extends Enum<MyEnum> {
    ...
}

这意味着您不能继续使用Enum&lt;Enum&lt;MyEnum&gt;&gt; 扩展声明。如果你愿意,你可以写这个:

public Enum<? extends Enum<MyEnum>> field;

这将编译,递归的可能性到此为止。

我对@9​​87654330@ 中的上限X 的理解是它包括X 及其子类。所以 Enum&lt;Enum&gt; 应该被允许,但它不是。

让我们看看E到底是什么,这里的E

public abstract class Enum<E extends Enum<E>>

当你写Enum&lt;Enum&lt;MyEnum&gt;&gt;时,E就是Enum&lt;MyEnum&gt;。这个E 是否与约束E extends Enum&lt;E&gt; 匹配?我们需要将E 替换为Enum&lt;MyEnum&gt;

E extends Enum<E>?
^              ^

Enum<MyEnum> extends Enum<Enum<MyEnum>>?
^^^^^^^^^^^^              ^^^^^^^^^^^^

现在让我们回答几个相关但略有不同的问题:

  • MyEnum 是否扩展 Enum&lt;MyEnum&gt;?是的。我上面列出的自动生成的代码表明情况就是这样。

  • Enum&lt;MyEnum&gt; 是否扩展 Enum&lt;MyEnum&gt;?是的。正如您在Number 示例中正确描述的那样,就extends 关键字而言,一个类被认为是其自身的子类。

  • 现在我们关心的问题是:Enum&lt;MyEnum&gt; 是否扩展了Enum&lt;Enum&lt;MyEnum&gt;&gt;?不,它没有。这是您尝试工作的代码需要保持的关系。它不成立,这就是您的代码无法编译的原因。

【讨论】:

  • 是的.. 这是学术性的。不..我当然不会写这样的代码:)。但我参与构建需要匹配类型的注释处理器。我们应该能够涵盖所有场景。这就是为什么我想了解我的推理为什么会出错。我需要考虑更多关于你的答案。假设一个类:public class Wrapper&lt;T extends Number&gt; {}。我将能够创建这样的字段:public class MyType{ public Wrapper&lt;Number&gt; field; } 对吗?上限也包括Number,无需使用通配符。
  • 我扩展了我的示例,只是为了表明这是一个学术问题。我知道MyEnumEnum&lt;MyEnum&gt; 的子类,但这仍然满足上限,对吧。它具有包容性(因此我以Number 为例)。
  • 我的意思是,Enum&lt;Enum&lt;MyEnum&gt;&gt; 的参数是Enum&lt;MyEnum&gt; 或原始Enum。我对T extends X 中的上限 X 的理解是它包括 X 及其子类。所以Enum&lt;Enum&gt; 应该被允许,但它不是。在这里,我不明白它与我的 Number 示例有何不同。
  • 您的回答非常清楚,对我帮助很大。非常感谢您投入的时间。虽然对我来说,aha 时刻伴随着上面@Andreas 的回答而来。混淆的部分是extends 绑定。毕竟,(原始)EnumE extends Enum 的范围内。但破坏它的是泛型类型参数XEnum&lt;X&gt;
【解决方案2】:

使用Enum&lt;Enum&lt;MyEnum&gt;&gt;,它使E 等于Enum&lt;MyEnum&gt;

因此,绑定的E extends Enum&lt;E&gt; 要求Enum&lt;MyEnum&gt; 必须扩展Enum&lt;Enum&lt;MyEnum&gt;&gt;,但它没有,因此被编译器拒绝。


请记住,Enumenum 的隐式超类。

当你写enum MyEnum { ... }时,你得到的其实是class MyEnum extends Enum&lt;MyEnum&gt; { ... }

这使得E 等于MyEnum

因此,绑定的E extends Enum&lt;E&gt; 要求MyEnum 必须扩展Enum&lt;MyEnum&gt;,它确实这样做了,所以编译器很高兴。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2013-09-20
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
相关资源
最近更新 更多