JUnit Test und HashCode

werdas34

Bekanntes Mitglied
Hallo,

ich habe als Aufgabe bekommen, ein paar Klassen zu programmieren und diese mit vorgebenen JUnit Test zu testen. Jetzt ist meine Frage wie?
Ich habe einen Ordner und drei .java Dateien. In unseren Skript hies es einfach in die IDE einfügen. Das funktioniert nicht so ganz. Arbeite mit Eclipse. Oder muss man die anderweitig ausführen?

Und zu hashCode. Ich weiß wofür sie da sind und was sie so essentiell macht.
Aber ich weiß nicht genau wie ich selbst eine solche Methode schreibe.
Was ich weiß. Ich brauche eine Primzahl und als Ergebnis eine bei neuen Objekten eindeutige Nummer.
Da es gewisse Java Regeln gibt frage ich hier:
Alles was ich im Internet finde sieht hashCode von anderen Objekten mit ein.
Ich habe aber abstract-Klasse und kein Objekt das irgenwie mitspielt.

Stelle mir das irgendwie so vor:
Code:
int hashCode(){
    int prim = 17;
    int result = 1;

    result = prim*3+result;
    result = result*prim+2;
}
Hoffe ihr wisst was ich meine.

mfg werdas34
 
Aber ich weiß nicht genau wie ich selbst eine solche Methode schreibe.
Was ich weiß. Ich brauche eine Primzahl und als Ergebnis eine bei neuen Objekten eindeutige Nummer.
Da es gewisse Java Regeln gibt frage ich hier:
Alles was ich im Internet finde sieht hashCode von anderen Objekten mit ein.
Ich habe aber abstract-Klasse und kein Objekt das irgenwie mitspielt.

Stelle mir das irgendwie so vor:

Deine gezeigte hashCode in in jedem Fall sinnlos - sie gibt für jedes Objekt den gleiche Wert zurück, man könnte also auch einfach return 86 hinschreiben.


Generell muss jedes relevante Feld deines Objekts mit einbezogen werden (jedes, welches auch in equals benutzt wird). Wenn deine abstrakte Klasse keine Felder hat, kannst du auch hashCode nicht sinnvoll überschreiben.

Josh Bloch hat das ganze recht einfach zusammengefasst:

1. result mit dem hashCode des ersten relevante Feldes initialisieren
* Wenn es ein Objekt ist: Object.hashCode() nutzen
* Wenn es ein primitiver Typ/Array ist: Type.hashCode(value) nutzen (für int z.B: Integer.hashCode(value))​
2. für jedes weitere Feld, dessen Hashcode c berechnen und nach result = 31* result + c mit dem bisherigen verknüpfen.
 
int hashCode(){
int prim = 17;
int result = 1;

result = prim*3+result;
result = result*prim+2;
}
Die Funktion liefert einen konstanten Wert und ist somit keine Hashfunktion.
Ziel einer Hashfunktion ist es unter Anderem anhand eines Objekt ein Wert zu berechnen um dieses schnell identifizieren zu können. Ein wichtiges Kriterium dabei ist es Kollisionen zu vermeiden.
Java:
int hash(  int key ){  return key % 3 ;}
So etwas ist ungeeignet, da alles auf 0,1,3 abgebildet wird.
z.B. könnte man so etwas schreiben.
Java:
public static int hash(String key) {
        int hash = key.length();
        for (int i = 0; i < key.length(); i++)
            hash = ((hash << 5) ^ (hash >> 27)) ^ (int) key.charAt(i);
        return hash;
    }
 
Java:
public interface Room{
/**Liefert die Adresse des Raumes.
* @return the address
*/
public String getAddress();
/**Liefert die Nummer des Raumes.
* @return the roomNumber
*/
public String getNumber();
}

Alle konkreten Klassen für Räume brauchen die gleichen Objektvariablen und den gleichen Code für die Getter des Interface.
Definieren Sie eine abstrakte Klasse BaseRoom, die das Interface implementiert. Wählen Sie
angemessene Modifier für den Konstruktor.
Definieren Sie die Methoden equals und hashCode.


Das ist der Teil mit dem HashCode. Sagt mir bitte wie ich da das machen soll?
Ich weiß, das mein Beipiel nicht so schlau war. hätte irgendwo noch eine statische Variable gebraucht.
 
Java:
public class BaseRoom implements Room {
    private String address;
    private String number;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((address == null) ? 0 : address.hashCode());
        result = prime * result + ((number == null) ? 0 : number.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        BaseRoom other = (BaseRoom) obj;
        if (address == null) {
            if (other.address != null)
                return false;
        } else if (!address.equals(other.address))
            return false;
        if (number == null) {
            if (other.number != null)
                return false;
        } else if (!number.equals(other.number))
            return false;
        return true;
    }

