据我所知,SortedMap
或SortedSet
等内容在compareTo
类型上使用equals
(而不是Comparable<?>
)来检查相等性( contains
,containsKey
)。
但是,如果某些类型在概念上是等同的,但不可比较呢? (哈希码,内存地址,......)
我必须声明Comparator<?>
并覆盖方法int compareTo(T o1, To2)
。好的,我可以为被认为相等的实例返回0。但是,对于非实际情况,当订单不明显时我会返回什么?
在 equatable 上使用SortedMap或SortedSet的方法,但是(按概念)不具有可比性类型是否有用呢?
谢谢!
修改
我不想存储已排序的东西,但是我会使用“通常的”Map和Set,我无法“覆盖”相等行为。
编辑2:
为什么我不能只是覆盖equals(...)
:
我需要改变外国阶级的平等行为。我无法编辑。
编辑3:
想想.NET:它们具有IEquatable接口,可以改变相等行为,而不会触及可比较的行为。
编辑4:
我不能让compareTo
返回0表示相等,1表示不相等的实例吗?什么是大问题?我进行了一些测试,似乎SortedMap / SortedSet在一对实例上调用compareTo一次。是的,订单没有意义,但为什么它应该是我的问题呢?我不需要订单。 *我只需要改变平等行为。可悲的是,大多数人都无法理解这一点
注意:现在证明为非平等实例返回1的概念是错误的。
编辑5:
改变外国阶级的等同行为 是一个坏概念?当然?我不这么认为:为什么我允许使用Comparator
改变外国类的比较行为?
编辑6:
感谢Mark Peters
和waxwing
关于将密钥类型包装在自定义类中的想法。这样,我可以覆盖equals和hashCode,从而改变了相等行为。
答案 0 :(得分:10)
不,在相同但不可比的类型上使用SortedMap或SortedSet是一个可怕的想法。如果它们无法通过内在比较或通过比较器进行比较,则不应在SortedSet中使用它们。排序意味着有排序,这意味着你可以比较两个项目,看看哪个是“更少”。
只需使用HashMap / Set。
编辑您的编辑#2
如果你无法正确覆盖equals,那么你的设计就会非常糟糕。您需要提供有关您要完成的内容的更多信息。
编辑您的编辑#3
在Java中,修改equals 不会更改可比较的行为。您不需要界面来完成此任务。
编辑您的编辑#4
不,你不能仅仅返回1个不等元素!
SortedSets使用比较来查找你的元素。可比较的界面具有特定要求。您要破解的是,如果A.compareTo(B) > 0
,则必须B.compareTo(A) < 0
。你破坏了那些无法在你的集合中找到元素的东西。
public static void main(String[] args) throws Exception {
SortedSet<MyClass> set = new TreeSet<MyClass>();
MyClass one = new MyClass(1);
set.add(one);
set.add(new MyClass(2));
set.add(new MyClass(3));
System.out.println(set.contains(one));
}
private static class MyClass implements Comparable<MyClass> {
private final int data;
private MyClass(int data) { this.data = data; }
public int compareTo(MyClass o) { return (data == o.data ? 0 : 1); }
}
此代码打印false
,因此显然您的比较器已经破坏了Set的语义。
答案 1 :(得分:10)
考虑将你的外国课程包装在你自己的内部。
public class Foreign {
// undesired equals() and hashCode() implementation
}
public class ForeignWrapper {
private Foreign foreign;
public ForeignWrapper(Foreign foreign) {
this.foreign = foreign;
}
public void equals() {
// your equals implementation, using fields from foreign
}
public int hashCode() {
// your hashCode implementation, using fields from foreign
}
}
然后将new ForeignWrapper(foreign)
添加到标准HashSet / HashMap。不适用于所有情况,但可能在您的情况下。
答案 2 :(得分:6)
看起来你不想/需要对元素进行排序。
在这种情况下,您可以使用HashMap
和HashSet
吗?如果您不需要对其进行排序,则无需使用SortedMap
和SortedSet
。
答案 3 :(得分:1)
我不想存储已排序的东西,但是我会使用“通常的”Map和Set,我无法“覆盖”相等行为。
如果您不想存储已排序的元素,那么为什么要使用已排序的集合?
为了维护已排序的集合,插入操作(通常)具有O(log n)复杂度,以将元素放置在正确的位置。如果你不需要排序,那么这很浪费,因为你可以使用基于哈希的集合(HashMap,HashSet),它会给你O(1)插入时间。
答案 4 :(得分:1)
是使用SortedMap的方法还是 SortedSet on equatable但是(by 概念)不可比的类型好 呢?
没有。这些集合的要点是允许您对其中的对象进行排序,如果对象没有自然的排序顺序,那么将它们放入已排序的集合中的重点是什么?
您应该覆盖equals()和hashcode()方法,而是使用标准的Map / Set类。
答案 5 :(得分:1)
如果您需要覆盖hashCode但不能,我认为您正在考虑扩展HashMap或编写自己的HashMap。
答案 6 :(得分:1)
目前尚不清楚,但可能是你要做的就是使用相同的Set / Map语义来获取 somethings 的集合,但是 somethings 没有充分实施Object.equals
。
在这种情况下,我建议您继承AbstractSet
或AbstractMap
并覆盖AbstractCollection.contains
以使用您的等号版本。
这不是我推荐的,但你的问题实际上并没有说明你想要实现的目标。
参见http://java.sun.com/javase/6/docs/api/java/util/AbstractSet.html 和http://java.sun.com/javase/6/docs/api/java/util/AbstractCollection.html#contains(java.lang.Object)
答案 7 :(得分:1)
如果内存不是一个大问题,则将HashMap和HashSet子类化为一个Equality类
interface Equality<T>//Defines the equality behavior
{
int hashCode(T t);//Required, always make sure equals = true => same hashCode
boolean areEqual(T t,Object t2);
}
class EqualWrapper<T>//Wraps object and equality for the HashMap/Set
{
T object;
Equality<T> equal;
int hashCode(){return equal.hashCode(object);}
boolean equals(Object o){return equal.areEqual(object,o);}
}
class MySet<T>extends AbstractSet<T>
{
private HashSet<EqualWrapper<T> > internalSet = new HashSet<T>();
private Equality<T> equal;
public MySet(Equality<T> et){equal = et;}
// TODO implement abstract functions to wrapp
// objects and forward them to
// internalSet
}
这样您就可以定义自己的相等行为。奇怪的是它在jre中缺失了
答案 8 :(得分:0)
如果对象无法比较,则无法对其进行排序;如果它们不具有可比性,你怎么知道这两个物体中的哪一个应该首先出现?因此,无法在SortedMap
或SortedSet
中放置无法比较的对象。 (您为什么要这样做?使用其他类型的Map
或Set
)。
Java中的equals()
方法在类Object
中定义,并且由于所有类都扩展为Object
,因此所有对象都具有equals()
方法。如果您希望能够判断两个对象是否相等,则必须注意在类中正确覆盖并实现equals()
。
如果您想将对象放在基于哈希的集合中(例如HashMap
或HashSet
),您还必须覆盖hashCode()
,并且必须确保hashCode()
并且equals()
以正确的方式实现(有关如何执行此操作的详细信息,请参阅类Object
中这些方法的文档。)
答案 9 :(得分:0)
正如其他人所说,如果没有自然顺序,SortedXXX实际上不是一个选择。 但是,假设您只是想要某种一致的列出元素的方法,如果您只是考虑用于相等性测试的字段,因为它们构成了“主键”,并提出了某种数字或字母顺序在他们周围可能适合你的目的。
答案 10 :(得分:0)
创建它时,只需使用为Sorted [Set | Map]的实现提供的(自定义)比较器...
javadocs倾向于建议:All keys inserted into a sorted map must implement the Comparable interface (or be accepted by the specified comparator).
SortedSet<MyObject> s = new TreeSet<MyObject>(new Comparator<MyObject>() {
@Override
public int compare(T o1, T o2) {
// your very specific, fancy dancy code here
}
});
答案 11 :(得分:0)
我不确定我是否看到了你的观点(我认为你试图从错误的方向解决问题),但如果你毕竟只想要一个Set
或Map
维护广告订单,然后分别使用LinkedHashSet
或LinkedHashMap
。
更新:根据您的报价:
我需要改变外来类的相等行为。我无法编辑它。
在排序的集合/地图中?然后使用您使用自定义TreeSet
构建的TreeMap
或Comparator
。 E.g。
SortedSet<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
(以不区分大小写的顺序构造一组String
s。)。
另见:
答案 12 :(得分:0)
我不想存储分类的东西, 但我会使用“通常的”地图和套装,我 无法“覆盖” 平等的行为。
您正在尝试覆盖未知类型的equals()方法。您正在考虑希望您拥有IEquatable接口的问题。如果必须使用SortedSet / SortedMap,则提供类似@ptomli mentions in his answer的比较器。
使用HashMap / HashSet似乎是一个很好的建议。你看过那些吗?