4

I have the following enum in a Java class:

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

I have more classes that need a similar kind of enum, with the same asInt property and the same constructor, but with different constants. So, in another class, I need the following enum:

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

If this was a class, I could use inheritance to not repeat the code in the constructor (and would likely have made a getter for that asInt property). What can I do in order to stop repeating myself each time I need such a Resolution enum? Ideally, I would like to just specify the constants for each Resolution, and to have the constructor and property kept.

rid
  • 61,078
  • 31
  • 152
  • 193

4 Answers4

8

EnumSet may be helpful in this context. Given the following,

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;
    }
};

Suitably named sets may be used as shown below.

for (Resolution r : Resolution.deluxe) {
    System.out.println(r.asInt);
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
3

Why not take the enums out of the class and create a stand-alone enum file that only use the second one (the one with RES_128) for all processing?

Edit 1
Your comment:

Because not all classes should have the same constants. Some need to have only 32 and 64, while others need to have 32, 64 and 128

There really is only one Resolution "type" and this suggests that there should be but one Resolution enum, but the problem appears to be that not all classes accept all resolutions. One possible solution is to use one enum to represent all resolutions, but have EnumMap for different classes, with some classes marking a resolution false or meaning not valid for that class.

Edit 2
Or even just have a HashSet of accepted enums.

Edit 3
e.g., using 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;
   }
};
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Because not all classes should have the same constants. Some need to have only 32 and 64, while others need to have 32, 64 *and* 128. – rid Jul 02 '11 at 19:39
  • @Radu: please see Edit 1 above. – Hovercraft Full Of Eels Jul 02 '11 at 19:43
  • Hovercraft Full Of Eels: sounds good, can you please give me an example? – rid Jul 02 '11 at 19:45
  • @Radu: `can you please give me an example?`: "that is left as an exercise for the reader". Seriously though it's not hard and is very similar to a hash map. – Hovercraft Full Of Eels Jul 02 '11 at 19:46
  • Hovercraft Full Of Eels: thank you anyway, but I have absolutely no clue how an `EnumMap` or `HashSet` can solve my problem, and searching doesn't help either. – rid Jul 02 '11 at 20:04
  • Hovercraft Full Of Eels: ah, now I understand what you mean, thanks for the clarification. – rid Jul 02 '11 at 20:17
  • One of the reasons for using `enum` in the first place is that it's immediately obvious what values the method can accept. By doing this, this advantage will disappear, and the user will need to guess or read the documentation or the source to find out what they can pass and what they can't, which is no better than simply having an `int` as parameter and documenting it. So, if this is the only way, then I'll probably have to look for a different solution. Thanks though for pointing this out. – rid Jul 02 '11 at 20:31
2

I would add the new value to the original enum and have the new classes just re-use it. Why can't they call the first one you posted? You have bigger issues than merely repeating a constructor if you copy and extend the first one.

duffymo
  • 305,152
  • 44
  • 369
  • 561
0

The following lets you work with enums on runtime, this is the reference link 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());
rid
  • 61,078
  • 31
  • 152
  • 193
AliDeo
  • 169
  • 6