题
我以为我很了解 Java 泛型,但后来我在 java.lang.Enum 中遇到了以下内容:
class Enum<E extends Enum<E>>
有人可以解释如何解释这个类型参数吗?提供可以使用类似类型参数的其他示例的奖励积分。
解决方案
这意味着枚举的类型参数必须从枚举中派生,枚举本身具有相同的类型参数。怎么会发生这种情况?通过使类型参数成为新类型本身。因此,如果我有一个名为StatusCode的枚举,它将等同于:
public class StatusCode extends Enum<StatusCode>
现在,如果您检查约束,我们已经Enum<StatusCode>
- 所以E=StatusCode
。我们来检查:E
扩展Enum<E>
?是!我们没事。
你可能会问自己这是什么意思:)嗯,这意味着Enum的API可以引用自身 - 例如,能够说Comparable<E>
实现Enum
。基类能够进行比较(在枚举的情况下),但它可以确保它只比较正确的枚举类型。 (编辑:嗯,差不多 - 看看底部的编辑。)
我在ProtocolBuffers的C#端口使用了类似的东西。有<!> quot; messages <!> quot; (不可变的)和<!> quot; builders <!> quot; (可变,用于构建消息) - 它们是成对的类型。涉及的接口是:
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的用户不需要真正关心它,但这是一个很好的工作 - 它非常复杂,需要多次迭代才能到达目的地。
编辑:请注意,这并不能阻止您创建使用类型参数的奇数类型,这种类型参数本身可以,但它的类型不同。目的是在正确的案例中提供好处,而不是保护您免受错误的案件的侵害。
所以,如果Second
未被处理<!>,则特别<!>无论如何,在Java中,您可以(如注释中所述)创建以下类型:
public class First extends Enum<First> {}
public class Second extends Enum<First> {}
Comparable<First>
会实现Comparable<Second>
而不是First
......但<=>本身就没问题。
其他提示
以下是 Java Generics and Collections 一书中解释的修改版本:
我们有一个Enum
声明的
enum Season { WINTER, SPRING, SUMMER, FALL }
将扩展为类
final class Season extends ...
其中...
是枚举的以某种方式参数化的基类。开始工作吧
这是必须的。嗯,Season
的要求之一是它应该实现Comparable<Season>
。所以我们需要
Season extends ... implements Comparable<Season>
你能用什么Enum<Season>
来实现这个目的?鉴于它必须是<=>的参数化,唯一的选择是<=>,以便您可以:
Season extends Enum<Season>
Enum<Season> implements Comparable<Season>
所以<=>在类似<=>的类型上进行参数化。摘要来自<=>和 你知道<=>的参数是满足
的任何类型 E extends Enum<E>
Maurice Naftalin(共同作者,Java Generics and Collections)
这可以通过一个简单的示例和一种可用于实现子类的链式方法调用的技术来说明。在下面的例子中 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!
}
}
你不是唯一想知道这意味着什么的人;请参阅混乱Java博客。
<!>#8220;如果一个类扩展了这个类,它应该传递一个参数E.参数E <!>#8217; s的范围是一个类,它使用相同的参数E <!>扩展该类。 #8221;
这篇文章完全向我阐明了“递归泛型类型”的问题。 我只想添加另一个需要这种特殊结构的案例。
假设您在通用图表中有通用节点:
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(){...}
}
如果您查看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>
意味着什么?这意味着类型参数是从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>
对象。
更清楚的例子是我在上回答的一个例子。这个问题,如果你想指定一个通用的边界,你就无法避免这种结构。