ADT-Klasse Index implementieren

christophs91

Mitglied
Hi,

ich stehe vor folgender Aufgabe und brauche ein paar Tipps:
In nahezu jedem Lehrbuch finden Sie im hinteren Teil so genannte Indexe bzw. Sachwortverzeichnisse. Hier werden wichtige Begriffe, die im Buch vorkommen, sowie die jeweiligen Seitenzahlen, auf denen die Begriffe vorkommen, aufgelistet.
Implementieren Sie eine ADT-Klasse Index, die einen solchen Index repräsentiert. Die Klasse soll folgende Methoden zur Verfügung stellen:
-Einen Default-Konstruktor, der einen leeren Index erstellt.
-Einen Copy-Konstruktor; der neue Index soll dabei alle Einträge enthalten, die der als Parameter übergebene Index zum Zeitpunkt des Aufrufs enthält.
-Eine Methode hinzufuegen, die einen Begriff (String) sowie eine Seitenzahl (int-Wert) als Parameter übergeben bekommt und die den Begriff mit der Seitenzahl im Index vermerkt. Dabei gilt: Begriffe dürfen nicht mehrfach im Index vorkommen und zu jedem Begriff darf eine Seitenzahl höchstens einmal im Index vorkommen.
-Eine Methode toString, die eine String-Repräsentation des aktuellen Index liefert (Überschreiben der von der Klasse Object geerbten Methode toString). Die String-Repräsentation soll dabei folgendermaßen aufgebaut
sein: Für jeden im Index vermerkten Begriff soll der String jeweils eine Zeile der folgenden Form enthalten: <begriff>: <seitenzahl 1> <seitenzahl 2> … <seitenzahl n> (also bspw.: Hamster: 2 45 123)

Hinweis:
Beachten Sie, dass die Anzahl an Begriffen des Index nicht beschränkt ist. Dasselbe gilt für die Anzahl der Seitenzahlen pro Begriff. Setzen Sie statt Arrays also die Klasse java.util.ArrayList ein.
Freiwilliger Zusatz:
Geben sie sowohl die Einträge des Index als auch die Seitenzahlen sortiert aus (lexikographische bzw. natürliche Ordnung der Begriffe bzw. der Seitenzahlen). Suchen Sie im JDK nach geeigneten Klassen bzw. Methoden zum Sortieren.

Testen:
Ob Ihre Klasse (zumindest teilweise) korrekt ist, können Sie testen, indem Sie das folgende Testprogramm ausführen:


Java:
 package Uebungszettel09;

class IndexTest {

    public static void main(String[] args) {
        
        Index index = new Index();
        
        index.hinzufuegen("Objekt", 1);
        index.hinzufuegen("Objekt", 15);
        index.hinzufuegen("Objekt", 3);
        index.hinzufuegen("Objekt", 15);
        
        Index index2 = new Index(index);
        
        index.hinzufuegen("Objekt", 17);
        index.hinzufuegen("Hamster", 45);
        index.hinzufuegen("Hamster", 2);
        index.hinzufuegen("Hamster", 199);
        index.hinzufuegen("Hamster", 45);
        
        System.out.println(index);
        System.out.println(index2);
    }
}


Bisher hab ich folgendes erarbeitet:
Java:
package Uebungszettel09;

import java.util.ArrayList;

public class Index {

    String begriff = new String();
    int seite;
    ArrayList<String> index = new ArrayList<>();
    
	//Default Konstruktor
    public Index() {
        this.begriff = null;
        this.seite = 0;
    }
         // Konstruktor
    public Index(String begriff, int seite) {
        this.begriff = begriff;
        this.seite = seite;
    }
         // Copy-Konstruktor
    public Index(Index i) {
        this.begriff = i.begriff;
        this.seite = i.seite;
        this.index = i.index;
    }
         // Neuen Index im Index erstellen
    public Index(ArrayList neuerIndex) {
        neuerIndex.add(this.index);
    }
         // Begriff und Seite zum Index hinzufügen
         // Solange der Begriff nicht bereits in der List ist
    public void hinzufuegen(String begriff, int seite) {
        if (!this.index.contains(this.begriff)) {
        this.index.add(this.begriff + ":" + this.seite);
        }
    }

