Equal Methode implementieren

Thisor

Bekanntes Mitglied
Hey,
in 2 Wochen schreibe ich in OOP ein Testat und bearbeite gerade alle Aufgaben durch. Zu der jetztigen Aufgabe die Aufgabenstellung:

1.) Erstellen Sie eine Klassenhierarchie für Bücher, CD und Filme: Die oberste Klasse lautet BibItem. Als Schlüssel dient eine id (int) und titel (String)
2.) Implementieren Sie die Methode toString() wie folgt: Ausgabe der id und des Titels. Bücher geben zustl. Seitenzahl aus, CD´s die Gruppe(Sänger), und Filme die Dauer(in Minuten).
3. Implementieren Sie die Methode equals(): 2 Objekte sind gleich, wenn die Werte ihre id übereinstimmen.
4.) Erstellen Sie für die Methode equals() folgende JUnit Testfälle:
a. Vergleich it null(false)
b. Vergleich eines Objekts mit sich selbst (true)
c. Vergleich zweier unterschiedlicher Objekte(false)
d. Vergleich zweiter Objekte (mit unterschiedlichen Referenzen), die die gleiche id haben (true)
5.) Bin noch nicht soweit..
6.)..
7.)..
8.)..
9.)..

mein jetztiger Code von Aufgabe 1-2:
die Superklasse
Code:
package main;

public class BibItem {

    int id;
    String titel;

    public BibItem(int id, String titel) {

        this.id = id;
        this.titel = titel;

    }

    public static void main(String[] args) {

    }

    @Override
    public String toString() {
//noch anpassen
        return "BibItem [id=" + id + ", titel=" + titel + "]";
    }

}

Die Unterklasse (hier nur Bücher, CD und Fime sehen gleich aus, nur eben angepasst):
Code:
public class Buecher extends BibItem {

    private int seitenzahl;

    public Buecher(int id, String titel, int seitenzahl) {
        super(id, titel);
        this.seitenzahl = seitenzahl;

    }

    @Override
    public String toString() {
        return super.toString() + "Seitenzahl : " + seitenzahl;
    }

}
Wie implementiere ich die equalMethode? Und dann am besten in einer neuen Klasse oder in die Superklasse?
Lg
 
Zuletzt bearbeitet:
ich würde es in der Superklasse machen

z.b.
main ....
Buecher buch1 = new Buecher(1,"buch1",233);
Buecher buch2 = new Buecher(2,"buch2",457);

und dann eine methode
Code:
public boolean isEqual(BibItem item1, BibItem item2){ // vllt. ist hier private besser und evtl. muss die Methode static sein, bin mir jetzt gerade nicht sicher
    if(item1.id == item2.id){
       return true;}
     else{
        return false;
     }
}

der Aufruf lautet dann
...
boolean e = isEqual(buch1,buch2); // in diesem Fall wird b false, da 1 != 2 ist

btw. anstatt Buecher würde ich die Klasse Buch nennen, Klassen werden norm. im Singular benannt
 
Zuletzt bearbeitet:
Hab gerade gesehen, das man die equals Methode auch einfach generieren lassen kann. Werden aber auch Sachen generiert, die man gar nicht braucht. Jetzt hab ich´s so:
Code:
package main;

public class BibItem {

    int id;
    String titel;

    public BibItem(int id, String titel) {

        this.id = id;
        this.titel = titel;

    }

    public static void main(String[] args) {

    }

    @Override
    public String toString() {
        return "BibItem [id=" + id + ", titel=" + titel + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;

        BibItem other = (BibItem) obj;
        if (id != other.id) {
            return false;
        }
        return true;
    }
}

Kann ich für die MainMethode dennoch eine neue Klasse erstellen oder gibt es sowas wie Richtlinien die besagen, dass MainMethode besser in der Superklasse aufgehoben sind oder so?

Edit:
Ich muss ja noch im Methodenkopf von equals den Parameter Object zu BibItem umändern und dann @Override rausnehmen. Liegt @Override an Object und wäre dann Object überschrieben/umgeändert wenn ich´s nicht umgeändert hätte?
 
Kann ich für die MainMethode dennoch eine neue Klasse erstellen oder gibt es sowas wie Richtlinien die besagen, dass MainMethode besser in der Superklasse aufgehoben sind oder so?

