Interface Interface Objectreference Übergabe

cptlava

Mitglied
Im Anhang befindet sich ein Bild zur Aufgabenstellung, bzw der Teil den ich nicht verstehe.

Jetzt stellt sich mir die Frage: Wenn ich ein Array von meiner Klasse Person(vorname, name als attribute) in meiner Klasse PersonQ erstelle und dann die Methode aufrufe:

Code:
  public void addLast(Object o){
  this.o = o;
  p[counter] = o;
  System.out.println(p[counter]);
  }

Warum erhalte ich als Fehlermeldung: "java.lang.Object cannot be converted to Person"

Muss ich für alle Methoden die ein Object als Parameter haben 2 Methoden für PersonQ und StringQ schreiben ode existiert eine elegantere Lösung?

Danke im voraus
 

Anhänge

  • Unbenannt.png
    Unbenannt.png
    72,7 KB · Aufrufe: 74

Tobse

Top Contributor
Die Fehlermeldung kommt, weil dein Array p vom Typ Person ist, du aber ein Object einfügst. Du musst prüfen, dass o ein Person ist und dann casten.

Ja, es gibt eine viel Elegantere Lösung als das, was die Aufgabenstellung suggeriert. Diese Lösung beinhaltet aber Generics und ich weiss nicht, ob ihr die schon behandelt habt. Falls der Nachfolgende Code für dich unverständlich ist, ignoriere ihn und mach weiter wie bisher.

Java:
class Queue<T> {
    List<T> items = new LinkedList<T>();

    public void addLast(T o) {
        items.add(o);
    }

    // u.s.w. für alle methoden, die da implementiert werden müssen
}

class StringQueue extends Queue<String> {} // fertig, kein weiterer Code nötig
class PersonQueue extends Queue<Person> {} // fertig, kein weiterer Code nötig

In Java gibt es auch schon eine Klasse, die exakt das macht. Siehe Deque<T> und als Implementierung bspw. ArrayDeque<T>
 

cptlava

Mitglied
Hey Danke für die schnelle Antwort. leider dürfen wir kein ArrayList nutzen, scheiß Prof^^.
Versuche das mit dem casten mal und hoffe das es klappt
 

thecain

Top Contributor
Hat nichts mit scheiss prof zu tun, bei einer Queue ist insert und remove in O(1), wenn man dann eine ArrayList dahinter packt, ist es noch O(n) bei remove.

Er hat aber auch keine LinkedList verwendet.
 

cptlava

Mitglied
Ich wusste gar nicht das Queue von Java bereits vordefiniert ist :O
Sobald ich mir Queue als eigenes Interface schreibe und implementiere funktionieren die ganzen add und remove Methoden doch gar nicht mehr..

Da wir, wie ich aus der Aufgabenstellung entnehme, nicht einfach Queue importieren dürfen. Könnte mir villt jemand nen Denkanstoß geben wie ich das über Interfaces löse?
 
Zuletzt bearbeitet:

Saheeda

Top Contributor
Das Interface gibt dir nur die Methodensignatur vor. In der addLast-Methode musst du also wie @Tobse schon sagte prüfen, ob das übergebene Objekt vom Typ Person ist (instanceof), wenn ja wird es entsprechend gecastet und an der ersten freien Stelle (null) im Array gespeichert.
 

cptlava

Mitglied
Ich habe aber doch sowieso 2 verschiedene Queue's einmal eine String und eine Personen Queue?
Da brauche ich ja eh 2 Arrays oder nicht? Habe das mit Zählervarible gelöst und nutze in der Anwendungsklasse if Abfragen.

Hier mal mein SC. Es funktioniert zwar alles aber nachdem was ich hier lese hört sich das an als hätte ich die Aufgabe komplett falsch gelöst :/

Queue Interface
Code:
public interface Queue
{
  void addLast(Object o);
  Object removeFirst();
  Object get(int i);
  boolean empty();
  boolean full();
  int size();
}

Klasse StringQueue
Code:
public class StringQueue implements Queue
{
  public StringQueue(){
  s = new String[3];
  }
  
  public void addLast(Object o){
  this.o = o;
  s[counter] = (String) o;  
  System.out.println(s[counter]);
  counter++;
  }
  
  public Object removeFirst(){
  String nrOne = s[0];
  for(int i = 0; i < counter-1; i++){
  buffer = s[i+1];
  s[i+1] = s[i];
  s[i] = buffer;  
  }
  counter--;
  return nrOne;  
  }

  public Object get(int i){  
  String str = s[i];
  return str;
  }
  
  public boolean empty() {
  if (s[0] != null){
  return true;
  } else {
  return false;
  }
  }
  
  public boolean full() {
  if (s[s.length - 1] != null){
  return true;
  } else {
  return false;
  }
  }
  
  public int size() {
  return counter;
  } 
  
