我的目标很简单。我有一个SetInterface<T>
:
public interface SetInterface<T>
{
public T duplicateSet();
}
然后,我还有一个
ExerciseInterface <T extends SetInterface<?>>
public interface ExerciseInterface <T extends SetInterface<?>>
{
public T getSet(int pos);
public void addSet(T set);
}
到目前为止,一切都很好。
问题出在哪里,我试图创建一个包含不同类的泛型集合,这些类都实现了ExerciseInterface。
我对Generics相当陌生,我一直认为自己已经解决了一些问题,但是我所做的只是推销错误。
我的
addA()
和addB()
方法几乎概括了这个问题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);
}
}
第一个
add()
给出以下错误。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<?>>)
第二个
add()
给出此错误。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<?>>)
重申一下,我有一个SetInterface,可以使用不同类型的Set来实现。
我也有不同的练习,可以反映出场景。例如:
BodyWeightExercise implements <SetInterface<BodyweightSet>>
和
WeightsExercise implements <SetInterface<WeightsSet>>
因此,我的目标是拥有一个不同练习的集合,以及一种使我能够添加到该集合中的方法。
任何帮助将由衷的感谢,我已经为此付出了一些努力。
干杯。
编辑:如果这不可行,那么朝着更可行方向的任何指针将不胜感激。
EDIT2:我将列表更改为
List <ExerciseInterface<SetInterface<?>>> exerciseList;
,并且add()方法上的错误都消失了。但是,使用此测试代码。
WeightsSet weightsSet = new WeightsSet();
WeightsExercise weightsExercise = new WeightsExercise();
weightsExercise.addSet(weightsSet);
Workout workout = new Workout("Wok");
workout.addExerciseA(weightsExercise); <-- ERROR
我正在尝试将WeightsExercise添加到“锻炼”列表中,但是现在出现此错误。
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<?>>>
编辑3:扩展了ExerciseInterface和SetInterface的示例类(具体方法也在上面的接口中更新)
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;}
}
解决:该解决方案似乎正确地包含了所有内容。
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);}
}
最佳答案
您应该将列表声明更改为:
List<ExerciseInterface<SetInterface<?>>> exerciseList;
当您使用上限通配符时(我认为这里并不需要),除了
null
和以前从中获取的元素之外,您无法向列表添加任何内容。这是因为,您不确切知道它实际引用的列表的具体参数化类型。例如:
List<? extends CharSequence>
可以引用ArrayList<String>
或ArrayList<StringBuffer>
。因此,您不能在该列表中添加任何内容,因为它的输入类型不安全。您可能正在向StringBuffer
添加ArrayList<String>
对象,该对象在运行时将失败。更新后:
我猜您正在尝试创建parallel class hierarchy,并且陷入困境。也许,您希望您的
ExerciseInterface
看起来像:// Notice the use of `T` in `SetInterface<T>` instead of `SetInterface<?>`
interface ExerciseInterface<T extends SetInterface<T>> {
SetInterface<T> getSet(int pos);
void addSet(SetInterface<T> set);
}
然后您的类
WeightsExercise
将被修改为:class WeightsExercise implements ExerciseInterface<WeightsSet> {
@Override
public SetInterface<WeightsSet> getSet(int pos) {return null;}
@Override
public void addSet(SetInterface<WeightsSet> set) {}
}
您还需要使您的
Workout
类通用,如下所示:public class Workout<U extends SetInterface<U>, T extends ExerciseInterface<U>> {
}
然后在
ExerciseInterface<SetInterface<?>>
类中将所有出现的ExerciseInterface<U>
替换为Workout
。并创建
Workout
的实例,如下所示:Workout<WeightsSet, WeightsExercise> workout = new Workout<>("Wok");
workout.addExerciseA(weightsExercise);
这将使IMO设计正确。
推荐职位:
What is a difference between <? super E> and <? extends E>?
What is PECS (Producer Extends Consumer Super)?
参考文献:
Java Generics FAQ - Angelika Langer
What is bounded Wildcards?
Do generics help designing parallel class hierarchies?