Um deine Aufgabe zu erfüllen, brauchst du keine main-Methode.
In deiner Superklasse ist sie sowieso nicht besonders gut aufgehoben, wenn du dennoch eine haben möchtest, dann lieber in einer eigenen Klasse.
 
In der letzten Aufgabe muss ich eine MainMethode erstellen, aber das habe ich nicht dazu geschrieben und habe sie jetzt schon erstellt 😛

Für die Erstellung von JUnit-Tests muss ich dazu eine normale Klasse erstellen oder eine JUnit Test Case-Klasse?
 
Ich bekomme den letzten Test nicht zu laufen und bin leicht am verzweifeln, habe versucht per punktnotation auf id zuzugreifen, geht aber nüüch...und den gesamten mainpaket bekomme ich nicht hin zu importieren, wie geht das? hab nur die Klasse buch importieren können. Wenn ich alles importieren könnte dann müsste es doch klappen oder...zumindest müsste ich auf id zugreifen können??
Auf jeden Fall sieht es so bisher aus:
Vergleich zweier Objekte (mit unterschiedlichen Referenzen), die die gleiche id haben (true)

Code:
package test;

import static org.junit.Assert.*;
import main.Buch;

import org.junit.Before;
import org.junit.Test;

public class TestFälle {


    @Test
    public void vergleichMitNull() {
        Buch buch2 = new Buch(25, "König der Löwen", 1021);
        Buch nullbuch = null;
        assertFalse(buch2.equals(nullbuch));

    }

    @Test
    public void mitSichSelbst() {
        Buch buch1 = new Buch(12, "Das Buch", 422);
        assertTrue(buch1.equals(buch1));
       
    }

    @Test
    public void unterschiedlicheObjekte() {

        Buch buch2 = new Buch(25, "König der Löwen", 1021);
        Buch buch4 = new Buch(10, "Das große Fressen", 740);
        assertFalse(buch2.equals(buch4));

    }

    @Test
    public void vergleichZweierObjekte() {

         Buch buch4 = new Buch(10, "Das große Fressen", 740);
         Buch buch3 = new Buch(10, "Der Salamander", 822);
         assertTrue(buch4.equals(buch3));

    }
}
 
In Deinen Unit-Tests fehlt noch ein wichtiger Test: Der equals Aufruf mit einer Instanz, die kein Buch ist.

So Dein equals noch so implementiert ist wie im gezeigten Code, dann erwarte ich eine NPE - da fehlt somit in meinen Augen noch etwas ...

Ansonsten kann ich thecain nur zustimmen - mit dem Debugger sollte das Problem doch schnell zu finden sein.

Konrad
 
Hallo Thisor,

in Bezug auf kneitzel schmeiße ich dir mal den "instanceof-Operator" vor die Füße, mit dem du gleich 2 Fälle ausschließen kannst 🙂

Grüße Coco07
 
Ohh ja - wo ich Deinen Beitrag lese coco07, da fällt mir auf, dass ich da auch ein Denkfehler habe. Der Cast geht natürlich in die Hose und das gibt keine NPE sondern natürlich eine ClassCastException. (Mein Denkfehler kommt, da ich halt sonst im .Net Umfeld tätig bin und da dann halt etwas wie BibItem other = obj as BibItem; stehen würde, was null ergibt, wenn der cast nicht möglich ist...)
 
hm..vllt hab ich mich ein wenig doof oder ungeschickt ausgedrückt.
Der letzte Testfall soll 2 verschiedene Objekte mit unterschiedlichen Referenzen vergleichen, die aber dieselbe id haben (soll true sein)
der code:
Code:
  @Test
    public void vergleichZweierObjekte() {

         Buch buch4 = new Buch(10, "Das große Fressen", 740);
         Buch buch3 = new Buch(10, "Der Salamander", 822);
         assertTrue(buch4.equals(buch3));

    }
Ich muss nicht mit dem Debugger reingehen um zu sehen dass hier buch4 und buch3 nicht gleich sind. Beide haben zwar denselben id, aber hier wird ja noch zusätzlich auch der titel überprüft...Wenn ich mit dem Debugger reingehe dann sagt der mir auch nicht wie ich das ausbessern kann 😀

@kneitzel Die Instanz keinBuch fehlt wahrscheinlich weil es in der Aufgabe nicht verlangt wird 😛
Was ist eine ClassCastException?
 