    @Override
    public String toString() {
        return this.begriff + ": " + this.seite;
        
    }
}


Mein erstes Problem ist, dass die Begriffe + Seite nicht zum Index hinzugefügt werden.
Wenn ich das Testprogramm ausführe, bekomme ich als Ausgabe:
null : 0
null : 0

Woran liegt es, dass die Begriffe nicht zum Index hinzugefügt werden?
Das die Methode neuerIndex und toString noch nicht funktionieren ist mir bewusst, aber als erstes möchte ich, dass die Dinge zum Index hinzugefügt werden können.

Freundliche Grüße
Christoph
 

Fant

Bekanntes Mitglied
this.begriff ist null. Du musst mit dem lokalen String vergleichen.
Wozu brauchst du hier überhaupt die Member-Variablen?
 

Sesostris

Aktives Mitglied
Aber ich übergebe doch einen Begriff in der IndexTest Klasse, warum bleibt this.begriff trotzdem = null, obwohl ich this.begriff = begriff stehen habe?
Das steht so im Konstruktor, ja, aber in deiner IndexTest-Klasse arbeitest du mit der hinzufuegen-Methode und die ist - wie Fant bereits sagte - falsch.
So sollte sie richtig aussehen:
Java:
	public void hinzufuegen(String begriff, int seite) {
		if (!this.index.contains(begriff + ":" + seite)) {
			this.index.add(begriff + ":" + seite);
		}
	}
Bei contains musst du übrigens das abprüfen, was du auch tatsächlich einfügst.

Die toString-Methode macht nicht das, was sie sollte. Du willst doch auf alle Objekte deiner ArrayList ausgeben und nicht nur ein einziges begriff:seite-Paar.

Member-Variablen sind was?
Jene Variablen, die zu deinem Objekt Index gehören und die du auch schön mit this gekennzeichnet hast. Aber wozu die Variablen begriff und seite? Die sollten doch in die ArrayList kommen, was zum Beispiel bei deinem Konstruktur mit begriff und seite nicht der Fall ist. Sinnvoller wäre so etwas:
Java:
	public Index(String begriff, int seite) {
		this.hinzufuegen(begriff, seite);
	}

Auch der copy-Konstruktor kopiert nicht wirklich, aber das wird dir schon selbest auffallen, sobald du dein IndexTest zum Laufen gebracht hast.
 

christophs91

Mitglied
Das steht so im Konstruktor, ja, aber in deiner IndexTest-Klasse arbeitest du mit der hinzufuegen-Methode und die ist - wie Fant bereits sagte - falsch.
So sollte sie richtig aussehen:
Java:
	public void hinzufuegen(String begriff, int seite) {
		if (!this.index.contains(begriff + ":" + seite)) {
			this.index.add(begriff + ":" + seite);
		}
	}
Bei contains musst du übrigens das abprüfen, was du auch tatsächlich einfügst.

Die toString-Methode macht nicht das, was sie sollte. Du willst doch auf alle Objekte deiner ArrayList ausgeben und nicht nur ein einziges begriff:seite-Paar.


Jene Variablen, die zu deinem Objekt Index gehören und die du auch schön mit this gekennzeichnet hast. Aber wozu die Variablen begriff und seite? Die sollten doch in die ArrayList kommen, was zum Beispiel bei deinem Konstruktur mit begriff und seite nicht der Fall ist. Sinnvoller wäre so etwas:
Java:
	public Index(String begriff, int seite) {
		this.hinzufuegen(begriff, seite);
	}

Auch der copy-Konstruktor kopiert nicht wirklich, aber das wird dir schon selbest auffallen, sobald du dein IndexTest zum Laufen gebracht hast.

