2017-02-22 20 views
0

У меня есть тройной класс, который является классом, который может содержать 3 целых числа (x, y, z). Я хочу переопределить методы equals/hashcode, чтобы они могли использоваться в наборе. Таким образом, obj с (1,2,3) должен быть равен (3,2,1) или (3,1,2) и поэтому должен быть равен любой из его перестановок. Я знаю, как сделать это для класса Пара с (х, у) - код для класса пары у меня есть для этого:Переопределение равных и hashcode для класса Triplet В java

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

Это прекрасно работает, но если я хочу продлить это тройной класс , Я знаю, что могу редактировать метод equals и добавлять дополнительные условия для проверки, но это кажется очень длинным. Есть ли способ сделать это без использования внешних библиотек в Java?

+2

Почему это кажется очень долго? – BackSlash

+0

Ваш метод equals * не * сравнивает перестановки. – shmosel

+0

Однако, вот подсказка, чтобы сделать ее «короче». У вас может быть метод под названием 'asList()' в вашем классе 'Triplet', который возвращает три элемента в виде списка и возвращает' thisList(). ContainsAll (other.asList()) '- Но я думаю, что это ужасный способ решить проблему. Хороший способ - использовать 'if' и проверить все необходимые условия. – BackSlash

ответ

5

Одним из решений является сохранение отсортированного массива для сравнения:

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); 
    } 
} 
+0

Может быть полезно перемещать сортировочную часть внутри метода 'equals'. Если OP будет реализовывать методы 'setX',' setY', 'setZ', ему придется сортировать массив каждый раз, когда вызывается один из этих методов. Если вы перемещаете сортировку внутри равных, это должно сделать вещи светлее, поскольку вы сортируете только один раз, когда вам нужно. – BackSlash

+2

«Если OP собирается реализовать setX, setY, setZ methods», лучше еще и не сохранять «Triple» неизменяемым –

+1

@BackSlash Я предположил, что класс неизменен (обратите внимание на модификаторы 'final'). Если это не так, вам придется сортировать их при каждом вызове 'equals()' или 'hashCode()', что я определенно хочу избежать. – shmosel

0

Для проверки комбинаций, вы можете добавить элементы в 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)); 
} 
0

Правильный ответ зависит от того, как вы хотите использовать этот класс, если равенства и 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())); 
    } 
} 
Смежные вопросы