当前位置: 首页 > 面试题库 >

Java枚举和泛型

欧奇希
2023-03-14
问题内容

这件事让我困扰了一阵子。我之前曾问过一些问题,但措辞可能很拙劣,而且例子太抽象了。所以目前尚不清楚我实际上在问什么。我会再尝试。并且请不要下结论。我希望这个问题根本不容易回答!

为什么我不能在Java中使用带有泛型类型参数的枚举?

问题不在于语法上为什么不可能做到这一点。我知道这只是不受支持。问题是:为什么JSR人员会“忘记”或“忽略”这个非常有用的功能?我无法想象与编译器相关的原因,为什么它不可行。

这就是我想做的。这在Java中是可能的。这是Java 1.4创建类型安全枚举的方法:

// A model class for SQL data types and their mapping to Java types
public class DataType<T> implements Serializable, Comparable<DataType<T>> {
    private final String name;
    private final Class<T> type;

    public static final DataType<Integer> INT      = new DataType<Integer>("int", Integer.class);
    public static final DataType<Integer> INT4     = new DataType<Integer>("int4", Integer.class);
    public static final DataType<Integer> INTEGER  = new DataType<Integer>("integer", Integer.class);
    public static final DataType<Long>    BIGINT   = new DataType<Long>   ("bigint", Long.class);

    private DataType(String name, Class<T> type) {
        this.name = name;
        this.type = type;
    }

    // Returns T. I find this often very useful!
    public T parse(String string) throws Exception {
        // [...]
    }

    // Check this out. Advanced generics:
    public T[] parseArray(String string) throws Exception {
        // [...]
    }

    // Even more advanced:
    public DataType<T[]> getArrayType() {
        // [...]
    }

    // [ ... more methods ... ]
}

然后,您可以<T>在其他许多地方使用

public class Utility {

    // Generic methods...
    public static <T> T doStuff(DataType<T> type) {
        // [...]
    }
}

但是用枚举是不可能做到的:

// This can't be done
public enum DataType<T> {

    // Neither can this...
    INT<Integer>("int", Integer.class), 
    INT4<Integer>("int4", Integer.class),

    // [...]
}

现在,正如我所说。我知道这些东西都是按照这种方式设计的。enum是语法糖。泛型也是如此。实际上,编译器会完成所有工作,并将其转换enums为的子类,java.lang.Enum并将泛型转换为强制转换和综合方法。

但是为什么编译器不能走得更远并允许泛型枚举呢?

编辑 :这是我期望作为编译器生成的Java代码:

public class DataType<T> extends Enum<DataType<?>> {
    // [...]
}

问题答案:

我会稍作猜测,这是由于Enum类本身的类型参数(定义为)上的协方差问题引起的Enum<E extendsEnum<E>>,尽管要研究所有极端情况会花费很多。

除此之外,枚举的主要用例是使用诸如EnumSet和valueOf之类的东西,其中您拥有具有不同泛型参数的事物集合,并从字符串获取值,所有这些都不支持或恶化枚举本身的泛型参数。

我知道当我尝试使用Generics时,我总是处在痛苦的世界中,而且我想象语言设计师会偷看这个深渊并决定不去那里,特别是因为这些功能是同时开发的,这意味着枚举方面的不确定性更大。

或者换种说法,Class<T>在处理本身具有通用参数的类时会遇到所有问题,您将不得不进行大量的转换和原始类型的处理。对于您正在查看的用例类型,语言设计师认为并非真正值得的东西。

编辑:响应评论(和汤姆-downvote吗?),嵌套的通用参数使各种不好的事情发生。
枚举实现Comparable。如果泛型在起作用,那么比较客户机代码中枚举的两个任意元素根本行不通。一旦处理了Generic参数的Generic参数,您将面临各种边界问题和头痛。设计一个处理良好的类很困难。在可比的情况下,我无法找到一种方法来使它能够比较枚举的两个任意成员,而又不返回原始类型并得到编译器警告。您可以…吗?

实际上,上述情况令人尴尬地错了,因为我在问题中使用DataType作为思考此问题的模板,但实际上Enum会有一个子类,因此不太正确。

但是,我坚持我的回答的要旨。汤姆(Tom)提出来了EnumSet.complementOf,当然,我们仍然会valueOf产生问题,并且就Enum的设计可以起到的作用而言,我们必须意识到那是20/20事后看来的事情。Enum与泛型同时设计,没有验证所有这种极端情况的好处。特别是考虑到具有通用参数的Enum的用例相当有限。(但同样,EnumSet的用例也是如此)。



 类似资料:
  • 问题内容: 我的结构相当复杂,无法正常工作。这是我所做的: 目的是根据枚举来概括调用,而只是能够迭代枚举数组。 这工作正常且花花公子。但是,如果我说 那么它是一个而不是一个。该方法返回,但最终它变为和。 我究竟做错了什么? 如何保留通用参数类型? 我想补充一点,我确实意识到问题出在未经检查的转换中。但是服务定义为 而且我不知道为什么不能推断类型。 编辑 :从技术上讲,如果我明确推断出它们,则可以使

  • 问题内容: 我有一个像这样的通用接口: 此接口具有有限的实例,因此最好将它们实现为枚举值。问题是那些实例具有不同类型的值,因此我尝试了以下方法,但无法编译: 有什么想法吗? 问题答案: 你不能 Java不允许在枚举常量上使用泛型类型。但是,它们允许用于枚举类型: 在这种情况下,你可以做的是为每个泛型类型都拥有一个枚举类型,或者通过将其设为一个类来“伪造”一个枚举: 不幸的是,它们都有缺点。

  • 本文向大家介绍详解Java中的 枚举与泛型,包括了详解Java中的 枚举与泛型的使用技巧和注意事项,需要的朋友参考一下 详解Java中的 枚举与泛型 一:首先从枚举开始说起 枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字enum来定义一个枚举类。下面就是一个典型枚举类型的定义:    显然,enum很像特殊的class,实际上enum声明定义的类型就是一个类。 而这些类都是类库中En

  • 问题内容: 更新: 感谢所有提供帮助的人-这个答案的答案在于我在更复杂的代码中没有注意到的内容以及对Java5协变量返回类型不了解的内容。 原始帖子: 今天早上我一直在玩一些东西。虽然我知道我 可以用 不同的方式解决整个问题,但我发现自己一直迷恋于弄清楚为什么它没有按我预期的那样工作。在花了一些时间阅读这些内容之后,我发现我离理解还很近,因此我将其作为一个问题来看看我是否只是愚蠢,或者是否真的有我

  • 主要内容:声明枚举,枚举类,为枚举添加方法,EnumMap 与 EnumSet枚举是一个被命名的整型常数的集合,用于声明一组带标识符的常数。枚举在曰常生活中很常见,例如一个人的性别只能是“男”或者“女”,一周的星期只能是 7 天中的一个等。类似这种当一个变量有几种固定可能的取值时,就可以将它定义为枚举类型。 在 JDK 1.5 之前没有枚举类型,那时候一般用接口常量来替代。而使用 Java 枚举类型 enum 可以更贴近地表示这种常量。 声明枚举 声明枚举时必须使用 enu

  • Spring 3.x、JPA 2.0、Hibernate 4.x、Postgresql 9.x. 使用希望映射到Postgresql枚举的枚举属性处理Hibernate映射类。 使用枚举列上的where子句进行查询会引发异常。 SQL: Hibernate xml查询: > 按而不是按枚举查询工作正常。 没有数据库交互的Java工作良好: 不是,与和相同,异常更改为: 在查看https://sta