Własne porównanie obiektów na potrzeby set

0

Hej,

Mam taką oto prostą klasę Punkt:

public class Point {
	public int X;
	public int Y;
	
	public boolean equals(Point otherPoint) {
		return ((X == otherPoint.X) && (Y == otherPoint.Y));
	}
}

Jak zrobić, aby kolekcja set widząc, że chcę włożyć punkt, ktory już istnieje w zbiorze, nie pozwalała na to? Jak wyżej, próbowałem z equals, ale coś nie działa. Bo wyniki mam i tak:

X = 1
Y = 1

X = 1
Y = 1
 

Albo, czego używa set w celu porównania obiektów, domyślam się, że raczej to powinno być equals.

Czyli:

Set<Point> unique_items = new HashSet<Point>();

Point p1 = new Point();
p1.X = 1;
p1.Y = 1;
		
Point p2 = new Point();
p2.X = 1;
p2.Y = 1;
		
unique_items.add(p1);
unique_items.add(p2);
		
Iterator<Point> it = unique_items.iterator();
		
while( it.hasNext() ) {
	Point p = it.next();
			
	System.out.println("\nX = " + p.X);
	System.out.println("Y = " + p.Y);
}

Dzięki za pomoc

1

Hashset używa metody hashCode do porównania obiektów. Musisz ją nadpisać razem z equals.

1

Pierwsza zasada przeciążania equals: Metody equals i hashCode przeciążamy razem.

Przeciążając jedną, musisz przeciążyć drugą, u gdy a.equals(b) to jednoczesnie a.hashCode()==b.hashCode().

Nie próbuj też robić tego sam. Nie ma sensu. Po prostu użyj odpowiedniej funkcji IDE żeby ono wygenerowało to za Ciebie. Nie popełnisz błędu, a np. Twoja implementacja jest nieodporna na null reference.

2

To nie jest do końca prawda że metoda hashCode jest używana do porównania obiektów. Metody hashCode i equals są ze sobą powiązane i powinny być implementowane obie. Mówi się o "kontrakcie hashCode/equals", który jest wspomniany w javadoc https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode%28%29.

Mówiąc obrazowo hashCode zwraca numerek przyporządowujący do przedziału a equals użyty jest do porównania w ramach danego przedziału. Jeśli kontrakt hashCode/equal nie jest zachowany te same obiekty (w sensie equals) mogą być przyporządkowane do różnych przedziałów (różna wartość zwracana przez hashCode).

1

Ponadto metoda equals w klasie Point ma złą sygnaturę, powinno być - w uproszczeniu - tak:

    public boolean equals(Object ob) 
    {
        Point otherPoint = (Point)ob;
        return ((x == otherPoint.x) && (y == otherPoint.y));
    }

W standardowej bibliotece Javy (java.awt) jest klasa Point. Dla ciekawych:

    public int hashCode() {
        long bits = java.lang.Double.doubleToLongBits(getX());
        bits ^= java.lang.Double.doubleToLongBits(getY()) * 31;
        return (((int) bits) ^ ((int) (bits >> 32)));
    }
    public boolean equals(Object obj) {
        if (obj instanceof Point) {
            Point pt = (Point)obj;
            return (x == pt.x) && (y == pt.y);
        }
        return super.equals(obj);
    }
0

Ok, teraz działa, dzięki za pomoc, problemem był brak funkcji hashCode().

public int hashCode() {
		StringBuffer buffer = new StringBuffer();
		buffer.append(this.X);
		buffer.append(this.Y);
		return buffer.toString().hashCode();
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1