我有两个实现通用接口的枚举。我试图声明界面,所以只有枚举才能实现它。
interface CommonEnumInterface<E extends Enum<?>> {
/** It doesn't matter what this does. */
E commonInterfaceMethod();
}
enum Enum1 implements CommonEnumInterface<Enum1> {
FOO,
BAR,
BAZ;
@Override
public Enum1 commonInterfaceMethod() {
return null;
}
}
enum Enum2 implements CommonEnumInterface<Enum2> {
BLAH,
YADDA,
RHUBARB;
@Override
public Enum2 commonInterfaceMethod() {
return Enum2.BLAH;
}
}
现在我想创建另一个枚举,其中每个常量都有自己的一组CommonEnumInterface
类型的元素,但不一定是同一个类。我发现的每一种方式都感觉像是一种黑客攻击,特别是对于我希望每个常量都用多组元素声明的情况。
这些评论显示了我的尝试。是否有更优雅的方式(编译)?
enum CreatingAnotherEnumAttempt {
// Type mismatch: cannot convert from List<Enum<?>&CommonEnumInterface<?>> to List<CommonEnumInterface<?>>
A(Arrays.asList(Enum1.FOO, Enum2.BLAH)),
// Cannot cast from List<Enum<?>&CommonEnumInterface<?>> to List<CommonEnumInterface<?>>
B((List<CommonEnumInterface<?>>) Arrays.asList(Enum1.FOO, Enum2.BLAH)),
// This works, but it generates type safety warnings, and it's hard to read.
C(Arrays.asList((CommonEnumInterface<?>) Enum1.FOO, (CommonEnumInterface<?>) Enum2.BLAH)),
// This is the best I've come up with.
D(getMixOfElements(Enum1.FOO, Enum2.BLAH));
/**
* I want to populate this set in the constructor.
*/
private final Set<CommonEnumInterface<?>> mixOfElements;
/**
* I tried declaring the Set this way, but wildcards can extend only one interface, so there's a syntax error at the ampersand.
*/
private final Set<? extends Enum<?> & CommonEnumInterface<?>> mixOfElements;
/**
* This is the constructor I'm trying to satisfy.
*
* @param mixOfElements I could make this a varargs parameter, but that only works for a single set of elements. What if I want more?
*/
private CreatingAnotherEnumAttempt(List<CommonEnumInterface<?>> mixOfElements) {
this.mixOfElements = Collections.unmodifiableSet(new HashSet<CommonEnumInterface<?>>(mixOfElements));
}
/**
* This method only exists to allow method {@link #D}. It's pretty pointless, otherwise.
*
* @param mixOfElements the mix of elements
* @return the mix of elements as a list
*/
private static List<CommonEnumInterface<?>> getMixOfElements(CommonEnumInterface<?>... mixOfElements) {
return Arrays.asList(mixOfElements);
}
/**
* This works without type safety warnings or superfluous methods, but for my constructor, I need a one-liner.
*/
private static void wayThatWorksInline() {
Collection<CommonEnumInterface<?>> inlineWay = new ArrayList<CommonEnumInterface<?>>();
inlineWay.add(Enum1.FOO);
inlineWay.add(Enum2.BLAH);
}
}
我的问题在上面,并在代码注释中。通常,这是声明我的界面的正确方法吗?
答案 0 :(得分:1)
涉及枚举的事实实际上是一种转移,因为简单地将List<CommonEnumInterface<?>>
传递给构造函数是您的目标。为此,请执行以下操作:
A(Arrays.<CommonEnumInterface<?>>asList(Enum1.FOO, Enum2.BLAH)),
//etc.
问题是类型推断 - 有时它会有点过于急切。根据参数Enum1.FOO
和Enum2.BLAH
到asList
,编译器为Enum<?>&CommonEnumInterface<?>
推断了T
,因此返回了List<Enum<?>&CommonEnumInterface<?>>
。自generics aren't covariant起,这不能分配给List<CommonEnumInterface<?>>
。指定T
的类型参数可以手动解决此问题。
答案 1 :(得分:-2)
我会尽力给这一点。您可以尝试使用动态类型。
List<CommonEnumInterface<dynamic>>
or
List<dynamic>
或者采用更加无声但干净的解决方案
public class MyEnums
{
List<Tuple<Enum, string>> myEnums;
public void addEnum(Enum Enum, string EnumName)
{
myEnums.Add(new Tuple<Enum, string>(Enum, EnumName));
}
public List<Tuple<Enum, string>> getEnums()
{
return myEnums;
}
public Enum getEnumByName(string EnumName)
{
return myEnums.Where(n => n.Item2 == EnumName).Select(n => n.Item1).FirstOrDefault();
}
}
或
public class myEnums
{
public dynamic s { get; set; }
}