Wie sieht denn die equals von Buch aus? Oben gibt es nur eine von BibItem, welche nur die IDs vergleicht. Da diese im Testfall übereinstimmen und die equals nur nach den IDs schaut, wird dein Test auch sagen, dass die Objekte gleich sind, selbst wenn andere Eigenschaften (Titel, Seitenzahl) verschieden sind.
 
Oh..war vorher so, also mit titel:
Code:
public boolean equals(BibItem obj) {
     if (this == obj)
       return true;
     if (obj == null)
       return false;

     BibItem other = (BibItem) obj;
     if (id != other.id)
       return false;
     if (titel == null) {
       if (other.titel != null)
         return false;
     } else if (!titel.equals(other.titel))
       return false;
     return true;
   }


nun sieht sie so aus und es läuft:
Code:
    public boolean equals(BibItem obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;

        BibItem other = (BibItem) obj;
        if (id != other.id)
            return false;
        if (titel == null) {
            if (other.titel != null)
                return false;
        }
        return true;
    }
also eigtl hab ich nur else if rausgenommen...aber sollte vermutlich alles mit titel rausnehmen^^
 
Also: Der Debugger dienst dazu um im Detail zu sehen, was passiert. Wenn Du hier die Frage aufwirfst, wieso da irgendwas false ist und nicht true oder so, dann ist die Antwort tatsächlich: Nimm den Debugger und üb den Umgang damit. Dann siehst Du im Detail, was abgeht und Du kannst Deinen Code berichtigen.

Und Java kommt schon mit sehr vielen Klassen. Dann vergleich doch mal, ob ein Buch von Dir equals("abc") ist oder equals(new Object()). Dann lernst Du auch, was eine ClassCastException ist, denn Du versuchst dann einen String oder ein Object in ein BibItem zu casten und das geht nicht. Daher der Hinweis, instanceof zu verwenden! Und der Vergleich der Titel ist ja noch nicht vollständig. Hier würde ich erst die Reference prüfen und wenn die Reference der Strings nicht gleich ist, dann würde ich erst auf null prüfen und bei ungleich null einen Vergleich der Strings durchführen.

Konrad
 
mh jaa ich mag den Debugger nicht, würde am liebsten sofort zur Lösung kommen 😀 gibt aber wohl keine Ausweichsmöglichkeit und gehört anscheinend zum programmieren dazu *grümel* ist halt so, sollte mich nicht mehr so anstellen.