Danke für deine Antwort, das ist mir gar nicht so bewusst geworden, dass ich ja mit der hinzufuegen Methode arbeite und dass die dann richtig sein muss.
Hab eine Frage zur hinzufuegen Methode:
Java:
	public void hinzufuegen(String begriff, int seite) {
		if (!this.index.contains(begriff + ":" + seite)) {
			this.index.add(begriff + ":" + seite);
		}
	}
Warum arbeite ich dann da nicht mit den Member Variablen?
Weil ich mit den übergebenen Parametern "begriff" und "seite" arbeite?


Was meinst du mit "Aber wozu die Variablen begriff und seite?"?
Meinst du this.begriff und this.seite?


Ich habe den Copy-Konstruktor auch nur so ähnlich aus einer vorherigen Aufgabe genommen, genau weiß ich gar nicht, wozu ich Copy-Konstruktor brauche. Kannst du mir in verständlichen Worten erklären, wozu ich so einen brauche?
 

Sesostris

Aktives Mitglied
Warum arbeite ich dann da nicht mit den Member Variablen?
Weil ich mit den übergebenen Parametern "begriff" und "seite" arbeite?
Du willst jene Informationen hinzufügen, die du deiner hinzufuegen-Methode übergibst. Und das sind die Parameter "begriff" und "seite".

Was meinst du mit "Aber wozu die Variablen begriff und seite?"?
Meinst du this.begriff und this.seite?
Ja. Die Member- bzw. Instanzvariablen this.begriff und this.seite halte ich für relativ überflüssig, da sie keinen Zweck erfüllen.

Ich habe den Copy-Konstruktor auch nur so ähnlich aus einer vorherigen Aufgabe genommen, genau weiß ich gar nicht, wozu ich Copy-Konstruktor brauche. Kannst du mir in verständlichen Worten erklären, wozu ich so einen brauche?
Na ja, um es salopp zu sagen: du brauchst ihn, weil es die Aufgabenstellung so vorschreibt.
In der Praxis kann so etwas schon Sinn haben. Stell dir vor, du hast ein Index-Objekt, das bereits gut gefüllt ist. Wenn du das nun kopieren willst, erstellst du einen neuen Index mit diesem Copy-Konstruktor, der direkt von deinem bestehenden Index-Objekt kopiert, anstatt die Begriffe/Seiten einzeln mit deiner hinzufuegen-Methode zu übernehmen.

So wie du deinen Copy-Konstruktor im Moment programmiert hast, kopiert er nicht, sondern referenziert dein bestehendes Index-Objekt. Du gibst ihm quasi einen neuen Namen, mehr nicht. Jede Änderung des angeblich kopierten Index wirkt sich auch auf den alten Index aus - das sollte so nicht sein.
 

christophs91

Mitglied
Okay, dass this.begriff und this.seite nicht brauche, kann ich nachvollziehen nun.

Frage mich nun, was ich in den default Konstruktor reinschreiben soll.
Java:
this.index = index;
?

Danke für deine Erklärung des Copy Konstruktors.
 

Sesostris

Aktives Mitglied
Laut Aufgabenstellung ein "Default-Konstruktor, der einen leeren Index erstellt".
Leerer Index heißt nun so viel wie this.index = new ArrayList<String>() und du hast eine leere ArrayList.
Da du das aber bereits gemacht hast, musst du es nicht noch einmal machen und kannst den Default-Konstruktor getrost leer lassen.
 

christophs91

Mitglied
Laut Aufgabenstellung ein "Default-Konstruktor, der einen leeren Index erstellt".
Leerer Index heißt nun so viel wie this.index = new ArrayList<String>() und du hast eine leere ArrayList.
Da du das aber bereits gemacht hast, musst du es nicht noch einmal machen und kannst den Default-Konstruktor getrost leer lassen.

Okay danke. Dann werd ich mich nach dem Deutschland Spiel damit wieder beschäftigen!
:)
 

christophs91

