My goal is pretty simple. I've a SetInterface<T>
:
public interface SetInterface<T>
{
public T duplicateSet();
}
I then also have an ExerciseInterface <T extends SetInterface<?>>
public interface ExerciseInterface <T extends SetInterface<?>>
{
public T getSet(int pos);
public void addSet(T set);
}
Everything works great up to this point.
The problem comes where I try to create a Generic Collection containing different classes which all implement the ExerciseInterface.
I am fairly new to Generics and I keep thinking I have solved something but all I am doing is pushing the error about.
The problem is pretty much summed by my addA()
and addB()
methods
public class Workout {
private String name;
private List <? extends ExerciseInterface<SetInterface<?>>> exerciseList;
// Constructor
public Workout(String name)
{
this.name = name;
exerciseList = new ArrayList<ExerciseInterface<SetInterface<?>>>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addExerciseA(ExerciseInterface<SetInterface<?>> exercise {
exerciseList.add(exercise);
}
public <T extends ExerciseInterface<SetInterface<?>>> void addExerciseB(T exercise {
exerciseList.add(exercise);
}
public ExerciseInterface<SetInterface<?>> getExercise(int pos) {
return exerciseList.get(pos);
}
}
The first add()
gives the following error..
The method add(capture#2-of ? extends ExerciseInterface<SetInterface<?>>) in the type List<capture#2-of ? extends ExerciseInterface<SetInterface<?>>> is not applicable for the arguments (ExerciseInterface<SetInterface<?>>)
The second add()
gives this error..
The method add(capture#2-of ? extends ExerciseInterface<SetInterface<?>>) in the type List<capture#2-of ? extends ExerciseInterface<SetInterface<?>>> is not applicable for the arguments (ExerciseInterface<SetInterface<?>>)
Just to reiterate, I have a SetInterface that different types of Sets implement.
I also have different exercises which mirror the Sets. For example:
BodyWeightExercise implements <SetInterface<BodyweightSet>>
and
WeightsExercise implements <SetInterface<WeightsSet>>
So my goal is to have a Collection of different exercises and a method that allows me to add to that collection.
Any help would be sincerely appreciated, I have lost a few hairs to this already.
Cheers.
EDIT: If this is not doable any pointers in a more feasible direction would be just appreciated.
EDIT2: I changed the List to List <ExerciseInterface<SetInterface<?>>> exerciseList;
and the error on the add() methods both dissappear.
However, using this test code..
WeightsSet weightsSet = new WeightsSet();
WeightsExercise weightsExercise = new WeightsExercise();
weightsExercise.addSet(weightsSet);
Workout workout = new Workout("Wok");
workout.addExerciseA(weightsExercise); <-- ERROR
I am trying to add a WeightsExercise to Workout's List, but I get this error now..
Bound mismatch: The generic method addExerciseB(T) of type Workout is not applicable for the arguments (WeightsExercise). The inferred type WeightsExercise is not a valid substitute for the bounded parameter <T extends ExerciseInterface<SetInterface<?>>>
EDIT 3: Example classes extending ExerciseInterface and SetInterface (Concrete methods update in the interfaces above as well)
public class WeightsExercise implements ExerciseInterface<SetInterface<WeightsSet>>
{
@Override
public SetInterface<WeightsSet> getSet(int pos) {return null;}
@Override
public void addSet(SetInterface<WeightsSet> set) {}
}
public class WeightsSet implements SetInterface<WeightsSet>
{
@Override
public WeightsSet duplicateSet() {return null;}
}
SOLVED: This solution seems to encompass everything correctly.
public class Workout
{
private String name;
private List <ExerciseInterface<? extends SetInterface<?>>> exerciseList;
// Constructor
public Workout(String name)
{
this.name = name;
exerciseList = new ArrayList<ExerciseInterface<? extends SetInterface<?>>>();
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public void addExerciseA(ExerciseInterface<? extends SetInterface<?>> exercise) {exerciseList.add(exercise);}
public ExerciseInterface<? extends SetInterface<?>> getExercise(int pos) {return exerciseList.get(pos);}
}
You should change your list declaration to:
When you use upper bounded wildcards, which I don't think you really need here, you can't add anything to the list, apart from
null
, and elements previously fetched from it.That's because, you don't know exactly what concrete parameterized type of list it actually references. For e.g.:
List<? extends CharSequence>
can reference aArrayList<String>
orArrayList<StringBuffer>
. So, you can't add anything to that list, because it's not type safe. You might possibly be adding aStringBuffer
object toArrayList<String>
, that will fail at runtime.After update:
I guess you are trying to create a parallel class hierarchy, and got messed up in that. Perhaps, you wanted your
ExerciseInterface
to look like:and then your class
WeightsExercise
would be modified as such:You would also need to make your
Workout
class generic like this:Then replace all occurrence of
ExerciseInterface<SetInterface<?>>
withExerciseInterface<U>
in yourWorkout
class.And create the instance of
Workout
like this:This will what make a correct design IMO.
Recommended post:
References: