Is it possible in java make something like Comparator but for implementing custom equals() and hashCode()

前端 未结 8 1135
庸人自扰
庸人自扰 2020-11-27 03:50

I have an array of objects and I want to concatenate it with another array of objects, except that objects that have same id\'s. That objects are used in many places in the

8条回答
  •  一整个雨季
    2020-11-27 04:22

    Of course you can create some external object providing an equality comparison and a HashCode. But the build-in collections of Java do not use such an object for their comparisons/lookup.

    I once did create an interface like this in my package-collection (just freshly translated to english):

    public interface HashableEquivalenceRelation {
    
        /**
         * Returns true if two objects are considered equal.
         *
         * This should form an equivalence relation, meaning it
         * should fulfill these properties:
         *  
      *
    • Reflexivity: {@code areEqual(o, o)} * should always return true.
    • *
    • Symmetry: {@code areEqual(o1,o2) == areEqual(o2,o1)} * for all objects o1 and o2
    • *
    • Transitivity: If {@code areEqual(o1, o2)} and {@code areEqual(o2,o3)}, * then {@code areEqual(o1,o3}} should hold too.
    • *
    * Additionally, the relation should be temporary consistent, i.e. the * result of this method for the same two objects should not change as * long as the objects do not change significantly (the precise meaning of * change significantly is dependent on the implementation). * * Also, if {@code areEqual(o1, o2)} holds true, then {@code hashCode(o1) == hashCode(o2)} * must be true too. */ public boolean areEqual(Object o1, Object o2); /** * Returns a hashCode for an arbitrary object. * * This should be temporary consistent, i.e. the result for the same * objects should not change as long as the object does not change significantly * (with change significantly having the same meaning as for {@link areEqual}). * * Also, if {@code areEqual(o1, o2)} holds true, then {@code hashCode(o1) == hashCode(o2)} * must be true too. */ public int hashCode(Object o); }

    Than I had a group of interfaces CustomCollection, CustomSet, CustomList, CustomMap, etc. defined like the interfaces in java.util, but using such an equivalence relation for all the methods instead of the build-in relation given by Object.equals. I had some default implementations, too:

    /**
     * The equivalence relation induced by Object#equals.
     */
    public final static EquivalenceRelation DEFAULT =
        new EquivalenceRelation() {
            public boolean areEqual(Object o1, Object o2)
            {
                return
                    o1 == o2 ||
                    o1 != null &&
                    o1.equals(o2);
            }
            public int hashCode(Object ob)
            {
                return
                    ob == null?
                    0 :
                    ob.hashCode();
            }
            public String toString() { return ""; }
        };
    
    /**
     * The equivalence relation induced by {@code ==}.
     * (The hashCode used is {@link System#identityHashCode}.)
     */
    public final static EquivalenceRelation IDENTITY =
        new EquivalenceRelation() {
            public boolean areEqual(Object o1, Object o2) { return o1 == o2; }
            public int hashCode(Object ob) { return System.identityHashCode(ob); }
            public String toString() { return ""; }
        };
    
    /**
     * The all-relation: every object is equivalent to every other one.
     */
    public final static EquivalenceRelation ALL =
        new EquivalenceRelation() {
            public boolean areEqual(Object o1, Object o2) { return true; }
            public int hashCode(Object ob) { return 0; }
            public String toString() { return ""; }
        };
    
    /**
     * An equivalence relation partitioning the references
     * in two groups: the null reference and any other reference.
     */
    public final static EquivalenceRelation NULL_OR_NOT_NULL =
        new EquivalenceRelation() {
            public boolean areEqual(Object o1, Object o2)
            {
                return (o1 == null && o2 == null) ||
                    (o1 != null && o2 != null);
            }
            public int hashCode(Object o) { return o == null ? 0 : 1; }
            public String toString() { return ""; }
        };
    
    /**
     * Two objects are equivalent if they are of the same (actual) class.
     */
    public final static EquivalenceRelation SAME_CLASS =
        new EquivalenceRelation() {
            public boolean areEqual(Object o1, Object o2)
            {
                return o1 == o2 || o1 != null && o2 != null &&
                    o1.getClass() == o2.getClass();
            }
            public int hashCode(Object o) { return o == null ? 0 : o.getClass().hashCode(); }
            public String toString() { return ""; }
        };
    
    
    /**
     * Compares strings ignoring case.
     * Other objects give a {@link ClassCastException}.
     */
    public final static EquivalenceRelation STRINGS_IGNORE_CASE =
        new EquivalenceRelation() {
            public boolean areEqual(Object o1, Object o2)
            {
                return o1 == null ?
                    o2 == null :
                    ((String)o1).equalsIgnoreCase((String)o2);
            }
            public int hashCode(Object o)
            {
                return o == null ? -12345 : ((String)o).toUpperCase().hashCode();
            }
            public String toString() { return ""; }
        };
    
    
    /**
     * Compares {@link CharSequence} implementations by content.
     * Other object give a {@link ClassCastException}.
     */
    public final static EquivalenceRelation CHAR_SEQUENCE_CONTENT =
        new EquivalenceRelation() {
            public boolean areEqual(Object o1, Object o2) 
            {
                CharSequence seq1 = (CharSequence)o1;
                CharSequence seq2 = (CharSequence)o2;
                if (seq1 == null ^ seq2 == null) // nur eins von beiden null
                    return false;
                if (seq1 == seq2)   // umfasst auch den Fall null == null
                    return true;
                int size = seq1.length();
                if (seq2.length() != size)
                    return false;
                for (int i = 0; i < size; i++)
                    {
                        if (seq1.charAt(i) != seq2.charAt(i))
                            return false;
                    }
                return true;
            }
            /**
             * Entrspricht String.hashCode
             */
            public int hashCode(Object o)
            {
                CharSequence sequence = (CharSequence)o;
                if (sequence == null)
                    return 0;
                int hash = 0;
                int size = sequence.length();
                for (int i = 0; i < size; i++)
                    {
                        hash = hash * 31 + sequence.charAt(i);
                    }
                return hash;
            }
        };
    

提交回复
热议问题