Mitglied
So ich habe mich jetzt erstmal damit beschäftigt, dass die Ausgabe schon mal annähernd funktioniert, nach mehreren Recherchen hab ich rausgefunden, dass NEtBeans anbietet die toString Methode selber zu überschreiben.
Kann das aber nicht nachvollziehen, warum das bei mir nicht vorher funktioniert hat.
Er schlägt mir vor:
Java:
  @Override
    public String toString() {
        return "Index{" + "index=" + index + '}';
    }

Warum kann ich nicht:

Java:
  @Override
    public String toString() {
        return index;
    }

schreiben? Der Compiler meckert dann ja rum, aber muss ich in der toString Methode immer einen kleinen String angeben ala "}"?
 

Fant

Bekanntes Mitglied
Die toString()-Methode von welcher Klasse soll das denn sein? Vermutlich ist index einfach kein String. Dann wäre deine erste Variante gleichwertig zu

Java:
@Override
    public String toString() {
        return "Index{" + "index=" + index.toString() + '}';
    }

Für die zweite Variante könntest du dann schreiben:
Java:
@Override
    public String toString() {
        return index.toString();
    }

oder

Java:
@Override
    public String toString() {
        return "" + index;
    }

Sei nicht so sparsam mit den Codeabschnitten. Wenn immer sofort klar ist, was du da genau abtippst, dann kann man dir auch besser und schneller helfen.
 

christophs91

Mitglied
Eine Methode toString, die eine String-Repräsentation des aktuellen Index liefert (Überschreiben der von der Klasse Object geerbten Methode toString). Die String-Repräsentation soll dabei folgendermaßen aufgebaut
sein: Für jeden im Index vermerkten Begriff soll der String jeweils eine Zeile der folgenden Form enthalten: <begriff>: <seitenzahl 1> <seitenzahl 2> … <seitenzahl n> (also bspw.: Hamster: 2 45 123)


Und das toString von der Klasse Index sein soll, steht ja auch oben schon im vollständigen Code. Index ist eine ArrayListe vom Typ String. Verstehe jetzt nicht, warum das unklar sein sollte?


Java:
 @Override
    public String toString() {
        return index.toString();
    }

Die Variante funktioniert nicht. Ich muss noch was hinzufügen wie in deiner letzten Variante:

Java:
 @Override
    public String toString() {
        return "" + index;
    }

Dann funktioniert es, aber ich frage mich dennoch, warum ich das "" hinzufügen muss und es nicht ohne geht.
 

Fant

Bekanntes Mitglied
Weil index kein String ist. Durch das vorrangestellte "" weiß der Compiler aber nun, dass ein String folgen muss und ruft beim Objekt index implizit die toString()-Methode auf.
Wenn
Java:
@Override
    public String toString() {
        return index.toString();
    }

bei dir nicht funktionieren sollte, dann machst du noch irgendwas anderes falsch.
 

christophs91

Mitglied
Also das ist jetzt mein kompletter Code bisher:


Java:
package Uebungszettel09;

import java.util.ArrayList;

public final class Index {

    String begriff;
    int seite;
    ArrayList<String> index;

    //Default Konstruktor
    public Index() {
        index = new ArrayList<>();
    }
    // Konstruktor

    public Index(String begriff, int seite) {
        this.hinzufuegen(begriff, seite);
    }
    // Copy-Konstruktor

    public Index(Index i) {
        this.index = i.index;
    }
    // Neuen Index im Index erstellen

    public Index(ArrayList index) {
        index.add(index);
    }
    // Begriff und Seite zum Index hinzufügen
    // Solange der Begriff nicht bereits in der List ist

    public void hinzufuegen(String begriff, int seite) {
        if (!this.index.contains(begriff + ":" + seite)) {
            this.index.add(begriff + ":" + seite);
        }
    }

    @Override
    public String toString() {
        return index + "";
    }
}

Ich weiß nicht, warum es ohne + "" nicht geht.
 

Neue Themen


Oben