我以为我很了解Java泛型,但是随后在java.lang.Enum中遇到了以下内容:
class Enum<E extends Enum<E>>
有人可以解释如何解释此类型参数吗?奖励积分,用于提供其他示例,说明可以使用类似类型的参数。
我以为我很了解Java泛型,但是随后在java.lang.Enum中遇到了以下内容:
class Enum<E extends Enum<E>>
有人可以解释如何解释此类型参数吗?奖励积分,用于提供其他示例,说明可以使用类似类型的参数。
Answers:
这意味着枚举的类型实参必须从本身具有相同类型实参的枚举派生。怎么会这样 通过使类型参数成为新类型本身。因此,如果我有一个名为StatusCode的枚举,则它等效于:
public class StatusCode extends Enum<StatusCode>
现在,如果你检查的限制,我们已经得到了Enum<StatusCode>
-如此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
本身会很好。
Enum
没有任何返回类型参数类型的实例方法。
class Enum<E>
在所有情况下这都是足够的。并且在泛型中,只有在确实需要确保类型安全的情况下才应使用限制性更强的界限。
Enum
子类并非总是自动生成的,那么您需要class Enum<E extends Enum<?>>
结束的唯一原因class Enum<E>
是可以访问ordinal
for compareTo()
。但是,如果您考虑一下,从语言的角度来看,让您通过它们的序数来比较两种不同类型的枚举是没有意义的。因此,仅在自动生成子类的情况下Enum.compareTo()
,使用的实现ordinal
才有意义Enum
。如果您可以手动子类化Enum
,则compareTo
可能必须这样做abstract
。
以下是从书中解释的修改版本的Java泛型和集合:我们有一个Enum
声明
enum Season { WINTER, SPRING, SUMMER, FALL }
这将扩展到一个类
final class Season extends ...
哪里...
是枚举参数化的基类。让我们算出那是什么。好吧,Season
对它的要求之一就是应该实现Comparable<Season>
。所以我们需要
Season extends ... implements Comparable<Season>
您可以使用什么...
来使它正常工作?鉴于它必须是的参数化Enum
,因此唯一的选择是Enum<Season>
,因此您可以拥有:
Season extends Enum<Season>
Enum<Season> implements Comparable<Season>
因此Enum
在诸如的类型上进行参数化Season
。从中摘录Season
,您会得到的参数Enum
是任何满足条件的类型
E extends Enum<E>
Maurice Naftalin(Java泛型和合集)的合著者
Season
工具Comparable<Season>
?
compareTo
方法的参数必须已声明为Enum
子类型,否则编译器将(正确)说它没有序数。
Enum
,那么class OneEnum extends Enum<AnotherEnum>{}
即使Enum
现在声明了它,也可能有。这将没有多大意义,以能够比较一个枚举类型与另一个,所以后来Enum
的compareTo
就没有意义作为反正声明。边界对此没有任何帮助。
public class Enum<E extends Enum<?>>
就足够了。
这可以通过一个简单的示例和一种可以用来实现子类的链接方法调用的技术来说明。在下面的示例中,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!
}
}
return (CHILD) this;
不受检查的强制类型转换:考虑添加getThis()方法:protected CHILD getThis() { return this; }
请参阅:angelikalanger.com/GenericsFAQ/FAQSections/…–
Node<T>
不是这种情况),那么我会忽略它们以节省时间。
return (SELF) this;
被编译为return this;
,因此可以将其省略。
您不是唯一想知道这意味着什么的人。请参阅Chaotic Java博客。
“如果一个类扩展了该类,则它应该传递参数E。参数E的范围是针对使用相同参数E扩展该类的类的。”
这篇文章向我完全阐明了“递归泛型类型”的问题。我只想添加另一个需要这种特殊结构的情况。
假设在通用图中有通用节点:
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(){...}
}
class Foo extends Node<City>
Foo与City不相关的地方。
class Node<T>
呢?
class Node<T>
与您的示例完全一致。
如果您查看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>
对象。
一个更清晰的示例是我在这个问题上回答的示例,如果要指定泛型绑定,则无法避免这种构造。
compareTo
也不getDeclaringClass
需要extends Enum<E>
约束。