Wie mach ich ein HashSet für eigene Objecte?

  • Themenstarter Themenstarter Guest
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Code:
package crawler.path;

import java.util.HashSet;

/**
 *
 * @author 
 */
public class paths extends HashSet<crawlDing>{

    
    
    
}

Code:
public class crawlDing {

    String s1,s2;

    public crawlDing(String s1, String s2) {
        this.s1 = s1;
        this.s2 = s2;
    }

    @Override
    public boolean equals(Object obj) {
        crawlDing cd=(crawlDing) obj;
        return true;
    }
    
}

also wenn ich jetzt
Code:
 quequed.add(new crawlDing("asdf", "asdf"));
        quequed.add(new crawlDing("asdf", "asdddf"));
       System.out.println(quequed.contains(new crawlDing("asdf", "asdf")));
bekomme ich trotzdem immer false zurück. Warum?
Wie mach ich es das HashSet überprüft ob die Strings in der Klasse CrawlDing gleich sind?
 
das wichtigste bei einem HashSet ist offensichtlich der Hash-Wert

überschreibe die hashCode()-Operation so, dass gleiche Objekte den gleichen Hashcode zurückgeben
(z.B. die Summer der Hashcodes der beiden enthaltenen Strings)

das ist übrigens auch ein allgemeines Java-Gesetz:
equals und hashCode müssen zusammenpassen
(genauer Laut in der API bei Object nachzulesen/ Lehrbuch/ oder postet noch jemand 😉 )

standardmäßig entspricht der Hashcode etwa der Speicheradresse des Objektes
-> unterschiedliche Objeke haben unterschiedlichen Wert -> nicht gleich im Set
 
also bedeuted das, das ich hash code überschreiben muss?

oder soll ich ne andere collection verwenden?
 
habs jetzt so gemacht:
Code:
  public int hashCode() {
        return path.hashCode()+type;
    }

    @Override
    public boolean equals(Object obj) {
        return obj.hashCode()==this.hashCode();
    }

oder soll ich ne andere collection verwenden?
 
wenn es so wäre dann wäre doch hashcode nur gleich wenn auch vergleich mit == true wäre.
Die Standard Implementierung verhält sich so wie von SlaterB beschrieben, die Java 5 API Dok enthält eigentlich alles was man zu diesem Thema Wissen müsste:
hashCode

public int hashCode()

Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable.

The general contract of hashCode is:

* Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
* If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
* It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#hashcode
 
> dann wäre doch hashcode nur gleich wenn auch vergleich mit == true wäre.

weitgehend richtig, siehe aber aber auch b) weiter unten

> aber der is doch auch gleich wenn nur der inhalt gleich is...

falsch oder Gegenbeispiel nennen 😉
dass es für bestimmte Objekte wie String anders aussieht,
ist unbestritten

---------

> habs jetzt so gemacht:

> public int hashCode() {
> return path.hashCode()+type;
> }


ohne zu wissen was path und type ist, kann man dazu kaum was sagen,
sieht aber gut aus,
die equals-Operation halbwegs ok, aber gefährlich, 3 Hinweise:
a) funktioniert nur dann einigermaßen, wenn hashCode alle enthaltenen Felder berücksichtigt,
übrigens könnte die hashCode()-Berechnung aufwändiger als andere Überprüfungen sein,
bei zwei String kann man anhand der Länge die meisten Unterschiede sofort erkennen, da muss nicht unbedingt der hasCode über jeden Buchstaben einzelnd errechnet werden

b) du hast noch die Gefahr, dass dein Hashcode zufällig dem eines anderen Objektes entspricht, welches nicht equal ist,
es gibt nur Integer.MAX_VALUE Hashcodes,
aber bestimmt viel mehr Möglichkeiten, etwa Strings der Länge 10 oder höher bei den Unmengen an verschiedenen Buchstaben,

aus equal folgt zwingend gleicher Hashcode, aber gleicher Hashcode heißt normalerweise nicht immer equal,
ist zwar wahrscheinlich und daher so nützlich für das HashSet,
aber nicht zwingend

c) auch ein Objekt einer ganz anderen Klasse könnte den gleichen Hashcode haben

