在java中,除了实现定制的equals()和hashCode()之外,是否可以制作类似Comparator的东西

在java中,除了实现定制的equals()和hashCode()之外,是否可以制作类似Comparator的东西,java,collections,equals,hashcode,Java,Collections,Equals,Hashcode,我有一个对象数组,我想将它与另一个对象数组连接起来,除了具有相同id的对象。对象在系统中的许多地方使用,并且没有实现哈希代码或相等值。所以我不想实现hashCode()和equals(),因为我害怕破坏系统中使用这些对象的某个地方,我对此一无所知 我想将所有这些对象放在一个集合中,但不知何故使这些对象使用自定义的hashCode()和equals()。类似于自定义比较器的东西,但是对于equals。是的,这样做是可能的。但它不允许您将对象放入HashMap、HashSet等中。这是因为标准集合类

我有一个对象数组,我想将它与另一个对象数组连接起来,除了具有相同id的对象。对象在系统中的许多地方使用,并且没有实现哈希代码或相等值。所以我不想实现
hashCode()
equals()
,因为我害怕破坏系统中使用这些对象的某个地方,我对此一无所知


我想将所有这些对象放在一个集合中,但不知何故使这些对象使用自定义的
hashCode()
equals()
。类似于自定义比较器的东西,但是对于equals。

是的,这样做是可能的。但它不允许您将对象放入HashMap、HashSet等中。这是因为标准集合类希望键对象提供
equals
hashCode
方法。(这就是他们设计的工作方式…)

备选方案:

  • 实现一个包含真实类实例的包装类,并提供它自己的
    equals
    hashCode
    实现

  • 实现您自己的基于哈希表的类,这些类可以使用“hashable”对象来提供equals和hashcode功能

  • 咬紧牙关,在相关类上实现
    equals
    hashCode
    重写

  • 事实上,第三个选项可能是最好的,因为您的代码库很可能需要使用一致的概念,即这些对象相等意味着什么。还有一些事情表明您的代码需要大修。例如,它目前正在使用对象数组而不是集合实现来表示显然应该是集合的内容


    另一方面,当前的实现可能有一些真实(或想象)的性能原因;e、 减少内存使用。在这种情况下,您可能应该编写一组helper方法来执行诸如连接两个表示为数组的集合之类的操作

    在这里需要帮助吗?TreeSet实际上使用compare/compareTo执行排序和基于集合的行为,并允许您定义自定义比较器以供i使用

    当然,您可以创建一些外部对象,提供相等比较和哈希代码。但是Java的内置集合不使用这样的对象进行比较/查找

    我曾经在我的软件包集合中创建过这样的界面(刚刚翻译成英文):


    使用比较器进行重复数据消除串联不会成功。大概你想做这样的事情:

    List<Object> list = new ArrayList<Object>();
    list.addAll( a );
    list.addAll( b );
    Collections.sort( list, new MyCustomComparator() );
    
    List List=new ArrayList();
    列表。添加全部(a);
    列表。添加全部(b);
    Collections.sort(list,新的MyCustomComparator());
    
    问题是比较器不仅需要比较相等/不相等,还需要比较相对顺序。给定不相等的对象x和y,必须回答其中一个是否大于另一个。您将无法这样做,因为您实际上并没有尝试比较对象。如果您没有给出一致的答案,您将把排序算法发送到一个无限循环中


    我确实有一个解决办法给你。Java有一个名为LinkedHashSet的类,其优点是不允许插入重复项,但保持插入顺序。与其实现一个比较器,不如实现一个包装器类来保存实际对象并实现hashCode/equals

    90%的时候,当用户想要一个等价关系时,已经有了一个更直接的解决方案。您想仅基于ID对一组内容进行重复数据消除吗?你能不能把它们都放到一个以ID为键的映射中,然后得到它的
    values()
    集合?

    是你要寻找的概念。它是一个策略接口,允许您定义equals和hashcode的自定义实现

    public interface HashingStrategy<E>
    {
        int computeHashCode(E object);
        boolean equals(E object1, E object2);
    }
    
    下面是如何使用HashingStrategy设置并使用
    统一网络

    java.util.Set<Data> set =
      new UnifiedSetWithHashingStrategy<>(HashingStrategies.fromFunction(Data::getId));
    Assert.assertTrue(set.add(new Data(1)));
    
    // contains returns true even without hashcode and equals
    Assert.assertTrue(set.contains(new Data(1)));
    
    // Second call to add() doesn't do anything and returns false
    Assert.assertFalse(set.add(new Data(1)));
    
    java.util.Set=
    新的UnifiedSetWithHashingStrategy(HashingStrategies.fromFunction(Data::getId));
    Assert.assertTrue(set.add(新数据(1));
    //包含返回true,即使没有hashcode和equals
    Assert.assertTrue(set.contains)(新数据(1));
    //对add()的第二次调用不执行任何操作并返回false
    Assert.assertFalse(set.add(新数据(1));
    
    为什么不直接使用
    地图
    UnifiedSetWithHashingStrategy
    使用了
    UnifiedMap
    的一半内存,以及
    HashMap
    的四分之一内存。有时你没有一个方便的键,必须创建一个合成键,比如元组。这会浪费更多的内存

    我们如何执行查找?请记住,集合具有
    contains()
    ,但不具有
    get()
    UnifiedSetWithHashingStrategy
    除了实现
    MutableSet
    之外,还实现了
    get()
    的一种形式


    注意:我是Eclipse集合的提交者。

    刚刚遇到这个问题,并制定了一个简单的解决方案。不确定它的内存密集程度;我相信人们可以不断完善它

    比较器返回0时,元素匹配

    public static <E> Set<E> filterSet(Set<E> set, Comparator<E> comparator){
        Set<E> output = new HashSet<E>();
        for(E eIn : set){
            boolean add = true;
            for(E eOut : output){
                if(comparator.compare(eIn, eOut) == 0){
                    add = false;
                    break;
                }
            }
            if(add) output.add(eIn);
        }
        return output;
    }
    
    使用番石榴:

    等价=新等价(){
    @凌驾
    受保护布尔不等价(TA,TB){
    返回CustomComparator.equals(a,b);
    }
    @凌驾
    受保护的int-doHash(T项){
    返回CustomHashCodeGenerator.hashCode(项);
    }
    };
    List items=getItems();
    Set setWithWrappedObjects=items.stream()
    .map(项目->等价性.wrap(项目))
    .collect(收集器.toSet());
    
    也许你需要创建一个包装类来实现equals和hashCode。我做不到,如果你担心
    public class Data
    {
        private final int id;
    
        public Data(int id)
        {
            this.id = id;
        }
    
        public int getId()
        {
            return id;
        }
    
        // No equals or hashcode
    }
    
    java.util.Set<Data> set =
      new UnifiedSetWithHashingStrategy<>(HashingStrategies.fromFunction(Data::getId));
    Assert.assertTrue(set.add(new Data(1)));
    
    // contains returns true even without hashcode and equals
    Assert.assertTrue(set.contains(new Data(1)));
    
    // Second call to add() doesn't do anything and returns false
    Assert.assertFalse(set.add(new Data(1)));
    
    public static <E> Set<E> filterSet(Set<E> set, Comparator<E> comparator){
        Set<E> output = new HashSet<E>();
        for(E eIn : set){
            boolean add = true;
            for(E eOut : output){
                if(comparator.compare(eIn, eOut) == 0){
                    add = false;
                    break;
                }
            }
            if(add) output.add(eIn);
        }
        return output;
    }
    
    filtered = Misc.filterSet(filtered, (a, b) -> a.sameFile(b) ? 0 : 1);