Reputation: 940
This is somewhat of a followup from a previous question I had.
Let's say I have an abstract parent class for animals. The same kind of animal can have different temperaments and can perform in different types of shows. So my animal definition looks something like this:
public abstract class Animal<T extends Temperament, S extends Show>{...}
I want to have trainers for various animals that are aware of the animal type, temperament, intended type of shows the animal is to perform in, AND defines a set of tricks the trainer can teach that animal. Because I want the set of tricks to be defined for a particular animal, I have an enum interface as follows:
public interface TrainingActions<T extends Animal<?,?>>{...}
Any enum that implements that interface defines a set of training actions for a particular animal regardless of its temperament and the shows it can perform in.
Keeping these in mind, my definition for the parent class of trainers is as follows:
public abstract class Trainer
<A extends Animal<?,?>,
E extends Enum<E> & TrainingActions<A>,
T extends Temperament,
S extends Show>{
...}
Now, I was trying to create a concrete trainer as follows but get an error:
public class DogTrainer
<T extends Temperament,
S extends Show> extends Trainer
<Dog<T,S>, DogTrainer.Trainables, T, S>{//error right here
public enum Trainables implements TrainingActions<Dog<?,?>>{
FETCH, GROWL, SIT, HEEL;
}
...
}
I'm getting the following error with trying to use DogTrainer.Trainables
as the parameters for Trainer
in my definition of DogTrainer
:
Bound mismatch: The type DogTrainer.Trainables is not a valid substitute
for the bounded parameter <E extends Enum<E> & TrainingActions<A>> of the type
Trainer<A,E,T,S>
Can someone help me understand what I'm doing wrong?
Upvotes: 1
Views: 92
Reputation: 298203
You have created an unsolvable problem by adding to much constraints into you generic signatures. Your current solution is too relaxed compared with your (assumed) intention. Look at the following declaration:
public abstract class Trainer
<A extends Animal<?,?>, // <- here you are not enforcing the right bounds
E extends Enum<E> & TrainingActions<A>,
T extends Temperament,
S extends Show>{
…
}
With this declaration you allow to pass an animal with the wrong Temperament
and Show
to a particular Trainer
instance. What you most probably want is:
public abstract class Trainer
<A extends Animal<T,S>,
E extends Enum<E> & TrainingActions<A>,
T extends Temperament,
S extends Show> {
…
}
But then, your solution does not work anymore. With this declaration you cannot create a DogTrainer
having type parameters for Temperament
and Show
without declaring the trained animal as Dog<T,S>
as it is intended since a Trainer
ought to train only animals with the right Temperament
and Show
(otherwise you don’t need to make them type parameters).
But if you declare the DogTrainer
as DogTrainer<T extends Temperament, S extends Show>
extends Trainer<Dog<T,S>, DogTrainer.Trainables, T, S>
you cannot specify your intended TrainingAction
as it does not have the right Temperament
and Show
and this is impossible to fix because you want the TrainingAction
to be an enum
. And enums
can only be declared either with wildcards like you did with enum Trainables implements TrainingActions<Dog<?,?>>
or with exactly one specific type. Inner enum
s are always static
and cannot refer to the outer classes type parameters.
So this is the combination of constraints summarized:
Trainer
has the parameters animal A
and temperament T
and show S
and training action E
A
should have the right T
and S
for a trainerE
should have the right A
for the trainerE
shall be an enum
T
and S
but a constant type for E
(as it is an enum
)This is impossible. You current solution ignores the constraint 2 but there’s no solution without removing at least one of the constrains
Upvotes: 1
Reputation: 940
Figured out the problem. My concrete trainer needed to be defined as follows:
public class DogTrainer
<T extends Temperament,
S extends Show> extends Trainer
<Dog<?,?>, DogTrainer.Trainables, T, S>{// changed line
public enum Trainables implements TrainingActions<Dog<?,?>>{
FETCH, GROWL, SIT, HEEL;
}
...
}
Upvotes: 0