Java - 泛型通配符问题

时间:2013-08-28 18:05:50

标签: java generics bounded-wildcard

我的目标非常简单。我有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的不同类的Generic Collection的地方。

我对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。

我也有不同的练习镜像集。例如:

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添加到Workout的列表中,但我现在收到此错误..

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);}

}

1 个答案:

答案 0 :(得分:2)

您应该将列表声明更改为:

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正确设计的原因。

<小时/> 推荐帖子:

<强>参考文献: