Java 枚举定义
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/211143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Enum definition
提问by Dónal
I thought I understood Java generics pretty well, but then I came across the following in java.lang.Enum:
我以为我很了解 Java 泛型,但后来我在 java.lang.Enum 中遇到了以下内容:
class Enum<E extends Enum<E>>
Could someone explain how to interpret this type parameter? Bonus points for providing other examples of where a similar type parameter could be used.
有人可以解释如何解释这个类型参数吗?提供可以使用类似类型参数的其他示例的奖励积分。
采纳答案by Jon Skeet
It means that the type argument for enum has to derive from an enum which itself has the same type argument. How can this happen? By making the type argument the new type itself. So if I've got an enum called StatusCode, it would be equivalent to:
这意味着 enum 的类型参数必须从本身具有相同类型参数的 enum 派生。这怎么会发生?通过使类型参数成为新类型本身。因此,如果我有一个名为 StatusCode 的枚举,它相当于:
public class StatusCode extends Enum<StatusCode>
Now if you check the constraints, we've got Enum<StatusCode>
- so E=StatusCode
. Let's check: does E
extend Enum<StatusCode>
? Yes! We're okay.
现在,如果您检查约束,我们会得到Enum<StatusCode>
- 所以E=StatusCode
。让我们检查一下:是否E
扩展Enum<StatusCode>
?是的!我们没事。
You may well be asking yourself what the point of this is :) Well, it means that the API for Enum can refer to itself - for instance, being able to say that Enum<E>
implements Comparable<E>
. The base class is able to do the comparisons (in the case of enums) but it can make sure that it only compares the right kind of enums with each other. (EDIT: Well, nearly - see the edit at the bottom.)
您可能会问自己这是什么意思:) 嗯,这意味着 Enum 的 API 可以引用自身 - 例如,可以说Enum<E>
实现Comparable<E>
. 基类能够进行比较(在枚举的情况下),但它可以确保它只比较正确类型的枚举。(编辑:嗯,几乎 - 请参阅底部的编辑。)
I've used something similar in my C# port of ProtocolBuffers. There are "messages" (immutable) and "builders" (mutable, used to build a message) - and they come as pairs of types. The interfaces involved are:
我在 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>
This means that from a message you can get an appropriate builder (e.g. to take a copy of a message and change some bits) and from a builder you can get an appropriate message when you've finished building it. It's a good job users of the API don't need to actually care about this though - it's horrendously complicated, and took several iterations to get to where it is.
这意味着您可以从消息中获得适当的构建器(例如,获取消息的副本并更改某些位),而在构建完成后,您可以从构建器中获得适当的消息。不过,API 的用户实际上不需要关心这一点是一件好事——它非常复杂,并且需要多次迭代才能达到它的位置。
EDIT: Note that this doesn't stop you from creating odd types which use a type argument which itself is okay, but which isn't the same type. The purpose is to give benefits in the rightcase rather than protect you from the wrongcase.
编辑:请注意,这并不能阻止您创建使用类型参数的奇怪类型,该类型参数本身是可以的,但类型不同。目的是在正确的情况下提供好处,而不是在错误的情况下保护您。
So if Enum
weren't handled "specially" in Java anyway, you could (as noted in comments) create the following types:
因此,如果Enum
无论如何都没有在 Java 中“专门”处理,您可以(如注释中所述)创建以下类型:
public class First extends Enum<First> {}
public class Second extends Enum<First> {}
Second
would implement Comparable<First>
rather than Comparable<Second>
... but First
itself would be fine.
Second
会实现Comparable<First>
而不是Comparable<Second>
......但First
它本身会很好。
回答by kpirkkal
You are not the only one wondering what that means; see Chaotic Java blog.
你不是唯一想知道这意味着什么的人;请参阅混乱的 Java 博客。
“If a class extends this class, it should pass a parameter E. The parameter E's bounds are for a class which extends this class with the same parameter E”.
“如果一个类扩展了这个类,它应该传递一个参数 E。参数 E 的边界是针对一个用相同参数 E 扩展这个类的类”。
回答by Maurice Naftalin
The following is a modified version of the explanation from the book Java Generics and Collections:
We have an Enum
declared
以下是Java 泛型和集合一书中解释的修改版本:我们有一个Enum
声明
enum Season { WINTER, SPRING, SUMMER, FALL }
which will be expanded to a class
这将扩展为一个类
final class Season extends ...
where ...
is to be the somehow-parameterised base class for Enums. Let's work
out what that has to be. Well, one of the requirements for Season
is that it should implement Comparable<Season>
. So we're going to need
where...
是枚举的以某种方式参数化的基类。让我们弄清楚那是什么。嗯, 的要求之一Season
是它应该实现Comparable<Season>
. 所以我们需要
Season extends ... implements Comparable<Season>
What could you use for ...
that would allow this to work? Given that it has to be a parameterisation of Enum
, the only choice is Enum<Season>
, so that you can have:
你可以用什么来...
让它工作?鉴于它必须是 的参数化Enum
,唯一的选择是Enum<Season>
,这样您就可以拥有:
Season extends Enum<Season>
Enum<Season> implements Comparable<Season>
So Enum
is parameterised on types like Season
. Abstract from Season
and
you get that the parameter of Enum
is any type that satisfies
所以Enum
是参数化的类型,如Season
. Abstract fromSeason
并且你得到的参数Enum
是满足的任何类型
E extends Enum<E>
Maurice Naftalin (co-author, Java Generics and Collections)
Maurice Naftalin(合著者,Java 泛型和集合)
回答by nozebacle
This post has totally clarified to me these problem of 'recursive generic types'. I just wanted to add another case where this particular structure is necessary.
这篇文章已经完全向我澄清了“递归泛型类型”的这些问题。我只是想添加另一个需要这种特殊结构的情况。
Suppose you have generic nodes in a generic graph:
假设您在通用图中有通用节点:
public abstract class Node<T extends Node<T>>
{
public void addNeighbor(T);
public void addNeighbors(Collection<? extends T> nodes);
public Collection<T> getNeighbor();
}
Then you can have graphs of specialized types:
然后你可以有专门类型的图表:
public class City extends Node<City>
{
public void addNeighbor(City){...}
public void addNeighbors(Collection<? extends City> nodes){...}
public Collection<City> getNeighbor(){...}
}
回答by Andrey Chaschev
This can be illustrated by a simple example and a technique which can be used to implement chained method calls for sub-classes. In an example below setName
returns a Node
so chaining won't work for the City
:
这可以通过一个简单的例子和一种技术来说明,该技术可用于实现子类的链式方法调用。在下面的示例中,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
}
So we could reference a sub-class in a generic declaration, so that the City
now returns the correct type:
所以我们可以在泛型声明中引用一个子类,以便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!
}
}
回答by EpicPandaForce
If you look at the Enum
source code, it has the following:
如果您查看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);
}
}
First thing first, what does E extends Enum<E>
mean? It means the type parameter is something that extends from Enum, and isn't parametrized with a raw type (it's parametrized by itself).
首先,是什么E extends Enum<E>
意思?这意味着类型参数是从 Enum 扩展的东西,并且没有用原始类型参数化(它自己参数化)。
This is relevant if you have an enum
如果您有枚举,这很重要
public enum MyEnum {
THING1,
THING2;
}
which, if I know correctly, is translated to
如果我知道正确的话,它会被翻译成
public final class MyEnum extends Enum<MyEnum> {
public static final MyEnum THING1 = new MyEnum();
public static final MyEnum THING2 = new MyEnum();
}
So this means that MyEnum receives the following methods:
所以这意味着 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;
}
And even more importantly,
而且更重要的是,
@SuppressWarnings("unchecked")
public final Class<MyEnum> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<MyEnum>)clazz : (Class<MyEnum>)zuper;
}
This makes getDeclaringClass()
cast to the proper Class<T>
object.
这使得getDeclaringClass()
投射到正确的Class<T>
对象。
A way clearer example is the one that I answered on this questionwhere you cannot avoid this construct if you want to specify a generic bound.
一个更清晰的例子是我在这个问题上回答的那个,如果你想指定一个通用的界限,你就无法避免这个构造。
回答by Hanzhou Tang
According to wikipedia, this pattern is called Curiously recurring template pattern. Basically, by using the CRTP pattern, we can easily refer to subclass type without type casting, which means by using the pattern, we can imitate virtual function.
根据维基百科,这种模式被称为Curiously recurring template pattern。基本上,通过使用 CRTP 模式,我们可以轻松地引用子类类型而无需类型转换,这意味着通过使用该模式,我们可以模仿虚函数。