在Java中将泛型类型与枚举关联

在Java中将泛型类型与枚举关联,java,generics,enums,Java,Generics,Enums,我正在为用户首选项创建一个存储,用户可以为固定数量的首选项设置值。首选项(设置)的名称存储为枚举: public enum UserSettingName { FOO, BAR, ETC } 我希望能够使用名称存储一个值类型,以便服务使用正确的Java类型存储用户的值。例如,FOO可能是长的,而BAR可能是字符串。到目前为止,我们将所有值存储为Strings,然后手动将值转换为适当的Java类型。当服务中只有一个try/catch时,这会导致到处出现try/catc

我正在为用户首选项创建一个存储,用户可以为固定数量的首选项设置值。首选项(设置)的名称存储为枚举:

public enum UserSettingName {

    FOO,
    BAR,
    ETC

}
我希望能够使用名称存储一个值类型,以便服务使用正确的Java类型存储用户的值。例如,FOO可能是
长的
,而BAR可能是
字符串
。到目前为止,我们将所有值存储为
String
s,然后手动将值转换为适当的Java类型。当服务中只有一个try/catch时,这会导致到处出现try/catch块。我知道枚举不能有泛型类型,所以我一直在玩弄:

public enum UserSettingName {

    FOO(Long.class),
    BAR(String.class),
    ETC(Baz.class)

    private Class type;

    private UserSettingName(Class type) {
        this.type = type;
    }

    public Class getType() {
        return this.type;
    }
}
我有一个通用的UserSetting对象,它有
public T getSettingValue()
public void setSettingValue(T value)
方法,这些方法应该返回并设置正确类型的值。我的问题来自于在创建或检索设置时尝试指定泛型类型
T
,因为我无法执行以下操作:

new UserSetting<UserSettingName.FOO.getType()>(UserSettingName.FOO, 123L)
newusersetting(UserSettingName.FOO,123L)
对不起,如果这不是很清楚,我可以尝试澄清,如果它不明白

谢谢

更新

设置名称和值都来自Spring MVC REST调用:

public ResponseEntity<String> save(@PathVariable Long userId, @PathVariable UserSettingName settingName, @RequestBody String settingValue)
public ResponseEntity save(@PathVariable-Long-userId、@PathVariable-usersetingName-setingName、@RequestBody-String-setingValue)

所以我使用了枚举,因为Spring会自动强制转换传入的数据。

看看netty是如何做到的:

他们通过使用类型化常量来实现:

编辑:

公共接口ChannelConfig{
...
布尔设置选项(通道选项,T值);
...
}
公共类频道选项。。。
公共静态最终通道选项SO\U超时=
新通道选项(“SO_超时”);
...
}
编辑2:您可以将其转换为:

class Baz {}

class UserSettingName<T> {
    public static final UserSettingName<Baz> ETC = new UserSettingName<Baz>();
}

class UserSetting {
    public <T> UserSetting(UserSettingName<T> name, T param) {

    }
}

public class Test {
    public static void main(String[] args) {
        new UserSetting(UserSettingName.ETC, new Baz());
    }
}
类Baz{}
类UserSettingName{
public static final UserSettingName ETC=new UserSettingName();
}
类用户设置{
公共用户设置(UserSettingName名称,T参数){
}
}
公开课考试{
公共静态void main(字符串[]args){
新的UserSetting(UserSettingName.ETC,new Baz());
}
}

首先,您必须后退一步,思考您要实现的目标,并使用标准模式或语言结构来实现它

现在还不完全清楚您在追求什么,但从您的方法来看,几乎可以肯定您正在重新发明一些可以用Java以更直接的方式完成的东西。例如,如果您真的需要了解和处理对象的运行时类,请考虑使用反射API。
在更实际的层面上,您在这里尝试的是泛型不可能实现的。泛型是编译时语言的一个特性——它们有助于避免从对象显式转换所有内容,并在编译时为您提供类型检查。您不能以这种方式使用泛型,即将
T
设置为某个值
UserSettingName.Foo.getType()
,该值仅在运行时已知。

枚举不是这里的答案。如果您发现自己在任何地方重复代码,您可以创建一个实用程序类,并在那里封装所有try/catch逻辑。这将减少代码冗余,而不会严重影响当前代码

public class Util
{
    public static MyObject getObjectFromString(String s)
    {
        try
        {
            return (MyObject)s;
        }
        catch(Exception e)
        {
            return null;
        }
    }
}
然后按如下方式使用:

MyObject myObj = Util.getObjectFromString(string);

我看不出你的链接如何回答这个问题。您能解释一下吗?@tom:如果可以使用静态最终字段而不是枚举,那么每个值都可以有一个与之关联的通用声明类型,遵循您在他提供的链接中的
ChannelOption
类中看到的模式。您能为这个答案添加一个相关的代码示例吗?实际上,它几乎只有几个链接。我唯一的问题是,直到运行时我才知道类型。因此,在第二次编辑中,我必须基于字符串解释类型,然后查找UserSettingName。数据来自REST调用:
public ResponseEntity save(@PathVariable Long userId、@PathVariable UserSettingName settingName、@RequestBody String settingValue)
这适用于Spring,因为它将字符串强制转换为引擎盖下的枚举,但是我必须使用一个原始字符串,我认为这是行不通的,因为直到运行时才知道类型。这一次我可能得反思一下。谢谢您的帮助。使用
enum
对您来说有多重要?如果您可以使用
静态final
字段,那么有一个相当简单的答案。@StriplingWarrior这并不重要,但它会减少代码,因为Spring MVC会自动强制转换到枚举。我将在我的问题中添加代码我完全同意这一点,并且想进一步补充的是,枚举通常不应该像OP中那样使用。基本上,枚举是一组用户定义的抽象(不是编码意义上的)类型,应该用来区分不同的场景。例如,如果您要规划您的生活,您可以使用一个枚举,该枚举包含从星期一到星期日的周数,然后可以使用该枚举来确定您是否可以睡多久。更好的例子是使用枚举为简单的自制(UDP)消息解析器指定消息类型。
MyObject myObj = Util.getObjectFromString(string);