Java 如何使用泛型实现enum?

Java 如何使用泛型实现enum?,java,generics,interface,enums,Java,Generics,Interface,Enums,我有这样一个通用接口: interface A<T> { T getValue(); } 接口A{ T getValue(); } 此接口具有有限的实例,因此最好将它们实现为枚举值。问题是这些实例具有不同类型的值,因此我尝试了以下方法,但无法编译: public enum B implements A { A1<String> { @Override public String getValue() {

我有这样一个通用接口:

interface A<T> {
    T getValue();
}
接口A{
T getValue();
}
此接口具有有限的实例,因此最好将它们实现为枚举值。问题是这些实例具有不同类型的值,因此我尝试了以下方法,但无法编译:

public enum B implements A {
    A1<String> {
        @Override
        public String getValue() {
            return "value";
        }
    },
    A2<Integer> {
        @Override
        public Integer getValue() {
            return 0;
        }
    };
}
公共枚举B实现了{
A1{
@凌驾
公共字符串getValue(){
返回“值”;
}
},
A2{
@凌驾
公共整数getValue(){
返回0;
}
};
}

你知道吗?

你不能。Java不允许对枚举常量使用泛型类型。允许在枚举类型上使用它们,但:

public enum B implements A<String> {
  A1, A2;
}
公共枚举B实现了{
A1,A2;
}
在这种情况下,您可以为每个泛型类型设置一个枚举类型,或者通过将枚举设置为类来“伪造”枚举:

public class B<T> implements A<T> {
    public static final B<String> A1 = new B<String>();
    public static final B<Integer> A2 = new B<Integer>();
    private B() {};
}
公共类B实现了{
公共静态最终B A1=新B();
公共静态最终B A2=新B();
私有B(){};
}

不幸的是,它们都有缺点。

作为设计某些API的Java开发人员,我们经常遇到这个问题。当我看到这篇文章时,我再次确认了我自己的怀疑,但我有一个冗长的解决方法:

// class name is awful for this example, but it will make more sense if you
//  read further
public interface MetaDataKey<T extends Serializable> extends Serializable
{
    T getValue();
}

public final class TypeSafeKeys
{
    static enum StringKeys implements MetaDataKey<String>
    {
        A1("key1");

        private final String value;

        StringKeys(String value) { this.value = value; }

        @Override
        public String getValue() { return value; }
    }

    static enum IntegerKeys implements MetaDataKey<Integer>
    {
        A2(0);

        private final Integer value;

        IntegerKeys (Integer value) { this.value = value; }

        @Override
        public Integer getValue() { return value; }
    }

    public static final MetaDataKey<String> A1 = StringKeys.A1;
    public static final MetaDataKey<Integer> A2 = IntegerKeys.A2;
}
请注意,每个实例都使用匿名实现,但不需要其他任何东西来实现它,因此
{}
是空的。这既令人困惑又令人恼火,但如果实例引用更可取,并且混乱程度保持在最低限度,那么它就可以工作,尽管对于经验较少的Java开发人员来说,这可能有点神秘,从而使其更难维护

最后,提供全球独特性和重新分配的唯一方法是对正在发生的事情更具创造性。我所看到的全局共享接口最常见的用途是元数据存储桶,它倾向于混合许多不同的值和不同的类型(基于每个键的
T
):

公共接口MetaDataKey扩展了可序列化
{
类getType();
字符串getName();
}
公共最终类类型安全密钥
{
公共静态枚举StringKeys实现MetaDataKey
{
A1;
@凌驾
公共类getType(){return String.Class;}
@凌驾
公共字符串getName()
{
返回getDeclaringClass().getName()+“+name();
}
}
公共静态枚举整数键实现MetaDataKey
{
A2;
@凌驾
公共类getType(){return Integer.Class;}
@凌驾
公共字符串getName()
{
返回getDeclaringClass().getName()+“+name();
}
}
公共静态最终元数据键A1=StringKeys.A1;
公共静态最终元数据键A2=IntegerKeys.A2;
}
这提供了与第一个选项相同的灵活性,并且提供了一种通过反射获得引用的机制(如果以后需要),因此避免了以后需要实例化。它还避免了第一个选项提供的许多容易出错的复制/粘贴错误,因为如果第一个方法错误,它将不会编译,而第二个方法不需要更改。唯一需要注意的是,您应该确保以这种方式使用的
enum
s是
public
,以避免任何人因为无法访问内部
enum
而出现访问错误;如果您不想让这些
MetaDataKey
穿过封送连接,则可以使用对外部包隐藏它们来自动丢弃它们(在封送期间,反射性地检查
enum
是否可访问,如果不可访问,则忽略键/值)。如果维护了更明显的
静态
引用(因为
枚举
实例就是这样),那么将其公开除了提供两种访问实例的方法外,没有任何好处或损失

我只是希望他们能够这样做,以便
enum
s能够扩展Java中的对象。也许在Java9中

最后一个选项并不能真正解决您的需求,因为您要求的是值,但我怀疑这会达到实际目标。

如果您被接受,那么您将能够使用如下语法(取自提案):

enum原语{
INT(Integer.class,0){
intmod(intx,inty){返回x%y;}
intadd(intx,inty){返回x+y;}
},
浮动(FLOAT.class,0f){
长加法(长x,长y){返回x+y;}
}, ... ;
最后一节课,最后一节课;
最终X值;
基元(类boxClass,X默认值){
this.boxClass=boxClass;
this.defaultValue=defaultValue;
}
}

使用此Java注释处理器,您可以编写以下内容:

import org.cmoine.genericEnums.GenericEnum;
导入org.cmoine.genericEnums.GenericEnumParam;
@通用数
公共枚举B实现了一个{
A1(字符串类,“值”),A2(整数类,0);
@通用货币
私人最终目的价值;
B(类clazz,@GenericEnumParam对象值){
这个值=值;
}
@通用货币
@凌驾
公共对象getValue(){
返回值;
}
}
注释处理器将生成一个enum
BExt
,其中包含您需要的所有内容

如果愿意,也可以使用以下语法:

import org.cmoine.genericEnums.GenericEnum;
导入org.cmoine.genericEnums.GenericEnumParam;
@通用数
公共枚举B实现了一个{
A1(字符串类){
@凌驾
public@GenericEnumParam对象getValue(){
返回“值”;
}
},A2(国际级){
@凌驾
public@GenericEnumParam对象getValue(){
返回0;
}
};
B(课堂){
}
@凌驾
公共摘要@GenericEnumParam Obje
public abstract class BasicMetaDataKey<T extends Serializable>
     implements MetaDataKey<T>
{
    private final T value;

    public BasicMetaDataKey(T value)
    {
        this.value = value;
    }

    @Override
    public T getValue()
    {
        return value;
    }

    // @Override equals
    // @Override hashCode
}

public final class TypeSafeKeys
{
    public static final MetaDataKey<String> A1 =
        new BasicMetaDataKey<String>("value") {};
    public static final MetaDataKey<Integer> A2 =
        new BasicMetaDataKey<Integer>(0) {};
}
public interface MetaDataKey<T extends Serializable> extends Serializable
{
    Class<T> getType();
    String getName();
}

public final class TypeSafeKeys
{
    public static enum StringKeys implements MetaDataKey<String>
    {
        A1;

        @Override
        public Class<String> getType() { return String.class; }

        @Override
        public String getName()
        {
            return getDeclaringClass().getName() + "." + name();
        }
    }

    public static enum IntegerKeys implements MetaDataKey<Integer>
    {
        A2;

        @Override
        public Class<Integer> getType() { return Integer.class; }

        @Override
        public String getName()
        {
            return getDeclaringClass().getName() + "." + name();
        }
    }

    public static final MetaDataKey<String> A1 = StringKeys.A1;
    public static final MetaDataKey<Integer> A2 = IntegerKeys.A2;
}
enum Primitive<X> {
    INT<Integer>(Integer.class, 0) {
        int mod(int x, int y) { return x % y; }
        int add(int x, int y) { return x + y; }
    },
    FLOAT<Float>(Float.class, 0f)  {
        long add(long x, long y) { return x + y; }
    }, ... ;

    final Class<X> boxClass;
    final X defaultValue;

    Primitive(Class<X> boxClass, X defaultValue) {
        this.boxClass = boxClass;
        this.defaultValue = defaultValue;
    }
}