instanceof sowie ClasscastException hatten wir bisher nicht (vermutlich sind die Aufgaben einfach so aufgebaut, dass es nicht zu einer ClassCastException kommen konnte bisher, außer man vertippt sich^^') und wird dieses Semester auch nicht mehr erwähnt, denk ich mal(sind halt so gut wie mit dem Stoff durch).
Die Aufgabe besagt ja selbst das ich Objekte verlgeichen soll, daher sehe ich mich gerade auch nicht gezwungen wieso ich hier jetzt mit equals(String) arbeiten/testen soll statt mit equals(new Object()). Zumindest seh ich den Grund hierzu nicht ( sorry wenn ich mich doof anstelle, die Testate stehen vor der Türe und die Prüfungen lächeln auch schon einen an, will mich jetzt nicht mit neuem Stoff auseinander setzen müssen..)

Die Referenzen muss ich hier doch gar nicht in Betracht ziehen sondern bloß die id...
Ich könnte, damit die Aufgabe erfüllt ist, doch alles was mit titel ist, aus equal auslassen. Wenn ich mich irre, lehrt mich eines besseren.
 
Also ich weiss nicht, was da im Kurs von euch verlangt wird und was nicht. Da ich den Kurs nicht besuche und keinerlei Details kenne (und mich das auch ehrlich nicht interessiert) werde ich dazu auch keine Aussage machen können.

Aber wenn es um das Implementieren einer equals Methode geht, dann sieht man ganz einfach einen Fehler in Deiner Implementation. So kann equals mit einem beliebigen Objekt aufgerufen werden. Und du machst einen cast auf deine Klasse ohne vorab zu prüfen, ob das überhaupt geht. Dies ist schlicht ein Fehler in der Implementation. Das mag für deinen Kurs und die dort Verantwortlichen ok sein. Aber ich denke, dass andere hier mir durchaus Recht geben werden, dass dies ein Fehler ist und wenn Du willst, kannst Du es gerne selbst ausprobieren - zwei mögliche Tests habe ich Dir genannt (Einmal einen String übergeben und einmal eine Instanz von Object - beides ist nicht null, die Referenz ist unterschiedlich und der Cast wird die genannte Exception werfen.

Wenn Du alles einfach nur machst, weil es gefordert ist, dann ist das ok. Aber Unit-Tests sollten alle Testfälle abdecken. Und wenn equals ein Object als Parameter bekommt, dann lässt sich da eine beliebige Instanz einer Klasse übergeben. Wie sinnvoll diese Tests sind zeigen sich ja schon dadurch, dass da bei Dir ein Fehler auftreten würde.

Was Du in equals abprüfen sollst, mag definiert sein. Wenn nur die id geprüft werden soll, dann musst Du den titel in keiner Weise mit anpacken. Aber in einem Codeschnipsel hattest Du auch etwas mit dem titel drin, weshalb ich diesen Code hinterfragt habe.

Konrad
 
Also ich weiss nicht, was da im Kurs von euch verlangt wird und was nicht. Da ich den Kurs nicht besuche und keinerlei Details kenne (und mich das auch ehrlich nicht interessiert) werde ich dazu auch keine Aussage machen können.
Versteh ich, mich würds umgekehrt auch nicht interessieren.

Ich weiß jetzt nich ob ich´s richtig verstanden habe oder so:
Code:
@Test
    public void vergleichZweierObjekte() {

         Buch buch4 = new Buch(10, "Das große Fressen", 740);
         Buch buch3 = new Buch(10, "Der Salamander", 822);
         assertTrue(buch4.equals("abc"));
Somit kommt ein Fehler mit:
java.lang.AssertionError
at test.TestFälle.verleichZweierObjekte(TestFälle.java:41)
Und um das vorzubeugen soll ich instanceof anwenden? Dann im equal?
Ich glaub ich versteh das nicht so ganz.
Wenn man sofort sieht dass ich einen cast auf eine Klasse führe ohne das zu überprüfen, dann fehlt ja was. Instanceof übernimmt dann diese Aufgabe?
Ich bin sowas von ein Grünschnabel -.-

Was Du in equals abprüfen sollst, mag definiert sein. Wenn nur die id geprüft werden soll, dann musst Du den titel in keiner Weise mit anpacken. Aber in einem Codeschnipsel hattest Du auch etwas mit dem titel drin, weshalb ich diesen Code hinterfragt habe.
Ja, richtig. Habe es einfach generieren lassen und habe dann schlampig gearbeitet. Also nicht alles raus genommen, war mein Fehler 🙁
 
Instanceof liefert true, wenn die Reference eine Instanz von der angegebenen Klasse ist. Wenn die Reference null ist oder eben der Typ nicht stimmt, dann wird false zurück geliefert.

Code:
public boolean equals(BibItem obj) {
        if (this == obj)
            return true;
        if (!(obj instanceof BibItem))
            return false;

        BibItem other = (BibItem) obj;
        if (id != other.id)
            return false;
  
      return true;
    }

Das wäre dann eine Möglichkeit, so nur die id geprüft werden soll.

Konrad
 
Okay, also wird dadurch überprüft ob es überhaupt eine Instanz von BibItem ist oder nicht. Und CastClassException ist quasi, wenn es ebene keine Instanz von BibItem wäre, es aber trotzdem versucht zu casten und eben nicht klappt?
Diesen Fall haben wir hier ja dann mit der if abfrag abgefangen. Dann kann ich gar kein CastClassException mehr bekommen?
 
Ich mach dann mal hier weiter:
6.) Erstellen Sie die Implementierung des Interface List für die Ausleihe (KlasseBibList). Ein Objekt darf nicht doppelt in der Liste vorkommen!

Ich muss also ein Interface erstellen und mit ArrayList arbeiten. Begleitend habe ich noch zusätzlich das hier offen -> http://openbook.rheinwerk-verlag.de/javainsel9/javainsel_13_003.htm

Was ich noch nicht so ganz verstehe ist der Ablauf bzw die Reihenfolge:
Ich habe ein Interface (Klassenname : IList) erstellt und eine weitere Klasse für die List (BibList).
Im Interface muss ich eine neue ArrayList erzeugen aus BibItem. Das so aussieht:
Code:
import java.util.ArrayList;

public interface IList   {
   
    ArrayList<BibItem> liste = new ArrayList<BibItem>();

}

und in BibList muss ich dann das Interface implementieren:
Code:
import java.util.List;

public class BibList implements IList {
   
    private List<BibItem> liste;
   
   
}

Und zum schluss habe ich noch in der Klasse BibItem die get- und setMethoden für id und titel generieren lassen.

Muss ich da nicht mit nem Konstruktor arbeiten? Bei mir wurde er zumindest nicht automatisch erstellt und das verwirrt mich n bisschen 😕
 
Habe mir die Frage selbst beantworten können 😀 am besten ist es glaub wenn man setter und getter zuerst, wenn schon nicht von anfang an, generieren lässt. Dann das Interface mit ArrayList erstellen...und jetzt hab ich´s wieder vergessen, aber der Konstruktor kam dann doch von selbst 🙂

Ich bin alle Aufgaben durch und bin mit dem Blatt fertig.
7.) Erstellen Sie Unit-Tests für die add-Methode(4unterschiedliche Fälle)
8.) Nehmen Sie mindestens 5 Objekte in die Liste auf (im Unit-Test). Versuchen Sie auch, ein Objekt mehrfach aufzunehmen.
9.)Erstellen von MainMethode und mit JF_Window ausgeben.