  public String toString(){
  String out = "";
  String save = "";
  
  for(int i = 0; i < counter; i++){
  buffer = s[i];
  save =  buffer + "\t";
  
  out = out + " " + save;
  }
  return out;
  }
  
  Object o;
  private int counter = 0;
  private String[] s;
  private String str, buffer;
}

Klasse PersonenQueue
Code:
public class PersonQueue implements Queue
{
  public PersonQueue(){
  p = new Person[3];
  }
  
  public void addLast(Object o){
  this.o = o;
  p[counter] = (Person) o;
  counter++;
  }
  
  public Object removeFirst(){
  Person nrOne = p[0];
  for(int i = 0; i < counter; i++){
  buffer = p[i+1];
  p[i+1] = p[i];
  p[i] = buffer;  
  }
  counter--;
  return nrOne;  
  }
  
  public Object get(int i){
  Person person = p[i];
  return person;  
  }
  
  public boolean empty() {
  if (p[0] != null){
  return true;
  } else {
  return false;
  }
  }
  
  public boolean full() {
  if (p[p.length - 1] == null){
  return true;
  } else {
  return false;
  }
  }
  
  public int size() {
  return counter;
  } 
  
  public String toString(){
  String out = "";
  String save = "";
  
  for(int i = 0; i < counter; i++){
  buffer = p[i];
  save =  buffer.getName() + "\t" +
  buffer.getVorname() + "\t" +
  "\n" ;
  
  out = out + " " + save;
  }
  return out;
  }
  
  public Person[] getArray() {
  return p;
  }
  
  Object o;
  Person buffer;
  private int counter = 0;
  private Person[] p;
  private String str, eing;
}

Und meine Anwendung die super umständlich ist mMn. Aber wir sollen es halt dialogfähig machen...
Code:
public class AppV2
{  
  //Klassenkonstanten
  private static final int ANLEGEN = 2;
  private static final int LOESCHEN = 3;
  private static final int GET_EINTRAG = 4;
  private static final int IST_LEER = 5;
  private static final int IST_VOLL = 6;
  private static final int GROESSE = 7;
  private static final int AUSGEBEN = 8;
  private static final int ENDE = 0;
  
  /**
  * Hauptschleife der Testklasse
  */
  public void start() {
  int funktion = -1;
  
  while (funktion != ENDE) {
  try{
  funktion = einlesenFunktion();
  ausfuehrenFunktion(funktion);  
  } catch (Exception ex) {
  System.err.println("EXCEPTION !!!");
  System.err.println(ex);
  }
  }
  }
  
  /**
  * Menue ausgeben und Funktion auswaehlen bzw. einlesen.
  * Auswahl wird als Integer zurueckgegegeben.
  */
  private int einlesenFunktion() {
  System.out.print(ANLEGEN  + ":Eintrag anlegen \n"  +
  LOESCHEN  + ":Eintrag loeschen \n"  +
  GET_EINTRAG + ":Eintrag anzeigen  \n" +
  IST_LEER + ":Auf leere Liste pruefen \n" +
  IST_VOLL + ":Auf volle Liste pruefen \n" +
  GROESSE + ":Anzahl der Eintraege ausgeben \n" +
  AUSGEBEN + ":Liste ausgeben \n" +
  ENDE  + ":Beenden --> ");
  return input.nextInt();
  }
  
