在Java枚举中如何避免重复项

4

我有一个Java类中的以下enum

public enum Resolution {
    RES_32 (32),
    RES_64 (64);
    private final int asInt;
    private Resolution(int asInt) {
        this.asInt = asInt;
    }
};

我有更多需要类似的枚举,具有相同的asInt属性和相同的构造函数,但是具有不同的常量。因此,在另一个类中,我需要以下枚举

public enum Resolution {
    RES_32 (32),
    RES_64 (64),
    RES_128 (128);
    private final int asInt;
    private Resolution(int asInt) {
        this.asInt = asInt;
    }
};

如果这是一个类,我可以使用继承来避免在构造函数中重复代码(并且可能已经为那个asInt属性创建了getter)。每当我需要这样的Resolution enum时,我该怎么做才能停止重复自己?理想情况下,我希望只需指定每个Resolution的常量,并保留构造函数和属性。
4个回答

8

EnumSet 在这种情况下可能会有所帮助。给定以下内容,

public enum Resolution {

    RES_32(32),
    RES_64(64),
    RES_128(128),
    RES_256(256);

    public static Set<Resolution> deluxe = EnumSet.allOf(Resolution.class);
    public static Set<Resolution> typical = EnumSet.range(RES_64, RES_128);
    public static Set<Resolution> ecomomy = EnumSet.of(RES_32);

    private final int asInt;

    private Resolution(int asInt) {
        this.asInt = asInt;
    }
};

适当命名的集合可如下使用。
for (Resolution r : Resolution.deluxe) {
    System.out.println(r.asInt);
}

更新以反映对接口优于实现的偏好。 - trashgod

3
为什么不将枚举从类中取出来,创建一个独立的枚举文件,只使用第二个枚举(带有RES_128)进行所有处理?
编辑1: 你的评论:
因为并非所有类都应该具有相同的常量。有些只需要32和64,而另一些则需要32、64和128。
实际上只有一种分辨率 "类型",这表明应该只有一个分辨率枚举,但问题似乎在于并非所有类都接受所有分辨率。一种可能的解决方案是使用一个枚举来表示所有分辨率,但对于不同的类使用EnumMap,其中一些类标记分辨率为false或表示该类无效。
编辑2:甚至只需拥有已接受枚举的HashSet。
编辑3:例如,使用HashSet。
class Foo002 {
   public static Set<Resolution> allowedResolution = new HashSet<Resolution>();
   static {
      allowedResolution.add(Resolution.RES_32);
      allowedResolution.add(Resolution.RES_64);
   }
   private Resolution resolution;

   public void setResolution(Resolution resolution) {
      if (!(allowedResolution.contains(resolution))) {
         throw new IllegalArgumentException("Disallowed Resolution: " + resolution);
      }
      this.resolution = resolution;
   }
}

enum Resolution {
   RES_32 (32),
   RES_64 (64),
   RES_128 (128);
   private final int asInt;
   private Resolution(int asInt) {
       this.asInt = asInt;
   }

   public int getIntValue() {
      return asInt;
   }
};

因为并不是所有的类都应该有相同的常量。有些只需要32和64,而另一些则需要32、64 128。 - rid
@Radu:请查看上面的编辑1。 - Hovercraft Full Of Eels
@Radu: 你能给我一个例子吗?:“这留给读者作为练习”。但说真的,这并不难,而且非常类似于哈希映射。 - Hovercraft Full Of Eels
气垫船满是鳗鱼: 啊,现在我明白你的意思了,感谢澄清。 - rid
使用enum的原因之一是可以立即知道方法可以接受哪些值。如果这样做,这种优势将消失,用户需要猜测或阅读文档或源代码才能找出他们可以传递什么以及不能传递什么,这并不比将int作为参数并进行记录更好。所以,如果这是唯一的方法,那么我可能必须寻找不同的解决方案。还是感谢您指出这一点。 - rid
显示剩余2条评论

2

我会将新值添加到原始枚举中,并让新类重复使用它。为什么它们不能调用你发布的第一个函数?如果您复制并扩展第一个函数,那么您将面临更大的问题。


因为此枚举代表了所有可能的“分辨率”。对于一个类,您只能有RES_32RES_64,而对于其他类,您也可以有RES_128 - rid
1
重复使用枚举并让每个类强制执行自己的不变量。 - duffymo
1+没错。常量对所有人都是相同的,只是允许使用的内容不同。 - Hovercraft Full Of Eels

0
以下内容让您在运行时处理枚举,这是参考链接http://www.theserverside.com/news/thread.tss?thread_id=50190
Constructor con = Day.class.getDeclaredConstructors()[0]; 
Method[] methods = con.getClass().getDeclaredMethods(); 
for (Method m : methods) 
{ 
    if (m.getName().equals("acquireConstructorAccessor")) 
    { 
        m.setAccessible(true); 
        m.invoke(con, new Object[0]); 
    } 
}

Field[] fields = con.getClass().getDeclaredFields(); 
Object ca = null; 
for (Field f : fields) 
{ 
    if (f.getName().equals("constructorAccessor")) 
    { 
        f.setAccessible(true); 
        ca = f.get(con); 
    } 
}

Method m = ca.getClass().getMethod( "newInstance", new Class[] { Object[].class }); 
m.setAccessible(true); 
Day v = (Day) m.invoke(ca, new Object[] { new Object[] { "VACATION", Integer.MAX_VALUE } }); 
System.out.println(v.getClass() + ":" + v.name() + ":" + v.ordinal());

这听起来像是一个危险的修补,现在可能有效,但如果JVM更改则会失败。如果您想要一个可变实例集合,最好使用类。 - Hovercraft Full Of Eels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接