Java Enum定义

Dón*_*nal 146 java generics enums crtp

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

class Enum<E extends Enum<E>>
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*eet 103

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

public class StatusCode extends Enum<StatusCode>
Run Code Online (Sandbox Code Playgroud)

现在,如果你检查约束,我们已经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>
Run Code Online (Sandbox Code Playgroud)

这意味着从消息中您可以获得适当的构建器(例如,获取消息的副本并更改某些位),并且从构建器中,您可以在构建完成后获得相应的消息.虽然API的用户不需要真正关心它,但这是一个很好的工作 - 它非常复杂,需要多次迭代才能到达目的地.

编辑:请注意,这并不会阻止您创建使用类型参数的奇数类型,该类型参数本身可以,但不是同一类型.目的是在正确的情况下给予利益,而不是保护您免受错误的情况.

因此,如果Enum不是在Java中"特别"处理,您可以(如注释中所述)创建以下类型:

public class First extends Enum<First> {}
public class Second extends Enum<First> {}
Run Code Online (Sandbox Code Playgroud)

Second会实施Comparable<First>而不是Comparable<Second>......但First本身会好起来的.


Mau*_*lin 26

以下是Java Generics和Collections一书中解释的修改版本:我们已经Enum声明了

enum Season { WINTER, SPRING, SUMMER, FALL }
Run Code Online (Sandbox Code Playgroud)

这将扩展到一个类

final class Season extends ...
Run Code Online (Sandbox Code Playgroud)

在哪里...是Enums的以某种方式参数化的基类.让我们弄清楚那是什么.那么,其中一个要求Season是它应该实现Comparable<Season>.所以我们需要

Season extends ... implements Comparable<Season>
Run Code Online (Sandbox Code Playgroud)

您可以使用什么来...实现这一点?鉴于它必须是参数化Enum,唯一的选择是Enum<Season>,所以你可以:

Season extends Enum<Season>
Enum<Season> implements Comparable<Season>
Run Code Online (Sandbox Code Playgroud)

所以Enum在类似的类型上参数化Season.摘要从Season你得到的参数Enum是任何满足的类型

 E extends Enum<E>
Run Code Online (Sandbox Code Playgroud)

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

  • @newacct看看Enum的定义.为了将一个实例与另一个实例进行比较,它必须比较它们的序数.所以`compareTo`方法的参数必须被*声明*作为'Enum`子类型,否则编译器会(正确地)说它没有序数. (2认同)
  • @MauriceNaftalin:`Enum.compareTo()` 被声明为采用类型为 `E` 的参数。这是一个标准库函数,如何实现不是用户关心的。Java 语言特别禁止用户手动对 Enum 进行子类化,并且所有编译器生成的枚举的类型参数无论如何都与类型本身相同,因此标准库实现可以依靠它来执行不安全的转换。 (2认同)
  • @MauriceNaftalin:如果 Java 不禁止手动对 `Enum` 进行子类化,那么即使现在声明 `Enum`,也可以使用 `class OneEnum extends Enum&lt;AnotherEnum&gt;{}`。能够将一种类型的枚举与另一种类型进行比较没有多大意义,因此无论如何`Enum` 的`compareTo` 都没有任何意义。边界对此没有任何帮助。 (2认同)
  • @MauriceNaftalin:如果序数是原因,那么`public class Enum&lt;E extends Enum&lt;?&gt;&gt;` 也足够了。 (2认同)

And*_*hev 5

这可以通过一个简单的示例和一种可以用于实现子类的链式方法调用的技术来说明。在下面的示例中,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
}
Run Code Online (Sandbox Code Playgroud)

因此,我们可以在泛型声明中引用子类,以便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!
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您的解决方案有一个未经检查的强制转换: `return (CHILD) this;` 考虑添加一个 getThis() 方法: `protected CHILD getThis() { return this; }` 请参阅:http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#getthis (2认同)