Eclipse编译器和javac之间的差异-枚举、接口和泛型

Eclipse编译器和javac之间的差异-枚举、接口和泛型,java,eclipse,enums,enumset,Java,Eclipse,Enums,Enumset,以下代码在Eclipse中编译(并按预期运行测试): import java.util.EnumSet; public class EnumTest { static enum Cloneables implements Cloneable { One, Two, Three; } public <T extends Cloneable> T getOne(Class enumType) { EnumSet<? ext

以下代码在Eclipse中编译(并按预期运行测试):

import java.util.EnumSet;
public class EnumTest {

    static enum Cloneables implements Cloneable {
        One, Two, Three;
    }

    public <T extends Cloneable> T getOne(Class enumType) {
        EnumSet<? extends T> set = EnumSet.allOf(enumType);
        return set.iterator().next();
    }
}
老实说,在我编写代码时,枚举+接口+类型参数(泛型)的复杂性一下子就把我甩了,但我认为我最终还是做对了

目标是编写如下调用代码:

Cloneable something = enumTest.getOne(Cloneables.class);
例如,在Eclipse中,以下测试编译并通过:

@Test
public void testGetFirst() {
    assertSame(Cloneables.One, getOne(Cloneables.class));
}
任何关于哪一个是“正确的”的线索,Eclipse或javac,我们都将不胜感激

同样值得赞赏的是关于实现该想法的其他方法的任何建议:将类作为可在
EnumSet.allOf()
中使用的方法参数,并确定
EnumSet
中枚举对象的类型


顺便说一句,不要费心批评这种方法的目的;我将其从更有用/更有意义的代码中缩减。我不想讨论“从枚举类型中查找第一个元素”的优点,这不是问题的重点。

您需要确保
T
是枚举类型,否则它将不满足
EnumSet
的约束:

public <T extends Enum<T> & Cloneable> T getOne(Class enumType) 

我甚至不知道在声明这样的类型参数时可以应用
&
操作符。即使在写了将近18年的Java代码之后,我今天也学到了一些新东西!顺便说一下,我使用
Class
的原始形式的原因是,如果没有
T
扩展
Enum
,Eclipse编译器将不会接受
Class
类型参数的任何值。因此,原始使用它是一种副作用,因为不知道如何为
T
组合
Cloneable
Enum
。有趣的是,Eclipse不允许我将集合声明为
EnumSet
——它抱怨“绑定不匹配:类型T不是类型EnumSet的绑定参数的有效替代品”。幸运的是,
EnumSet@E-丽兹:没有;实际上,边界应该是
T extends Enum&Cloneable
。然后您可以再次删除通配符。@E-Riz鉴于泛型是在2004年添加到Java中的,您只有10年(将近11年)的时间了解它们:-)。我发现泛型是迄今为止Java最复杂的领域。使用它们并不是那么糟糕,但是当涉及到声明任何泛型方法/类时,它可能是非常可怕的。这可能是javac(jdk1.7.060)中的一个bug。下面公认的答案是一个变通方法(实际上是更干净的代码)。请参见第页的详细分析
public <T extends Enum<T> & Cloneable> T getOne(Class enumType) 
public <T extends Enum<T> & Cloneable> T getOne(Class<T> enumType) {
    EnumSet<T> set = EnumSet.allOf(enumType);
    return set.iterator().next();
}