  /**
  * Ausgewählte Funktion ausfuehren.
  */
  private void ausfuehrenFunktion(int funktion) {
  String eing, eing1;
  int pos = 0;
  if (funktion == ANLEGEN) {
  System.out.print("\tMöchten sie einen String(1) oder Person(2) anlegen ");
  test = input.nextInt();
  if(test == 2){
  System.out.println("Vorname: ");
  eing = input.next();
  System.out.println("Name: ");
  eing1 = input.next();
  p.addLast(new Person(eing1,eing));
  } else {
  System.out.println("String: ");
  eing = input.next();
  s.addLast(eing);
  }
  } else if (funktion == LOESCHEN) {
  System.out.print("\tMöchten sie einen String(1) oder Person(2) loeschen ");
  test = input.nextInt();
  if(test == 2){
  pers = (Person)p.removeFirst();
  ausg  = pers.getName() +"  " +  pers.getVorname();
  System.out.println(ausg);
  } else {
  save = (String)s.removeFirst();
  System.out.println(save);
  }
  }else if (funktion == GET_EINTRAG) {
  System.out.print("\tMöchten sie einen String(1) oder Person(2) ansehen ");
  test = input.nextInt(); 
  System.out.print("\tAn welcher Stelle steht ihr Eintrag: ");
  pos = input.nextInt();
  if(test == 2){
  pers = (Person)p.get(pos);
  ausg  = pers.getName() +"  " +  pers.getVorname();
  System.out.println(ausg);
  } else {
  save = (String)s.get(pos);
  System.out.println(save);
  }
  }else if (funktion == IST_LEER) {
  System.out.print("\tMöchten sie die String(1)- oder Personen(2) Liste testen ");
  test = input.nextInt();
  if(test == 2){
  empty = p.empty();  
  if (empty == true) {
  System.out.println("Das Feld ist  nicht leer");
  } else {
  System.out.println("Das Feld ist leer");
  }
  } else {
  empty = s.empty();  
  if (empty == true) {
  System.out.println("Das Feld ist  nicht leer");
  } else {
  System.out.println("Das Feld ist leer");
  }
  }  
  }else if (funktion == IST_VOLL) {
  System.out.print("\tMöchten sie die String(1)- oder Personen(2) Liste testen ");
  test = input.nextInt();
  if(test == 2){
  full = p.full();  
  if (full == true) {
  System.out.println("Das Feld ist nicht voll");
  } else {
  System.out.println("Das Feld ist voll");
  }
  } else {
  full = s.full();
  if (full == true) {
  System.out.println("Das Feld ist voll");
  } else {
  System.out.println("Das Feld ist nicht voll");
  }
  }
  } else if (funktion == GROESSE) {
  System.out.print("\tMöchten sie die String(1)- oder Personen(2) Liste testen ");
  test = input.nextInt();
  if(test == 2){
  size = p.size();
  System.out.println("Das Feld ist " + size + " Personen groß");
  } else {
  size = s.size();
  System.out.println("Das Feld ist " + size + " Strings groß");
  }
  }else if (funktion == AUSGEBEN) {
  System.out.print("\tMöchten sie die String(1)- oder Personen(2) Liste ausgeben");
  test = input.nextInt();
  if(test == 2){
  System.out.println(p);  
  } else {
  System.out.println(s);  
  }
  }else if (funktion == ENDE) {
  System.out.println("Programmende!");
  }else {  
  System.out.println("Falsche Funktion!");
  }
  }
  /**
  * Main-Methode zum Erzeugen des AppDialog-Objektes
  * Startet die Hauptschleife
  */
  public static void main(String[] args) {
  new AppV2().start();
  }
  
  
  int size, test;
  boolean empty, full;
  Person pers;
  String ausg, save;
  StringQueue s = new StringQueue();
  PersonQueue p = new PersonQueue();
  Scanner input = new Scanner(System.in);


Code:
 

Saheeda

Top Contributor
Was passiert, wenn ich in die PersonQueue ein anderes Objekt gebe?


Ich persönlich finde die Lösung mit der counter-Variable eher ungünstig. Du musst bei jeder Änderung der Queue aufpassen, dass diese aktualisiert wird. Besser wäre es imho in size() über das Array zu iterieren und zu ermitteln, wieviele Werte null sind oder nicht. In full() und empty() würde ich dann abfragen, ob bei size() 0 oder eben der maximal-Wert zurück kommt.

In addLast fragst du nicht, ob die Liste bereits voll ist, hier kann schnell eine IndexOutOfBounds fliegen.

Deine Methoden kannst du an sich auch kürzer schreiben, hier mal am Beispiel get() und empty():

Java:
public Object get(int i){
  return s[i];
}
public boolean empty() {
  return s[0] != null;
}

Für toString gibt es bereits eine Java-native Methode: Arrays.toString(//dein Array). Mit einer vernünftigen toString-Methode in Person sparst du nochmal Code.
Ansonsten: Wenn du Strings zusammenbasteln musst, nimm lieber den StringBuilder. Da Strings in Java unveränderlich sind, wird bei jedem '"a" + "b"' nicht etwa der bestehende String einfach erweitert, sondern jedes Mal eine komplette neue Referenz erzeugt.

Wozu brauchst du die privaten Variablen o, str und eing? str und eing werden nirgendwo verwendet, o wird nur in addLast zugewiesen und sonst ebenfalls nirgendwo mehr aufgerufen.


EDIT:
Die ausführeFuntion ist zu lang und kompliziert geschrieben.
Ich würde hier mehrere kleine Methoden anlegen, die jeweils nur eine Sache erledigen (z.b. neuen Eintrag anlegen) und diese aufrufen, anstatt alles in einer Methode abhandeln zu wollen.
Das ewig lange if-else-Ding zum auswählen der Funktion würde ich in ein Switch-Case ändern.

Du fragst außerdem für jede Funktion separat, welche Queue jetzt bearbeitet werden soll. Das lässt sich auch in einer einzigen Abfrage verallgemeinern. Die Methoden der Funktionen würden dann als Parameter einfach nur eine Queue erwarten (also irgendeine Klasse, welche das Interface implementiert) und könnten darauf die entsprechenden Methoden ausführen.
 
Zuletzt bearbeitet:

cptlava

Mitglied
Danke für deine Tipps!
Habe noch ein paar Probleme damit meinen Code möglichst klein zu halten, konnte deine Ratschläge aber gut umsetzen und die erleichtern das schon allgemein.

Die Fehlerbehandlung bzw. Abfrage zB bei der PersonenQueue mach ich immer erst ganz am Ende. Ich weis ja was ich eingeben darf^^.

Könntest du mir vielleicht noch sagen wie ich diese Aufgabenstellung also besonders das Ausgeben über void print(Queue q) lösen soll? Ich müsste dann ja ein Objekt von meinem Interface übergeben und das ergibt für mich irgendwie keinen Sinn

Erstellen Sie ein interaktives Testprogramm zum Testen der Methoden addLast und removeFirst, das
möglichst unabhängig von den Klassen StringQueue und PersonQueue sein sollte. Insbesondere sollten
Sie die Ausgabe einer Queue mit Hilfe einer Methode
void print(Queue q)
realisieren, die die jeweilige Warteschlange mit Hilfe der get-Methode sequenziell durchläuft und ausgibt.
[/qoute]
 

thecain

Top Contributor
Was soll das für eine Queue sein? Dein Remove first hat ja Komplexität O(n) weil du jedes mal jeden Eintrag im Array verschiebst...

Ich würde einfach 3 int mitführen. size, head, tail. Dazu ein Array vom jeweiligen Typ als speicher.

Darin die jeweiligen Werte speichern. Solange meine size kleiner ist, als die Arraylength, würde ich mit einer Art "Wrap-Around arbeiten, damit ich die Queue nicht vergrössern muss, wenn gleichmässig Elemente entfernt und hinzugefügt werden.

Wenn size grösser als die ArrayLength wird, muss das store vergrössert werden, dann kann man es auch direkt wieder in die ordentliche Reihe bringen.

Zum veranschaulichen mit dem Wrap Around:

Code:
|_|_|1|2|   //Head 2, tail 3, size 2
0 1 2 3

Add (3)

|3|_|1|2| // Head 2, tail 0, size 3
0 1 2 3
 

Saheeda

Top Contributor
@cptlava

Die Signatur ausgeben(Queue que) besagt nur, dass _irgendein_ Objekt übergeben wird, welches dieses Interface implementiert. Welchen konkreten Typ das übergebene Objekt (StringQueue oder PersonQueue) hat, wird erst zur Laufzeit festgelegt.
Und genau das ist ein entscheidender Vorteil von Interfaces: Ich kann eine sehr allgemeine Methode schreiben, was dann genau passiert, wird in den implementierenden Klassen selbst festgelegt.

Schau dir mal statische und dynamische Typen an, vielleicht wirds dir dann klarer:
https://bruck.me/2014/01/08/java-statischer-vs-dynamischer-typ/
 
Zuletzt bearbeitet:

cptlava

Mitglied
Davon hatte ich schonmal gelesen. Ich schreibe mir einfach die Methode im Interface, implementiere sie in beiden Klassen und während der Laufzeit wird die Klassenmethode und nicht die aus dem Interface aufgerufen.

Nur warum übergebe ich eine Queue? Methoden die ich im Interface schreibe müssen ja in den Klassen, die dieses implementieren ausgeführt werden. Wieso sollte ich dann in PersonQueue PersonQueue übergeben?
 

Saheeda

Top Contributor
Die Methode sieht so aus:

Java:
public void print(Queue queue){

}

Der Aufruf ungefähr so:

Java:
PersonQueue que = new PersonQueue();
print(que);

Angenommen, Queue wäre kein Interface, sondern eine normale Klasse, von der PersonQueue erbt. Dann ist jede spezielle PersonQueue auch gleichzeitig eine ganz allgemeine Queue. Ist dir das Prinzip klar?
Mit Interfaces funktioniert es im Grunde gleich.
Du übergibst keine Queue (geht auch gar nicht, Interfaces können nicht instantiiert werden), aber ein Objekt, das davon ableitet. Probiers einfach mal aus, schreib die Methode und ruf sie mit einer PersonQueue oder einer StringQueue auf.


Oder mal ein Beispiel aus der realen Welt:
In einem Aquarium können viele verschiedene Tiere leben: Fische, Seesterne, Krabben, etc. Die einzige Gemeinsamkeit zwischen ihnen ist, dass sie irgendwie unter Wasser atmen können. Die Bedingung, um ein Tier ins Aquarium zu setzen ist also "KannUnterWasserAtmen". Niemand käme auf die Idee, seinen Hamster reinzusetzen. Wie die einzelnen Tiere das jetzt konkret machen (Sauerstoff filtern, einfach sehr lange die Luft anhalten, whatever) kann dir ja vollkommen egal sein. Die Tiere können überleben, fertig.
 

Neue Themen


Oben