Ich habe keine Ahnung wie ich Unit-Tests für die add-Methode anwende. Ich habe bloß nur die elemente in die Liste hinzugefügt. Wäre super wenn mir hier jemand nochmal entgegen kommt.

Das Interface:
Java:
import java.util.ArrayList;

public interface IList {

    void hinzufuegen(BibItem element);

    ArrayList<BibItem> liste = new ArrayList<BibItem>();

}
( @kneitzel Habe mir das was du gesagt hast nochmal angeschaut aber viel schlauer wurde ich trotzdem nicht :/)
BibItem:
Java:
public class BibItem {

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitel() {
        return titel;
    }

    public void setTitel(String titel) {
        this.titel = titel;
    }

    int id;
    String titel;

    public BibItem(int id, String titel) {

        this.id = id;
        this.titel = titel;

    }

    @Override
    public String toString() {
        return "BibItem ID : " + id + " Titel : " + titel;
    }

    public boolean equals(BibItem obj) {
        if (this == obj)
            return true;
        if (!(obj instanceof BibItem))
            return false;

        BibItem other = (BibItem) obj;
        if (id != other.id)
            return false;
      return true;
    }

}

BibList bzw ArrayList:
Java:
public class BibList implements IList {

    private List<BibItem> list;

    public BibList() {
        list = new ArrayList<BibItem>();
    }

    @Override
    public void hinzufuegen(BibItem element) {
        // TODO Auto-generated method stub
        if (!(list.contains(element))) {
            list.add(element);

            System.out.println("Das Objekt " + element.getTitel()
                    + " wurde hinzugefügt!");
        } else
            System.out.println("Das Objekt " + element.getTitel()
                    + " ist bereits vorhanden.");

    }

    public List<BibItem> getList() {
        return this.list;
    }
}

und die mainmethode mit der Liste :
Code:
    public static void main(String[] args) {

        BibList dieNeueListe = new BibList();
      
      
        Buch buch1 = new Buch(22, "The Gamer", 444);
        Buch buch2 = new Buch(13, "Life is Strange", 728);
        Buch buch3 = new Buch(17, "Der Herr der Ringe", 1001);
        Buch buch4 = new Buch(23, "Harry Potter und die Kammer des Schreckens",
                542);
        Buch buch5 = new Buch(24, "Harry Potter und der Stein des Weisen",
                612);
        Buch buch6 = new Buch(24, "Harry Potter und der Stein des Weisen",
                612);
      
        dieNeueListe.hinzufuegen(buch1);
        dieNeueListe.hinzufuegen(buch2);
        dieNeueListe.hinzufuegen(buch3);
        dieNeueListe.hinzufuegen(buch4);
        dieNeueListe.hinzufuegen(buch5);
        dieNeueListe.hinzufuegen(buch5);
        dieNeueListe.hinzufuegen(buch6);
      
        System.out.println(buch1.toString());
      
        JF_Window window = new JF_Window(dieNeueListe.getList(), BibItem.class);
        window.setVisible(true);
    }
}

lg und noch einen schönen Abend
 
Zuletzt bearbeitet von einem Moderator:

Zurück
Oben