我有两家公司asoft和bsoft的代码。我也不能改变。这是我的情况的简化版本,我敢肯定,它有足够的信息来查找导致问题的原因。
bsoft提供了IGang,它代表可以与其他帮派作战的帮派。
IGang
package bsoft; public interface IGang { /** @return negative, 0, or positive, respectively * if this gang is weaker than, equal to, or stronger * than the other */ public int compareTo(IGang g); public int getStrength(); public String getName(); public void attack(IGang g); public void weaken(int amount); }
asoft提供了GangWar,它允许IGang进行战斗:
GangWar
package asoft; import java.util.*; import bsoft.*; /** An `IGang` ordered by identity (name) */ public interface ComparableGang extends IGang, Comparable<IGang> {} package asoft; import java.util.*; public class GangWar { public final Set<ComparableGang> gangs = new TreeSet<ComparableGang>(); public void add(ComparableGang g) {gangs.add(g);} public void doBattle() { while (gangs.size() > 1) { Iterator<ComparableGang> i = gangs.iterator(); ComparableGang g1 = i.next(); ComparableGang g2 = i.next(); System.out.println(g1.getName() + " attacks " + g2.getName()); g1.attack(g2); if (g2.getStrength() == 0) { System.out.println(g1.getName() + " smokes " + g2.getName()); gangs.remove(g2); } if (g1.getStrength() == 0) { System.out.println(g2.getName() + " repels " + g1.getName()); gangs.remove(g1); } } for (ComparableGang g : gangs) { System.out.println(g.getName() + " now controls the turf!"); } } }
它需要Gang您提供给它的s 的附加约束Comparable,大概是它可以按名称排序或避免重复。每个帮派(为简单起见,这里使用任意顺序的Set顺序)都会攻击另一个帮派,直到只剩下一个帮派(如果最后两个有并列,则没有帮派)。我已经编写了一个简单的实现来对其ComparableGang进行测试:
Gang
Comparable
ComparableGang
import asoft.*; import bsoft.*; import java.util.*; class Gang implements ComparableGang { final String name; int strength; public Gang(String name, int strength) { this.name = name; this.strength = strength; } public String getName() {return name;} public int getStrength() {return strength;} public int compareTo(IGang g) { return strength - g.getStrength(); } public void weaken(int amount) { if (strength < amount) strength = 0; else strength -= amount; } public void attack(IGang g) { int tmp = strength; weaken(g.getStrength()); g.weaken(tmp); } public boolean equals(Object o) { if (!(o instanceof IGang)) return false; return name.equals(((IGang)o).getName()); } } class Main { public static void main(String[] args) { GangWar gw = new GangWar(); gw.add(new Gang("ballas", 2)); gw.add(new Gang("grove street", 9)); gw.add(new Gang("los santos", 8)); gw.add(new Gang("triads", 9)); gw.doBattle(); } }
测试出来…
$ java Main ballas attacks los santos los santos repels ballas los santos attacks grove street grove street repels los santos grove street now controls the turf!
问题是,三合会不会出现在战斗中。实际上,gangs.size()在doBattle()返回开始处直接打印3而不是4。为什么?如何解决?
gangs.size()
doBattle()
问题是,三合会不会出现在战斗中。实际上,在doBattle()开始时立即打印gangs.size()会返回3而不是4。为什么?
双方triads并grove street有9所以他们来讲等于强度Gang.compareTo(实现Comparable)。因此,一个中只允许一个TreeSet。
triads
grove street
Gang.compareTo
TreeSet
如果您不想删除按排序顺序重复的项目,请不要使用TreeSet…
编辑:ComparableGang接口说明指示了所期望的:
/** An `IGang` ordered by identity (name) */ public interface ComparableGang extends IGang, Comparable<IGang> {}
你的compareTo方法确实 不是 靠力量才下订单- 订单“的标识(名称)”。老实说,它首先是一个非常愚蠢的接口,因为asoft创建一个类public class GangNameComparator : Comparator<IGang>,然后将其作为树集的比较器(如果他们想按名称排序)将非常容易。
compareTo
asoft
public class GangNameComparator : Comparator<IGang>
但是,由于他们建议您实施比较,因此您需要按照界面说明进行操作:
public int compareTo(IGang g) { return name.compareTo(g.getName()); }
但是…正如您在评论中(以及Rob的回答中所指出的)所指出的,这与约定俗称的IGang描述相矛盾:
public interface IGang { /** @return negative, 0, or positive, respectively * if this gang is weaker than, equal to, or stronger * than the other */ public int compareTo(IGang g); }
ComparableGang既要实现自己的文档又要满足文档是不可能的IGang。从asoft的角度来看,这基本上是通过设计打破的。
任何代码都应该能够使用IGang实现, 仅 了解IGang并依赖IGang合同之后的实现。但是,asoft通过在扩展接口中要求不同的行为打破了这一假设IGang。
这本来是合理的为他们增添 了更多的要求 的ComparableGang,只要他们没有违反 现行 的规定IGang。
请注意,这是C#和Java之间的重要区别。在C#中,两个具有相同签名的不同接口中的两个函数可以组合为一个继承两个函数的接口,并且这两种方法保持不同且可访问。在Java中,这两种方法由于完全是抽象的并且具有相同的签名,因此被视为相同的方法,而实现组合接口的类仅具有一个这样的方法。因此 在Java中 ComparableGang是无效的,因为它不能具有满足ComparableGang协定和IGang协定的compareTo()实现。