不能与父子孙继承进行比较

发布于 2024-12-23 22:25:41 字数 1477 浏览 0 评论 0原文

给出以下代码:

public abstract class Participant {
    private String fullName;

    public Participant(String newFullName) {
        this.fullName = new String(newFullName);
    }

    // some more code 
}


public class Player extends Participant implements Comparable <Player> {    
    private int scoredGoals;

    public Player(String newFullName, int scored) {
        super(newFullName);
        this.scoredGoals = scored;
    }

    public int compareTo (Player otherPlayer) {
        Integer _scoredGoals = new Integer(this.scoredGoals);
        return _scoredGoals.compareTo(otherPlayer.getPlayerGoals());
    }

    // more irrelevant code 
}

public class Goalkeeper extends Player implements Comparable <Goalkeeper> { 
    private int missedGoals;        

    public Goalkeeper(String newFullName) {
        super(newFullName,0);
        missedGoals = 0;
    }

    public int compareTo (Goalkeeper otherGoalkeeper) {
        Integer _missedGoals = new Integer(this.missedGoals);
        return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
    }

    // more code 
}

问题是 Goalkeeper 不会遵守。

当我尝试编译该代码时,Eclipse 会抛出:

The interface Comparable cannot be implemented more than once with 
different arguments: Comparable<Player> and Comparable<Goalkeeper>

我不想与 Player 进行比较,而是与 Goalkeeper 进行比较,并且仅与他进行比较。

我做错了什么?

Given the following code :

public abstract class Participant {
    private String fullName;

    public Participant(String newFullName) {
        this.fullName = new String(newFullName);
    }

    // some more code 
}


public class Player extends Participant implements Comparable <Player> {    
    private int scoredGoals;

    public Player(String newFullName, int scored) {
        super(newFullName);
        this.scoredGoals = scored;
    }

    public int compareTo (Player otherPlayer) {
        Integer _scoredGoals = new Integer(this.scoredGoals);
        return _scoredGoals.compareTo(otherPlayer.getPlayerGoals());
    }

    // more irrelevant code 
}

public class Goalkeeper extends Player implements Comparable <Goalkeeper> { 
    private int missedGoals;        

    public Goalkeeper(String newFullName) {
        super(newFullName,0);
        missedGoals = 0;
    }

    public int compareTo (Goalkeeper otherGoalkeeper) {
        Integer _missedGoals = new Integer(this.missedGoals);
        return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
    }

    // more code 
}

The problem is that Goalkeeper won't complie.

When I try to compile that code the Eclipse throws:

The interface Comparable cannot be implemented more than once with 
different arguments: Comparable<Player> and Comparable<Goalkeeper>

I'm not trying to compare with Player, but with Goalkeeper, and only with him.

What am I doing wrong ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

美男兮 2024-12-30 22:25:41

Angelika Langer 的 泛型常见问题解答 #401 中描述了该问题:

一个类可以实现同一个泛型的不同实例化吗
接口?

不,类型不得直接或间接派生自
同一通用接口的两个不同实例。

原因
此限制是通过类型擦除进行翻译。键入后
删除同一通用接口的不同实例
折叠为相同的原始类型。运行时没有区别
不同实例之间不再存在。

(我强烈建议您查看问题的完整描述:它比我引用的内容更有趣。)

为了解决此限制,您可以尝试以下操作:

public class Player<E extends Player> extends Participant implements Comparable<E> {
    // ...
    public int compareTo(E otherPlayer) {
        Integer _scoredGoals = this.scoredGoals;
        return _scoredGoals.compareTo(otherPlayer.getPlayerGoals());
    }
    // ...
}


public class Goalkeeper extends Player<Goalkeeper> {
    // ...
    @Override
    public int compareTo(Goalkeeper otherGoalkeeper) {
        Integer _missedGoals = this.missedGoals;
        return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
    }
    // ...
}

The problem is described in Angelika Langer's Generics FAQ #401:

Can a class implement different instantiations of the same generic
interface?

No, a type must not directly or indirectly derive from
two different instantiations of the same generic interface.

The reason
for this restriction is the translation by type erasure. After type
erasure the different instantiations of the same generic interface
collapse to the same raw type. At runtime there is no distinction
between the different instantiations any longer.

(I highly recommend checking out the whole description of the problem: it's more interesting than what I've quoted.)

In order to work around this restriction, you can try the following:

public class Player<E extends Player> extends Participant implements Comparable<E> {
    // ...
    public int compareTo(E otherPlayer) {
        Integer _scoredGoals = this.scoredGoals;
        return _scoredGoals.compareTo(otherPlayer.getPlayerGoals());
    }
    // ...
}


public class Goalkeeper extends Player<Goalkeeper> {
    // ...
    @Override
    public int compareTo(Goalkeeper otherGoalkeeper) {
        Integer _missedGoals = this.missedGoals;
        return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
    }
    // ...
}
┊风居住的梦幻卍 2024-12-30 22:25:41

就您的设计逻辑而言,您没有做错任何事情。然而,Java 有一个限制,阻止您实现具有不同类型参数的相同泛型接口,这是由于它实现泛型的方式(通过类型擦除)造成的。

在您的代码中,Goalkeeper 继承自 Player 它的 Comparable 实现,并尝试添加一个 Comparable; 自己的;这是不允许的。

解决此限制的最简单方法是覆盖 Goalkeeper 中的 Comparable,将传入的玩家投射到 Goalkeeper,然后进行比较传给这个守门员。

