Link to home
Start Free TrialLog in
Avatar of gmoniey
gmoniey

asked on

Using generics with enums

Hi, I have something like the following:


public interface EnumThing { }

public abstract class Parent extends EnumThingy> {
  public abstract void doSomething(E e);
}
 
public class Child extends Parent {
  enum BabyEnum implements EnumThingy {... }
  public void doSomething(BabyEnum e) { ... }
}



Now I have a completely seperate class, in a different package, that kinda looks like this:

public class MyObject {
private EnumThingy thingy;
...
public EnumThingy getThingy() { return thingy; }
}




now in some other class, I have the following:

Child.BabyEnum myEnum = myObject.getThingy();



obviously, this doesn't work, as I need the following cast:

Child.BabyEnum myEnum (Child.BabyEnum) myObject.getThingy();



My question is how can I use generics to elimiate the need for casts?

Thanks!
Avatar of aozarov
aozarov

changed MyObject to:
public class MyObject <T extends EnumThingy> {
private T thingy;

public void setThingy(T thingy)
{
      this.thingy = thingy;
}

public T getThingy() { return thingy; }
}

Make the "some other class" like this:
public class OtherClass {
      public static void main(String st[])
      {
            MyObject<Child.BabyEnum> myObject = new MyObject<Child.BabyEnum>();
              Child.BabyEnum myEnum = myObject.getThingy();
            
      }
Avatar of gmoniey

ASKER

Thanks, that worked. The sad part, is that I tried this, but my IDE marked it as an error. I never thought of compiling, which proved my IDE wrong. Thanks again!
NP :-)
Avatar of gmoniey

ASKER

Hi azoarov,

I guess I didn't figure it out completely, as I started integrating those changes into my code, I ran into the following problem.

I have a set of general classes, and a set of specific classes. So for example, in my general MainFrame class, I have an instance of MyObject, as such:

MyObject<EnumThing> myO = new MyObject<EnumThingy>;

Because as this point, I dont know what type of enum will be related to that object. Sometime later within the same class, I send the myO object as a parameter to a class with the following constructor:

public SpecificClass(MyObject<Child.BabyEnum> myObject) {
            super(myObject);
}

Now I run into an error on this line:

SpecificClass sf = new SpeficClass(myO); //this is from within my general MainFrame class.

the error says it cannot find the constructor for SpecificClass(MyObject<EnumThingy>)...

any ideas?

Thanks!
I see two problems here.
1. Such declaration "SpecificClass(MyObject<Child.BabyEnum> myObject)" says basically I only accept an argument of the type MyObject<Child.BabyEnum>
So you want to replace it with public <T extends Child.BabyEnum> SpecificClass(MyObject<T> myObject)  to accept any types
that extends Child.BabyEnum (and that leads to the second problem)
2. You are passing MyObject<EnumThingy> where EnumThingy is a parent of Child.BabyEnum. that is an OO problem (has nothing to
do with generics). You can't pass a parrent to an argument that expect its child (not without casting).

If you do:
public class SpecificClass
{
public <T extends EnumThingy> SpecificClass(MyObject<T> myObject) {
}
}

Then you will be able to pass the following:
public static void main(String st[])
{
      MyObject<EnumThingy> myO = new MyObject<EnumThingy>();
      MyObject<Child.BabyEnum> my1 = new MyObject<Child.BabyEnum>();
      SpecificClass sf1 = new SpecificClass(myO);
      SpecificClass sf2 = new SpecificClass(my1);
}

I suggest you to read this short article (the second part of it): http://java.sun.com/developer/JDCTechTips/2005/tt0104.html
Avatar of gmoniey

ASKER

Hi azozarov,

That article was helpful, but i'm still a little stuck, and it may be a result of my design. I have a common package, and a more specific app package. My MainFrame, and MyObject classes lie within my common package. I also have another class, say GeneralClass which is within the common package.

The general class looks something like this:

public abstract class GeneralClass<T extends EnumThingy> { ... }

then my SpecificClass, as mentioned above, really looks like this:

public class SpecificClass extends GeneralClass<Child.BabyEnum> { ... }

Sorry I didn't mention this all earlier. I didn't think it was relevant (I thought I just was having problems with enums & generics). Based on this design. I have myObject, inside a MainFrame class. Which looks as such:

MyObject<EnumThing> myO = new MyObject<EnumThingy>;  //I don't know which enum I will use yet

Depending on what the user chooses. the myObject is passed to the constructor of a SpecificClass (which can take any enum which implements EnumThingy). As such:

SpecificClass sf = new SpeficClass(myO); //pass myObject to the specific class, which already knows the enum it wants.


Thus the suggestion you provided doesn't work for this situation.



>> and a more specific app package
don't think it is relevant here (as long as EnumThingy is defined as public [as it seems]).

>> public class SpecificClass extends GeneralClass<Child.BabyEnum> { ... }
Why do you narrow the generic types that can be used with SpecificClass ?
Once you do this you will be able to construct GeneralClass only with Child.BabyEnum types.
If you need to construct it with new MyObject<EnumThingy> then don't narrow it (see my suggestion above).
Avatar of gmoniey

ASKER

Well, I initially decided to narrow it down, because that is the only type of enum I that class can accept, so to speak.
I have my abstract class, which defines all the methods, and then I have the child classes, and I want them to use only specific enums, which may or may not be the same as other child classes.

My dilemma with this approach, is of course, not knowing the enum when I instantiate the myObject variable. And that is where I am stuck. I have tried casting, but found that not possible. I guess I could create a clone method in MyObject, which I could define the enum type and then return an object which uses the generic of the enum I need to use. I was just hoping there would be a better way to do this.

I'm also open to any design suggestions you may have.
>>  because that is the only type of enum I that class can accept, so to speak.
Then why do you pass new MyObject<EnumThingy> and not new MyObject<Child.BabyEnum>

>> My dilemma with this approach, is of course, not knowing the enum when I instantiate the myObject variable
This were defining it as the parent type can help.

>>  I guess I could create a clone method in MyObject,
You can try also to downcast it (though -Xlint:unchecked will give you warning about it).
Avatar of gmoniey

ASKER

I tried to do the casting thing as such:

SpecificClass sf = new SpeficClass( (MyObject<Child.BabyEnum>) myO);

but i got a compile error. Am I doing the cast wrong?
ASKER CERTIFIED SOLUTION
Avatar of aozarov
aozarov

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of gmoniey

ASKER

Hi,

no I didnt change SpecificClass to: public class SpecificClass extends GeneralClass<T extends Child.BabyEnum>. I got an error about no constructor in GeneralClass.

However, your casting suggestion worked out. Not really the solution I was going for, but I guess it will work.