在 java 中覆盖三元组 Class 的等于和哈希码
Overriding equals and hashcode for a Triplet Class In java
我有一个三元组 class,它是一个 class,可以包含 3 个整数 (x,y,z)。我想覆盖 equals/hashcode 方法,以便它们可以在集合中使用。因此具有 (1,2,3) 的对象应该等于 (3,2,1) 或 (3,1,2),因此应该等于它的任何排列。我知道如何为一对 class 和 (x,y) 执行此操作 - 我拥有的一对 class 的代码是:
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);
}
}
这很好用,但如果我想将其扩展到三元组 class,我知道我可以编辑 equals 方法并添加更多条件来检查,但这看起来真的很长。有什么方法可以在不使用 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));
}
正确的答案取决于你想如何使用它class,如果相等和 hashCode 需要便宜,那么考虑在构造时初始化一个可以很容易比较的数组。像这样:
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()));
}
}
我有一个三元组 class,它是一个 class,可以包含 3 个整数 (x,y,z)。我想覆盖 equals/hashcode 方法,以便它们可以在集合中使用。因此具有 (1,2,3) 的对象应该等于 (3,2,1) 或 (3,1,2),因此应该等于它的任何排列。我知道如何为一对 class 和 (x,y) 执行此操作 - 我拥有的一对 class 的代码是:
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);
}
}
这很好用,但如果我想将其扩展到三元组 class,我知道我可以编辑 equals 方法并添加更多条件来检查,但这看起来真的很长。有什么方法可以在不使用 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));
}
正确的答案取决于你想如何使用它class,如果相等和 hashCode 需要便宜,那么考虑在构造时初始化一个可以很容易比较的数组。像这样:
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()));
}
}