编辑

public int compareTo (Player otherPlayer) {
    Goalkeeper otherGoalkeeper = (Goalkeeper)otherPlayer;
    Integer _missedGoals = new Integer(this.missedGoals);
    return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
}

As far as the logic of your design goes, you are not doing anything wrong. However, Java has a limitation that prevents you from implementing the same generic interface with different type parameters, which is due to the way it implements generics (through type erasure).

In your code, Goalkeeper inherits from Player its implementation of Comparable <Player>, and tries to add a Comparable <Goalkeeper> of its own; this is not allowed.

The simplest way to address this limitation is to override Comparable <Player> in the Goalkeeper, cast the player passed in to Goalkeeper, and compare it to this goalkeeper.

Edit

public int compareTo (Player otherPlayer) {
    Goalkeeper otherGoalkeeper = (Goalkeeper)otherPlayer;
    Integer _missedGoals = new Integer(this.missedGoals);
    return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
}
ぺ禁宫浮华殁 2024-12-30 22:25:41

我想在现有的好的答案的基础上补充两点。

  1. 即使您尝试过的设计是可行的,您也可能不想要它,这是有原因的。它有点蓬松。
  2. 除了谢尔盖·卡利尼琴科提出的解决方案之外,还有其他可能的解决方案。

您的设计有缺点

如您所知,您的设计不可能用 Java 实现。这是 Java 泛型的限制。让我们暂时设想一下如果可能的话。我认为这意味着许多人会感到惊讶和/或困惑的一些行为。

根据您的设计,假设我们有:

    Goalkeeper goalkeeper1 = new Goalkeeper("Imene");
    Goalkeeper goalkeeper2 = new Goalkeeper("Sofia");
    Player goalkeeper3 = new Goalkeeper("Maryam");

    goalkeeper1.compareTo(goalkeeper2); // would call Goalkeeper.compareTo(Goalkeeper)
    goalkeeper1.compareTo(goalkeeper3); // would call Player.compareTo(Player)

我们可以更进一步:

    List<? extends Player> list1 = new ArrayList<Goalkeeper>();
    List<? extends Player> list2 = new ArrayList<Player>();

现在我们(仅)用守门员填充两个列表并对它们进行排序。现在,list1 应该使用 Goalkeeper.compsreTo() 进行排序,list2 可能使用 Player.compareTo() 进行排序。开始变得混乱了,不是吗?这样的设计你想要吗?您是否更喜欢一种更明确何时使用哪种比较方式的方法? (是的,我知道,您无法通过变量 list1list2 填充列表。您必须先填充列表,然后再将它们分配给这两个变量。

)解决方案

解决方案 1:使用 Comparator 代替其中一个 compareTo 方法(或两者)。 ComparatorComparator 或两者之一。例如:

    Comparator<Player> playerComparator = Comparator.comparingInt(Player::getScoredGoals);

解决方案 2:为非守门员的球员引入一个单独的类。由于没有更好的词,我暂时将其称为 FieldPlayerFieldPlayerGoalkeeper 都应该是 Player 的子类。 FieldPlayer 实现了 Comparable,并且 Goalkeeper 已经实现了 Comparable。现在Player不需要实现Comparable,并且避免了冲突。

I would like to add two points to the existing good answers.

  1. There are reasons why you might not want the design you tried even if it had been possible. It is a bit fluffy.
  2. There are other possible solutions in addition to the one that Sergey Kalinichenko presents.

Your design has downsides

As you know, your design isn’t possible with Java. It’s a restriction with Java generics. Let’s for a moment play what if it had been possible. It would imply some behaviour that I think many would find surprising and/or confusing.

With you design, assume we have:

    Goalkeeper goalkeeper1 = new Goalkeeper("Imene");
    Goalkeeper goalkeeper2 = new Goalkeeper("Sofia");
    Player goalkeeper3 = new Goalkeeper("Maryam");

    goalkeeper1.compareTo(goalkeeper2); // would call Goalkeeper.compareTo(Goalkeeper)
    goalkeeper1.compareTo(goalkeeper3); // would call Player.compareTo(Player)

We can take it one step further:

    List<? extends Player> list1 = new ArrayList<Goalkeeper>();
    List<? extends Player> list2 = new ArrayList<Player>();

Now we fill both lists with goalkeepers (only) and sort them. Now list1 should be sorted using Goalkeeper.compsreTo() and list2 probably using Player.compareTo(). It’s beginning to be confusing, isn’t it? Would you want such a design? Would you prefer one where you are more explicit about which way to compare is used when? (Yes, I know, you cannot fill the lists through the variables list1 and list2. You would have to fill the lists before assigning them to those two variables.)

A couple of solutions

Solution 1: Instead of one of your compareTo methods (or both of them) use a Comparator. Either a Comparator<Player> or a Comparator<Goalkeeper> or one of each. For example:

    Comparator<Player> playerComparator = Comparator.comparingInt(Player::getScoredGoals);

Solution 2: Introduce a separate class for players that are not goalkeepers. I am calling it FieldPlayer for now for lack of a better word. Both FieldPlayer and Goalkeeper should be subclasses of Player. FieldPlayer implements Comparable<FieldPlayer> and Goalkeeper already implements Comparable<Goalkeeper>. Now Player doesn’t need to implement Comparable, and the conflict is avoided.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文