-----------

> oder soll ich ne andere collection verwenden?

für TreeSet musst du glaube ich Comparable implementieren,
aber schaue dir doch mal alle verfügbaren Sets an,
nur mit equals wirds knapp,
dann kannst du aber immer noch eine normale Liste nehmen und vor jedem Einfügen contains() prüfen, das läuft die ganze Liste durch und verwendet nur equals()
 
SlaterB hat gesagt.:
> dann wäre doch hashcode nur gleich wenn auch vergleich mit == true wäre.

weitgehend richtig, siehe aber aber auch b) weiter unten

> aber der is doch auch gleich wenn nur der inhalt gleich is...

falsch oder Gegenbeispiel nennen 😉
dass es für bestimmte Objekte wie String anders aussieht,
ist unbestritten
naja ich hab hashcode() bisher net verstanden
und werds wohl net verstehen.
ich seh darin kein sinn, was der mir zeigen soll.
will ich gleiche speicheradresse wissen dann ==
will ich gleichen inhalt wissen dann equals
also für was hashcode, wobei da doch auch immer wie du auch gesagt hast, die gefahr kommt das 2 verschiedene objekte den gleichen haben.

also falls einer mir das mal erklären will, nach dem motto "hashcode für dummies", schreibt hier oder ne pn, falls offtopic werden würde^^
 
Die einfachste Art mit equals und hashcode umzugehen ist: Sie nicht zu überschreiben 🙂

Ansonsten wird's immer kompliziert...

Ein anderes Problem:
Angenommen der hashcode (und damit equals auch) eines Objektes beruht auf dem Wert von ein paar Attributen anstatt wie in der Standardimplementierung auf der Addresse des Objektes.

Was passiert, wenn ich ein Objekt in eine Hash-Table/Set/Map ablege, und sich danach die Attribute auf dem der hashcode beruht ändern?
Das Objekt würde man nie wieder in der Hash-Table/Set/Map finden, zumindest nicht über den hashcode, schliesslich hat sich der hashcode des Objektes im nachhinein geändert... damit so etwas funktioniert, müsste man die Objekte als Immutables entwerfen.

Punkt 7 und 8 in "Effective Java Programming" geht im Detail auf die Problematik um equals und hashcode ein.
 
ach das ist ja so ein schönes Thema, da erzähle ich dann gerne weiter,
statt auf Bücher zu verweisen 😉


HashCode ist z.B. für die Doppelten-Suche gedacht, wie hier gewünscht,

schlecht wäre, die Objekte in eine Liste zu stecken und dann mit contains die ganze Liste zu durchlaufen und mit jedem Objekt zu vergleichen,

bei einem Vergleich muss jedesmal von vorne, bei 0 angefangen werden,
schlauer ist dagegen, einen Index aufzubauen, alle Elemente EINMAL auf eine Zahl, 1, 2, 3, 454664 usw. abzubilden,
diese Zahlen berechnet man einmal und speichert sie geeignet,
Zahlen kann man ja gut sortiert ablegen und schnell wiederfinden

dann berechnet man für ein neues Element nur EINMAL den Hashcode, z.B. 4745, und schaut nach, ob schon Elemente zu 4745 da sind,
da die Anzahl der Zahlen begrenzt ist, können das durchaus auch mehrere Elemente zum Hashcode da sein sein,
aber bei einer guten Hash-Funkion eben durchschnittlich höchstens 0,00...01% aller Elemente,
für diese muss dann ganz trivial jeweils equals aufgerufen werden

auch Maps können so arbeiten, ist ja im wesentlichen die Suche nach den Keys,

------------

vereinfachtes Beispiel: CD/ Bücher-Regal nach ersten Buchstaben sortieren, das ist die Hashfunktion, die Werte sind A-Z,
wenn du ein Buch names "Bibel" suchst, musst du dann nur noch die B-Bücher alle durchschauen, nur noch 1/ 26 der Arbeit,
die Berechnung des ersten Buchstabens (B) und die Markierung im Bücherregal, wo B anfängt und aufhört sind dagegen ein geringer Zusatzaufwand
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben