【问题标题】:using wildcards in java method overrides在 java 方法覆盖中使用通配符
【发布时间】:2014-01-21 07:32:27
【问题描述】:

大多数泛型和通配符的示例都涉及集合,但我正在尝试学习如何仅将它们与类一起使用。我想学习这种更现代的泛型方法,这样我就可以避免子类覆盖超类中的方法时出现的尴尬强制转换。

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

这是 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 子类的参数。

然后我创建了我的 Score for 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 来使代码工作,但我希望了解如何/是否可以使用泛型来完成。我真的很想更彻底地了解泛型。

感谢您的帮助。

【问题讨论】:

  • 你做错了。您很可能想要&lt;T extends Level&gt; boolean isWin(T level) 之类的东西。

标签: java generics inheritance wildcard overriding


【解决方案1】:

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

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

表示您的方法采用 Class 具有 TypeScore 或某个子类。所以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) 方法。

【讨论】:

    【解决方案2】:

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

    然而,在您的类MastermindScore 中,您使用MastermindScoreMastermindLevel 类型作为方法参数。那是行不通的,因为类型和超类中的不一样,而且MastermindScore不是Class&lt;? extends Score&gt;的子类等等。

    改为这样做:

    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.
    }
    

    【讨论】:

    • 谢谢,杰斯珀。它现在可以编译,尽管我收到警告:games.Score is a raw type. References to generic type games.Score&lt;S,L&gt; should be parameterized 你能帮我理解这里的概念吗?我很感激。
    • 这是因为ScoreS, L 中的泛型类型,而equals 方法采用没有泛型类型的Score - rawtype。由于这个原因,这种方法有点缺陷。在任何情况下,如果您想覆盖 equals 方法,equals 应该采用 Object
    • 实际上,警告出现在超类public abstract class Score&lt;S extends Score, L extends Level&gt;{ 的类声明行上覆盖该方法。我只是使用名称 equals 因为它很好地描述了我想要的东西,看看一个分数是否与另一个分数相同。
    • @NinaKoch 原因是一样的——Score 是参数化的,而声明不是。特别是在S extends Score 中使用Score
    猜你喜欢
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 2018-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多