在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);