Java Enum 定义

我认为我对 Java 泛型的理解非常好,但是后来我在 Java.lang 中遇到了以下问题:

class Enum<E extends Enum<E>>

有人能解释一下如何解释这个类型参数吗?另外,还提供了可以使用类似类型参数的其他示例。

24769 次浏览

这意味着枚举的类型参数必须从具有相同类型参数的枚举派生。怎么会这样?通过将类型参数设置为新类型本身。因此,如果我有一个名为 StatusCode 的枚举,它将等效于:

public class StatusCode extends Enum<StatusCode>

现在如果你检查约束,我们得到了 Enum<StatusCode>-so E=StatusCode。让我们检查一下: E是否延伸 Enum<StatusCode>?太棒了!我们没事。

您可能会问自己这样做的目的是什么:)这意味着 Enum 的 API 可以引用它自己——例如,可以说 Enum<E>实现了 Comparable<E>。基类可以进行比较(在枚举的情况下) ,但是它可以确保只比较正确类型的枚举。(编辑: 嗯,差不多-看底部的编辑。)

我在 ProtocolBuffers 的 C # 端口中使用了类似的代码。有“消息”(不可变的)和“构建器”(可变的,用于构建消息)——它们是成对的类型。涉及的接口如下:

public interface IBuilder<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder>


public interface IMessage<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder>

这意味着从一个消息中你可以得到一个合适的构建器(例如,获取一个消息的副本并修改一些位) ,当你完成构建后,你可以从一个构建器中得到一个合适的消息。这是一个很好的工作,API 的用户不需要真正关心这个问题——它非常复杂,并且需要几次迭代才能达到它的目的。

编辑: 请注意,这并不妨碍您创建使用类型参数的奇怪类型,类型参数本身是可以的,但不是同一类型。目的是在 的情况下给予好处,而不是保护你从 错了的情况下。

因此,如果 Enum在 Java 中没有得到“特殊”处理,您可以(如注释中所述)创建以下类型:

public class First extends Enum<First> {}
public class Second extends Enum<First> {}

Second将实现 Comparable<First>而不是 Comparable<Second>... 但是 First本身就可以了。

您不是唯一一个想知道这意味着什么的人; 请参阅 混乱的 Java 博客

”如果一个类扩展了这个类,它应该传递一个参数 E。参数 E 的边界用于扩展具有相同参数 E 的类。

以下是 Java 泛型和集合一书中解释的修改版本: 我们申报了 Enum

enum Season { WINTER, SPRING, SUMMER, FALL }

它将扩展为一个类

final class Season extends ...

其中 ...是 Enums 的某种参数化基类 看看那是什么。那么,对于 Season的一个要求就是它应该实现 Comparable<Season>。所以我们需要

Season extends ... implements Comparable<Season>

你可以使用什么 ...,让这个工作?考虑到它必须是参量化的 Enum,唯一的选择是 Enum<Season>,因此你可以:

Season extends Enum<Season>
Enum<Season> implements Comparable<Season>

因此,Enum是参数化的类型,如 Season 你得到 Enum的参数是任何满足

 E extends Enum<E>

Maurice Naftalin (Java 泛型和集合的合著者)

这篇文章完全向我澄清了“递归泛型类型”的问题。 我只是想添加另一种情况,这种特殊的结构是必要的。

假设在泛型图中有泛型节点:

public abstract class Node<T extends Node<T>>
{
public void addNeighbor(T);


public void addNeighbors(Collection<? extends T> nodes);


public Collection<T> getNeighbor();
}

然后你就可以得到特定类型的图表:

public class City extends Node<City>
{
public void addNeighbor(City){...}


public void addNeighbors(Collection<? extends City> nodes){...}


public Collection<City> getNeighbor(){...}
}

这可以通过一个简单的示例和一种技术来说明,该技术可用于实现子类的链式方法调用。在下面的一个例子中,setName返回一个 Node,所以链接不适用于 City:

class Node {
String name;


Node setName(String name) {
this.name = name;
return this;
}
}


class City extends Node {
int square;


City setSquare(int square) {
this.square = square;
return this;
}
}


public static void main(String[] args) {
City city = new City()
.setName("LA")
.setSquare(100);    // won't compile, setName() returns Node
}

因此,我们可以在泛型声明中引用一个子类,这样 City就可以返回正确的类型:

abstract class Node<SELF extends Node<SELF>>{
String name;


SELF setName(String name) {
this.name = name;
return self();
}


protected abstract SELF self();
}


class City extends Node<City> {
int square;


City setSquare(int square) {
this.square = square;
return self();
}


@Override
protected City self() {
return this;
}


public static void main(String[] args) {
City city = new City()
.setName("LA")
.setSquare(100);                 // ok!
}
}

如果您查看 Enum源代码,它有以下内容:

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


public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}


@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}


public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
}

首先,E extends Enum<E>是什么意思?它意味着 type 参数是从 Enum 扩展而来的,并且没有使用原始类型参数化(它本身是参数化的)。

如果您有枚举,那么这是相关的

public enum MyEnum {
THING1,
THING2;
}

如果我没记错的话

public final class MyEnum extends Enum<MyEnum> {
public static final MyEnum THING1 = new MyEnum();
public static final MyEnum THING2 = new MyEnum();
}

这意味着 MyEnum 接收以下方法:

public final int compareTo(MyEnum o) {
Enum<?> other = (Enum<?>)o;
Enum<MyEnum> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}

更重要的是,

    @SuppressWarnings("unchecked")
public final Class<MyEnum> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<MyEnum>)clazz : (Class<MyEnum>)zuper;
}

这使得 getDeclaringClass()转换为适当的 Class<T>对象。

一个更清楚的例子是我在 这个问题上回答的一个例子,如果你想指定一个通用的界限,你不能避免这个结构。

根据维基百科,这种模式被称为 奇异递归模板模式。 基本上,通过使用 CRTP 模式,我们可以很容易地引用没有类型强制转换的子类类型,这意味着通过使用该模式,我们可以模拟虚函数。