Java Enum定义

问题

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

class Enum<E extends Enum<E>>

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


#1 热门回答(97 赞)

这意味着枚举的类型参数必须从枚举中派生,枚举本身具有相同的类型参数。怎么会发生这种情况?通过使类型参数成为新类型本身。因此,如果我有一个名为StatusCode的枚举,它将等同于:

public class StatusCode extends Enum<StatusCode>

现在,如果你检查约束,我们已经得到了667894465- soE=StatusCode。我们来看看:doesEextendEnum<StatusCode>?是!我们没事。

你可能会问自己这是什么意思:)嗯,这意味着Enum的API可以引用自身 - 例如,能够说Enum<E>implementsComparable<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自己会好的。


#2 热门回答(24 赞)

以下是bookJava Generics and Collections中解释的修改版本:我们有一个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>

SoEnum参数类似于Season。摘自Season,你得到的参数是Enum是任何满足的类型

E extends Enum<E>

Maurice Naftalin(合着者,Java Generics and Collections)


#3 热门回答(3 赞)

这可以通过一个简单的例子和​​一种技术来说明,该技术可用于实现子类的链式方法调用。在下面的示例中,setName返回aNode,因此链接将不适用于58303939:

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
}

所以我们可以在泛型声明中引用一个子类,以便Citynow返回正确的类型:

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!
    }
}