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
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;
}
};