代码之家  ›  专栏  ›  技术社区  ›  java.is.for.desktop

爪哇:如何解决缺乏平等的界面?

  •  3
  • java.is.for.desktop  · 技术社区  · 16 年前

    据我所知, SortedMap 或 SortedSet 使用 compareTo (而不是 equals 对 Comparable<?> 用于检查相等性的类型( contains , containsKey )

    但是如果某些类型在概念上是相等的,但是 不 可比的?
    (哈希代码、内存地址…)

    我必须申报 Comparator<?> 并重写该方法 int compareTo(T o1, To2) . 好的,对于被认为相等的实例,我可以返回0。但是,对于非定量的情况,当订单不明显时,我应该返回什么?

    使用sortedmap或sortedset的方法是 可等值的 但是(从概念上讲) 不可比 类型好吗?

    谢谢您!

    编辑:
    我不想存储排序的东西,但我会使用“常规”映射和设置,我不能“覆盖”平等行为。

    编辑2:
    为什么我不能忽略 equals(...) :
    我需要改变外国阶级的平等行为。我不能编辑它。

    编辑3:
    想想.NET:它们有一个IEquatable接口,cat可以在不影响可比较行为的情况下改变相等行为。

    编辑4:
    我不能就这么做吗 比较函数 相等实例返回0,不相等实例返回1?有什么大问题?我已经完成了一些测试,看起来sortedmap/sortedset对一对实例调用compareto一次。是的,这个订单没有意义,但为什么是我的问题?我不需要订单。*我只需要改变平等的行为。遗憾的是,大多数人都无法理解这一点。
    注: 对于不相等的实例返回1的概念现在被证明是错误的。

    编辑5:
    改变平等行为 外国阶级 是个坏概念吗?当然?我不这么认为:那为什么我可以改变比较行为呢? 外国阶级 使用 Comparator ?

    编辑6:
    多亏了 Mark Peters 和 waxwing 在自定义类中包装键类型的想法。这样,我 可以 重写equals和hashcode,从而改变相等行为。

    13 回复  |  直到 16 年前
        1
  •  10
  •   waxwing    16 年前

    考虑把你的外国班级包装在你自己的班级里。

    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) 到标准哈希集/哈希映射。不适用于所有情况,但可能适用于您的情况。

        2
  •  10
  •   Mark Peters    16 年前

    不,在相等但不可比较的类型上使用sortedmap或sortedset是一个可怕的想法。如果它们在本质上或通过比较器无法进行比较,则不应在排序集中使用它们。排序意味着有排序,这意味着你可以比较两个项目,看看哪个是“更少”。

    只需使用hashmap/set。

    编辑到您的编辑2

    如果你不能正确地覆盖等号,在某个地方你的设计很糟糕。你需要提供更多的信息来了解你想要达到的目标。

    编辑到您的编辑3

    在爪哇,修改等式 不 改变可比行为。您不需要一个接口来完成这一点。

    编辑到您的编辑4

    不,不相等的元素不能只返回1!!

    排序集使用比较 找到 集合中的元素。可比较的接口有特定的要求。你要打破的是如果 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 显然,您的比较器已经破坏了集合的语义。

        3
  •  6
  •   ryanprayogo    16 年前

    看起来您不想/不需要对元素排序。

    那样的话,也许你可以用 HashMap 和 HashSet 相反?没有用武之地 SortedMap 和 SortedSet 如果你不需要分类的话。

        4
  •  1
  •   matt b    16 年前

    我不想存储排序的东西,但我会使用“常规”映射和设置,我不能“覆盖”平等行为。

    如果不想存储已排序的元素,那么为什么要使用已排序的集合?

    为了维护已排序的集合,插入操作(通常)具有将元素放置在正确位置的O(log n)复杂性。如果您不需要排序,那么这是浪费,因为您可以使用基于散列的集合(hashmap、hashset),这将给您0(1)的插入时间。

        5
  •  1
  •   Paolo    16 年前

    是使用sortedmap的方法还是 可等量排序集,但 概念)不可比类型良好 反正?

    不。这些集合的目的是允许您对其中的对象进行排序,如果对象没有自然的排序顺序,那么将它们放入排序集合的目的是什么?

    您应该重写equals()和hashcode()方法,并改用标准的map/set类。

        6
  •  1
  •   sblundy    16 年前

    如果您需要重写hashcode但不能,我认为您正在寻找扩展hashmap或编写自己的hashmap。

        7
  •  1
  •   ptomli    16 年前

    还不清楚,但可能是你想做的就是收集 某物 ,使用与set/map相同的语义,但使用 某物 没有充分实施 Object.equals .

    在这种情况下,我建议你子类 AbstractSet 或 AbstractMap 超驰 AbstractCollection.contains 使用您的equals版本。

    这不是我推荐的,但你的问题并不能让你清楚地知道你想要达到什么目标。

    见 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)

        8
  •  1
  •   josefx    16 年前

    如果内存不是一个大问题,那么子类hashmap和hashset将采用相等类

    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中丢失了

        9
  •  0
  •   Jesper    16 年前

    如果对象不具有可比性,则无法对其进行排序;如果两个对象不具有可比性,您如何知道哪一个应排在第一位?所以没有办法把不可比的物体放在 SortedMap 或 SortedSet . (你为什么要这样做?使用另一种 Map 或 Set )

    这个 equals() Java中的方法在类中定义 Object 因为所有类都扩展了 对象 ,所有对象都有一个 等式() 方法。您必须注意重写和实现 等式() 如果你想知道两个对象是否相等,在你的类中是正确的。

    如果要将对象放入基于哈希的集合(例如 HashMap 或 HashSet )您还必须重写 hashCode() 你必须确保 哈希德() 和 等式() 以正确的方式实现(请参见类中这些方法的文档 对象 有关如何执行此操作的详细信息)。

        10
  •  0
  •   Trevor Tippins    16 年前

    正如其他人所说,如果没有自然的顺序,排序的XXX实际上不是一个选项。 但是,假设您只想以某种一致的方式列出元素,如果您只考虑用于相等性测试的字段,因为这些字段构成了“主键”,并在它们周围提出一些可能适合您的目的的数字或字母顺序。

        11
  •  0
  •   ptomli    16 年前

    在创建排序的[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
        }
    });
    

    http://java.sun.com/javase/6/docs/api/

        12
  •  0
  •   Community Mohan Dere    9 年前

    我不确定我是否明白你的观点(我认为你是在试图从错误的方向解决问题),但如果你毕竟想要一个 Set 或 Map 它保持 插入顺序 然后使用 LinkedHashSet 或 LinkedHashMap 分别。


    更新 :根据您的报价:

    我需要改变外国阶级的平等行为。我不能编辑它。

    在已排序的集合/映射中?然后使用 TreeSet 或 TreeMap 你用一种习惯 Comparator . 例如。

    SortedSet<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
    

    (它构造了一组 String 以不区分大小写的顺序排列)。

    参见:

        13
  •  0
  •   Community Mohan Dere    9 年前

    我不想把东西分类存放, 但是我能用“平常”的地图和布景吗? 无法“覆盖” 平等行为。

    您试图重写未知类型的equals()方法。你在考虑这个问题,希望你有一个IEquatable接口。如果必须使用sortedset/sortedmap,请提供类似于 @ptomli mentions in his answer .

    相反,使用hashmap/hashset似乎是一个不错的建议。你看过那些吗?