    @Override
    public String getAddress() {
        return address;
    }

    @Override
    public String getNumber() {
        return number;
    }

}

Könnte so aussehen. 🙄😉
 
werdas34 hat gesagt.:
Das ist der Teil mit dem HashCode. Sagt mir bitte wie ich da das machen soll?
Das hier ist das Beste, was ich je zum Thema HashCode lass!
Als Tipp: erstelle eine Klasse X, ganz zwanglos. Vergebe zwei Attribute für die Klasse, als Beispiel String und int. Implementiere die Methode equals(Object obj), dann kannst du die IDE deiner Wahl dazu auffordern, die hashCode-Methode für dich erstellen zu lassen. Dann kommst du auch dahinter, was @Blender3D gemeint hat.

edit: zu spät 🙂
 
Das hier ist das Beste, was ich je zum Thema HashCode lass!
Ich persönlich finde die Implementierung von Bloch aus dem aktuellem Effective Java deutlich besser, zur Erklärung ist das aber super 😉
Das von dir genannte Beispiel sieht auch älter als Java 8 aus, da sind einige neue nützliche Methoden hinzugekommen.
Der Unterscheid ist da im wesentlichen: result = result * 31 +(int)(field>>>32); result = result * 31 + (int)(field & 0xFFFFFFFF) vs result = result * 32 + Long.hashCode(field);

Könnte so aussehen. 🙄😉
Wie praktisch, dass man Aufgaben nicht mehr selbst machen muss...
 
Zuletzt bearbeitet:
Java:
public class BaseRoom implements Room {
    private String address;
    private String number;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((address == null) ? 0 : address.hashCode());
        result = prime * result + ((number == null) ? 0 : number.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        BaseRoom other = (BaseRoom) obj;
        if (address == null) {
            if (other.address != null)
                return false;
        } else if (!address.equals(other.address))
            return false;
        if (number == null) {
            if (other.number != null)
                return false;
        } else if (!number.equals(other.number))
            return false;
        return true;
    }

    @Override
    public String getAddress() {
        return address;
    }

    @Override
    public String getNumber() {
        return number;
    }

}

Könnte so aussehen. 🙄😉
Ok. Danke. Jetzt verstehe ich das auch.
Aber jetzt noch zwei Fragen:
Werden immer alle Objektvariablen zur Berechnung mit einbezogen? Also wenn ich 20 Objektvariablen habe dann eben auch 20 Berechnungen?
Und wenn ich jetzt eine konkrete Klasse habe, die von BaseRoom erbt. Ändert sich da am Design von HashCode was? Spielt der hashCode der BaseRoom eine Rolle?
 
Werden immer alle Objektvariablen zur Berechnung mit einbezogen? Also wenn ich 20 Objektvariablen habe dann eben auch 20 Berechnungen?
Alle die Felder, die relevant für die "Identität" des Objekte sind (im Idealfall auch nur die, die sich nie ändern).

Und wenn ich jetzt eine konkrete Klasse habe, die von BaseRoom erbt. Ändert sich da am Design von HashCode was? Spielt der hashCode der BaseRoom eine Rolle?
Wenn es nötig ist, den zu überschreiben (zB, weil relevante Felder hinzukommen), muss man das entsprechend überschreiben.
hashCode der super-Klasse spielt dann eine Rolle, wenn sie nicht überschrieben ist, oder wenn man sie beim überschreiben explizit aufruft (zB, wenn ein weiteres Feld betrachtet werden muss, dann ruft man erst die super-Methode auf, und verknüpft das Ergebnis mit dem einem Feld)
 
@mrBrown
Jepp, das stimmt, aus dem Jahre 2002 😀 Verlieh mir jedoch die Machete für mein intellektuelles Dickicht!
Es scheint ein sehr gutes Buch zu sein, laut Amazon 5 Sterne.. Das habe ich bis jetzt noch nicht gesehen, ist es wirklich so gut? Bis jetzt kann ich es von keinem Buch behaupten, mich über die Länge zu 100% mitgenommen zu haben.
 
Es scheint ein sehr gutes Buch zu sein, laut Amazon 5 Sterne.. Das habe ich bis jetzt noch nicht gesehen, ist es wirklich so gut? Bis jetzt kann ich es von keinem Buch behaupten, mich über die Länge zu 100% mitgenommen zu haben.
Ich würde es vorbehaltlos empfehlen, alles was drin steht, sollte man als Java-Entwicker irgendwann mal gelesen haben. Es ist aber eher nichts, was man am Stück lesen würde.

(wenn man einfach mal nach "effective java pdf" googlet, findet man "bestimmt" eine ältere Ausgabe als PDF, da kann man mal reinschnuppern 😉 )
 

Neue Themen


Zurück
Oben