我有一个三重类,该类别可以包含3个整数(x,y,z)。我想覆盖等价/哈希码方法,以便可以在集合中使用它们。因此,具有(1,2,3)的OBJ应等于(3,2,1)或(3,1,2),因此应等于其置换。我知道如何与(x,y)对一对类别进行此操作 - 我所拥有的一对的代码是:
class Pair {
int x;
int y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Pair) {
Pair p = (Pair) obj;
if (this.x == p.x && p.y == this.y || this.x == p.y && this.y == p.x) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return Integer.hashCode(x) * Integer.hashCode(y);
}
}
这可以正常工作,但是如果我想将其扩展到三级类,我知道我可以编辑等于方法并添加更多条件进行检查,但这似乎真的很长。在不使用Java中的外部库的情况下,有什么办法可以做到这一点?
一种解决方案是保留排序的数组以进行比较:
class Triple {
private final int x, y, z;
private final int[] sorted;
public Triple(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
this.sorted = new int[] {x, y, z};
Arrays.sort(sorted);
}
@Override
public boolean equals(Object obj) {
return obj instanceof Triple
&& Arrays.equals(((Triple)obj).sorted, this.sorted);
}
@Override
public int hashCode() {
return Arrays.hashCode(sorted);
}
}
要检查组合,您可以将元素添加到list
中并调用containsAll
方法以检查平等,例如:
public static void main(String[] args) throws IOException {
List<Integer> list1 = Arrays.asList(new Integer[]{1,2,4});
List<Integer> list2 = Arrays.asList(new Integer[]{4,2,1});
System.out.println(list1.containsAll(list2) && list2.containsAll(list1));
}
正确的答案取决于您要如何使用此类,如果相等性和哈希码需要便宜,请考虑初始化可以轻松比较的构造阵列。这样的东西:
import java.util.Arrays;
public class Triple {
// Use this array only for hashCode & equals.
private final int[] values;
private final int x;
private final int y;
private final int z;
public Triple(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
this.values = new int[]{x, y, z};
// Sort the values for simpler comparison of equality.
Arrays.sort(values);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Triple triple = (Triple) o;
return Arrays.equals(values, triple.values);
}
@Override
public int hashCode() {
return Arrays.hashCode(values);
}
}
添加了一些测试以证明平等和非平等:
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNot.not;
import org.junit.Assert;
import org.junit.Test;
public class TripleTest {
@Test
public void valuesInDifferentOrderAreEqual() {
Triple sortedTriple = new Triple(1, 2, 3);
Triple outOfOrderTriple = new Triple(3, 2, 1);
Assert.assertThat(sortedTriple, equalTo(outOfOrderTriple));
Assert.assertThat(sortedTriple.hashCode(), is(outOfOrderTriple.hashCode()));
}
@Test
public void valuesInOrderAreEqual() {
Triple sortedTriple = new Triple(1, 2, 3);
Triple outOfOrderTriple = new Triple(1, 2, 3);
Assert.assertThat(sortedTriple, equalTo(outOfOrderTriple));
Assert.assertThat(sortedTriple.hashCode(), is(outOfOrderTriple.hashCode()));
}
@Test
public void valuesThatAreDifferentAreNotEqual() {
Triple sortedTriple = new Triple(1, 2, 3);
Triple outOfOrderTriple = new Triple(7, 8, 9);
Assert.assertThat(sortedTriple, not(outOfOrderTriple));
Assert.assertThat(sortedTriple.hashCode(), not(outOfOrderTriple.hashCode()));
}
@Test
public void valuesWithSameSumAreNotEqual() {
Triple sortedTriple = new Triple(11, 21, 31);
Triple outOfOrderTriple = new Triple(36, 12, 21);
Assert.assertThat(sortedTriple, not(outOfOrderTriple));
Assert.assertThat(sortedTriple.hashCode(), not(outOfOrderTriple.hashCode()));
}
@Test
public void valuesWithSameProductAreNotEqual() {
Triple sortedTriple = new Triple(11, 21, 31);
Triple outOfOrderTriple = new Triple(33, 7, 31);
Assert.assertThat(sortedTriple, not(outOfOrderTriple));
Assert.assertThat(sortedTriple.hashCode(), not(outOfOrderTriple.hashCode()));
}
}