Java枚举定义

我以为我很了解Javagenerics,但后来我在java.lang.Enum中遇到了以下内容:

class Enum<E extends Enum<E>> 

有人可以解释如何解释这个types的参数? 用于提供可以使用类似types参数的其他示例的奖励点。

这意味着枚举的types参数必须从一个枚举派生,而枚举本身具有相同的types参数。 这怎么可能发生? 通过使types参数成为新types本身。 所以如果我有一个名为StatusCode的枚举,它将相当于:

 public class StatusCode extends Enum<StatusCode> 

现在如果你检查约束条件,我们得到Enum<StatusCode> – 所以E=StatusCode 。 让我们检查一下: E扩展Enum<StatusCode> ? 是! 我们没事

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

我在ProtocolBuffers的C#端口中使用了类似的东西。 有“消息”(不可变)和“build设者”(可变的,用于build立一个消息) – 他们来成对的types。 涉及的接口是:

 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> 

这意味着从消息中你可以得到一个合适的构build器(例如获取一个消息的副本并修改一些位),并且从构build器中获得一个适当的消息,当你完成构build时。 API的使用者不需要真正关心这个问题 – 这个过程非常复杂,需要经过几次迭代才能到达目的地。

编辑:请注意,这不会阻止你创build使用types参数本身是好的,但不是相同types的奇数types。 目的是在正确的情况下给予好处,而不是保护你免受错误的情况。

所以如果Enum没有在Java中“特别”处理,你可以(如注释中所述)创build以下types:

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

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

以下是Javagenerics和集合的解释修改版本:我们已经声明了Enum

 enum Season { WINTER, SPRING, SUMMER, FALL } 

这将扩大到一个类

 final class Season extends ... 

在哪里...是以某种方式参数化的基类Enums。 让我们来研究一下是什么。 那么对Season的要求之一是它应该实施Comparable<Season> 。 所以我们需要

 Season extends ... implements Comparable<Season> 

你可以用什么来...这将使这个工作? 鉴于它必须是一个Enum的参数,唯一的select是Enum<Season> ,所以你可以有:

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

所以Enum参数化的types如Season 。 从Season摘要,你会发现Enum的参数是任何满足的types

  E extends Enum<E> 

Maurice Naftalin(Javagenerics和集合的合着者)

你不是唯一一个想知道这意味着什么的人。 看到混沌的Java博客 。

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

这篇文章已经完全澄清了这些“recursiongenerics”的问题。 我只是想补充一下这个特殊的结构是必要的。

假设在通用图中有通用节点:

 public abstract class Node<T extends Node<T>> { public void addNeighbor(T); public void addNeighbors(Collection<? extends T> nodes); public Collection<T> getNeighbor(); } 

那么你可以有专门的types的图表:

 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 } 

因此,我们可以在generics声明中引用一个子类,以便City返回正确的types:

 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的情况下,它是无用的。 如果它被声明为一样,所有东西都可以工作

 class Enum<E> 

如果你看看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>是什么意思? 这意味着types参数是从Enum扩展的东西,并没有用原始types参数化(它本身是参数化的)。

这是相关的,如果你有一个枚举

 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>对象。

一个更清晰的例子就是我在这个问题上回答的问题 ,如果你想指定一个generics边界,那么你不能避免这个结构。