我有一个对象数组,我想将它与另一个对象数组连接起来,除了具有相同id的对象。这些对象在系统中的许多地方使用,并且没有实现散列代码或equals。所以我不想实现hashCode()
和equals()
,因为我害怕破坏系统中使用这些对象的某个地方,我不知道这一点。
我希望将所有这些对象放在一个集合中,但又以某种方式使这些对象使用自定义的hashCode()
和equals()
。有点像自定义的Comparator
,但是等同的。
发布于 2011-03-07 00:17:42
90%的情况下,当用户想要一个等价关系时,已经有了一个更直接的解决方案。您想仅根据ids对一堆东西进行重复数据删除吗?您是否可以将它们全部放入一个映射中,并将ids作为键,然后获取该ids的values()
集合?
发布于 2014-06-23 23:57:05
HashingStrategy是您正在寻找的概念。它是一个策略接口,允许您定义equals和hashcode的自定义实现。
public interface HashingStrategy<E>
{
int computeHashCode(E object);
boolean equals(E object1, E object2);
}
正如其他人所指出的,您不能将HashingStrategy
与内置的HashSet
或HashMap
一起使用。Eclipse Collections包括一个名为UnifiedSetWithHashingStrategy
的集合和一个名为UnifiedMapWithHashingStrategy
的映射。
让我们看一个例子。下面是一个可以在UnifiedSetWithHashingStrategy
中使用的简单Data
类。
public class Data
{
private final int id;
public Data(int id)
{
this.id = id;
}
public int getId()
{
return id;
}
// No equals or hashcode
}
下面是如何设置和使用UnifiedSetWithHashingStrategy
的方法。
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)));
为什么不直接使用Map
呢?UnifiedSetWithHashingStrategy
的内存只有UnifiedMap
的一半,HashMap
的四分之一。有时你没有一个方便的键,必须创建一个合成的键,比如元组。这会浪费更多的内存。
我们如何执行查找?请记住,Set有contains()
,但没有get()
。除了MutableSet
之外,UnifiedSetWithHashingStrategy
还实现了Pool
,因此它还实现了一种形式的get()
。
注意:我是Eclipse Collections的提交者。
发布于 2011-03-05 22:17:01
当然,您可以创建一些外部对象,提供相等比较和HashCode。但是Java的内置集合不会使用这样的对象进行比较/查找。
我曾经在我的package-collection (刚刚翻译成英语)中创建了一个这样的接口:
public interface HashableEquivalenceRelation {
/**
* Returns true if two objects are considered equal.
*
* This should form an equivalence relation, meaning it
* should fulfill these properties:
* <ul>
* <li>Reflexivity: {@code areEqual(o, o)}
* should always return true.</li>
* <li>Symmetry: {@code areEqual(o1,o2) == areEqual(o2,o1)}
* for all objects o1 and o2</li>
* <li>Transitivity: If {@code areEqual(o1, o2)} and {@code areEqual(o2,o3)},
* then {@code areEqual(o1,o3}} should hold too.</li>
* </ul>
* 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
* <em>change significantly</em> 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);
}
然后我有了一组接口CustomCollection
,CustomSet
,CustomList
,CustomMap
,等等,就像java.util
中的接口一样,但是对所有的方法都使用了这样的等价关系,而不是Object.equals
给出的内置关系。我也有一些默认的实现:
/**
* 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 "<DEFAULT>"; }
};
/**
* 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 "<IDENTITY>"; }
};
/**
* 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 "<ALL>"; }
};
/**
* 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 "<NULL_OR_NOT_NULL>"; }
};
/**
* 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 "<SAME_CLASS>"; }
};
/**
* 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 "<STRINGS_IGNORE_CASE>"; }
};
/**
* 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;
}
};
https://stackoverflow.com/questions/5204082
复制相似问题