在java方法覆盖中使用通配符

时间:2014-01-03 15:21:35

标签: java generics inheritance wildcard override

泛型和通配符的大多数示例涉及集合,但我正在尝试学习如何仅使用类来使用它们。我想学习这种更现代的泛型方法,这样我就可以避免当子类重写超类中的方法时出现的笨拙的转换。

我有一个猜测游戏的抽象类,可能用于数字猜谜游戏,猜词游戏,甚至是Mastermind。游戏包中包含Level和Score的抽象类。然后,我想将猜测游戏子类化,并将级别和分数子类化,以制作特定的游戏。

以下是分数的抽象类:

// a score is a measure of how close a guess is to being correct
public abstract class Score{

    public abstract boolean equals(Class<? extends Score> otherScore);

    public abstract boolean isWin(Class<? extends Level> level);

}

在编写isWin的参数时,我试图说:期望获得一个Level或Level子类的参数。

然后我创建了分数为Mastermind的子类:

public class MastermindScore extends games.Score{
    int numRightPlace;
    int numWrongPlace;


    public MastermindScore(int numRightPlace, int numWrongPlace){
            this.numRightPlace = numRightPlace;
            this.numWrongPlace = numWrongPlace;
    }

    public boolean equals(MastermindScore otherScore){
            if (this.numRightPlace==otherScore.numRightPlace){
                    if (this.numWrongPlace == otherScore.numWrongPlace){
                            return true;
                    }
            }
            return false;
    }

    public boolean isWin(MastermindLevel level){
            return this.numRightPlace == level.numSlots;
    }

这不能编译,因为它认为我没有正确地覆盖抽象超类所需的方法。因此,即使子类'isWin方法的参数是Level的子类,它也不会将其识别为期望的类型。

然后我将Level的子类的类声明行更改为:

public class MastermindLevel<T extends games.Level>{

    public final int numColors;
    public final int numSlots;


    public MastermindLevel(int numColors, int numSlots, int maxGuesses){
            super(maxGuesses);
            this.numColors = numColors;
            this.numSlots = numSlots;
    }
}

但是,当我这样做时,对超类构造函数的调用不起作用,因为它认为我的类是Object的子类,而不是Level的子类。

我知道我可以通过使用超类的参数编写重写方法,然后将Level和Score转换为MastermindLevel和MastermindScore来获取代码,但我希望了解如何使用泛型来完成此操作。我真的想更全​​面地理解泛型。

感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

请注意,在抽象类Score中,您的方法正在接受java.lang.Class对象。

但是,在您的班级MastermindScore中,您使用类型MastermindScoreMastermindLevel作为方法参数。这不会起作用,因为类型与超类中的类型不同,MastermindScore不是Class<? extends Score>等的子类。

做这样的事情:

public abstract class Score<S extends Score, L extends Level> {

    public abstract boolean equals(S otherScore);

    public abstract boolean isWin(L level);
}

public class MastermindScore extends Score<MastermindScore, MastermindLevel> {

    public boolean equals(MastermindScore otherScore) {
        // ...
    }

    // etc.
}

答案 1 :(得分:2)

你不能这样做,你的方法声明:

public abstract boolean isWin(Class<? extends Level> level);

表示您的方法需要Class Type Score或某个子类。所以Score.class可以作为参数。即你要求Class不是它的实例。

所以你真正想要的是:

public abstract<L extends Level> boolean isWin(L level);

这是一种通用方法。但这并没有真正增加你的代码,因为当你使用L时,所有编译器都可以说LLevel - 你仍然需要强制转换。

所以你真正需要的是通用interface

public interface Score<L> {

    boolean isWin(L level);    
}

当你创建其他实现时,你会这样做:

public class MastermindScore implements Score<MastermindLevel> {

你需要一个方法:

boolean isWin(MastermindLevel level);

显然MastermindLevel需要extends Level

另请注意,equals已实施为equals(Object other),因此必须强制转换。你不应该有equals(MyType other)方法。