16

I have an enum

public enum Days {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY 

}

I want to make a class which can take values of type Days. So I used Java Generics

public class State<T extend Days>

But there is an error

The type parameter T should not be bounded by the final type Days. 
Final types cannot be further extended

How can I resolve this?

5 Answers 5

10

Don't use a generics bound. There's no need. Just use an unbounded type, like this:

public class State<T> {
    public State(T startState) {
        // whatever
    } 
}

And to use it:

State<Days> dayState = new State<>(Days.SUNDAY);

This is a straightforward typed class that doesn't need a bound.

The only bound that might make sense is a bound to an enum:

public class State<T extends Enum<T>> {
    public State(T startState) {
        // whatever
    } 
} 

This version requires that the generic parameter be an enum. With this version the above usage example would still compile, but this would not compile (for example):

State<String> dayState = new State<>("hello");

because String is not an enum.

Sign up to request clarification or add additional context in comments.

5 Comments

That's not what the OP wants. OP wants to accept only Days, not anything at all or any enum. Not only he doesn't need a generics bound to do that, he doesn't need to use generics at all.
@Malcolm Well, he can use generics for his State class (as per my code). He just doesn't need the generic to be bounded. I see what you mean, but he could make his class generic - it seem like a handy class to have that deal with initial/current state
It doesn't serve the purpose the OP specified. He needs a class which operates on Days or its children: I want to make a class which can take values of type days. Since there are no children for any enum, he should write Days explicitly. Your code doesn't limit the values to Days.
It was useful to know that enums are final and therefore cannot be extended.
Also, you can do a few things to fix your problem: 1. Don't make State generic. Just use Days. 2. If you're going to define methods on Days, create an interface that Days implements. e.g. Days implements IDays; and class State<T extends IDays>; 3. Do as Bohemian suggests and use State<T extends Enum<T>>;
9

enums are final types, which means, you can not extend from them

a generic like wants a Class as Parameter which is Days or an extended class, but the extended class is not possible

so the only parameter possible is Days and you don't need a generic, if only one value is possible

2 Comments

-1 You are missing the point here. Any type is possible - it's a generic state class.
@Bohemian No, I think it is you who misses the point. See the comment to your answer.
5

You cannot extend enums in java (http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html towards the end). Thus is not possible.

-IF you need your class to work only with your enum you don't need generics

-if instead you need it to work with others enum (does it makes sense?) you don't need to specify the extend.

What does exactly your State class do ?

Comments

5

The thing to do here is

public enum Days{..}

public class State { // no generic argument!
  ...
}

As it stands, you can't have State<T extends Days> because the only way to satisfy T extends Days is to have T be Days. That's what it means for Days to be final.

So instead, you should make State not generic, and use Days directly everywhere you were trying to use T. You can't declare public class State<Days>, because then it'll try to treat Days as a type variable, not as the class Days, and that's not what you want.

Comments

2

This compiles fine for me under Java 6:

public enum Days {
  SUNDAY, 
  MONDAY, 
  TUESDAY, 
  WEDNESDAY,
  THURSDAY, 
  FRIDAY, 
  SATURDAY
}

public class State<T extends Days> {
  T state;

  public State(T startState) {
    this.state = startState;
  }
}

private void test() {
  State<Days> state = new State<Days> (Days.MONDAY);
}

However, if you want your State object to change from one enum to another you would be better to use something like:

public class State<S extends Enum<S>> {
  final ArrayList<S> states = new ArrayList<S>();
  private S state;

  public State(S startState) {
    states.addAll(EnumSet.allOf(startState.getClass()));
    this.state = startState;
  }

  public S next() {
    return state = states.get((state.ordinal() + 1) % states.size());
  }

  public S prev() {
    return state = states.get((state.ordinal() - 1 + states.size()) % states.size());
  }

  public S set(S newState) {
    return state = newState;
  }

  public S get() {
    return state;
  }
}

private void test() {
  State<Days> state = new State<Days> (Days.MONDAY);
  // ...
}

6 Comments

this.states = (S[])states.toArray(); throws a ClassCastException! I am working on a solution.
Fixed the ClassCastException issue!
@FBB - Yes but once you create a State<E> you can only ever use E states. set(F) will fail at compile time because F is not an E - this is the fundamental point of generics.
But this is useless, you can simply have a set(Days) method. See Louis Wasserman's answer.
@FBB - Agreed - but this does a next and prev for you.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.