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边界,那么你不能避免这个结构。