Problem mit instanceof



  • Hey icarus2!

    Danke trotzdem für die Antwort. Mir kommt es ganz gelegen, dass Du antwortest, denn ich habe gemerkt, dass sich mein Problem doch noch nicht ganz aufgelöst hat.

    Ich habe eine Klasse A mit zwei protected Attributen (color, size). Eine Klasse B erbt nun von dieser Klasse A.

    Klasse B hat nun die Methode "equals" die überprüfen soll, ob ein willkürlich übergebenes Objekt dem aktuellen gleicht.

    Gleichen heißt: Das übergebene Objekt ist von derselben Klasse und der Inhalt der vererbten protected Variablen ist gleich. Da weiß ich aber nicht so ganz, wie ich diesen Vergleich anstellen soll:

    public boolean equals (Object o) { 
      boolean res = o instanceof B;
      boolean sameDescription = this.color.equals(o) && this.size == o.size; 
    
      //Das funktioniert so nicht, da ich ja gar nicht weiß, ob "o" zu meiner Klasse gehört und damit auch nicht sagen kann, ob es die Attribute size und color hat.
    
      return res && sameDescription;
    
    }
    

    Wie muss der Zugriff auf "size" und "color" von o lauten?



  • Ich bin mir noch nicht ganz sicher was du machen willst. Ich fange mal vorne an.

    Der Ausdruck

    boolean res = o instanceof B;
    

    ist immer falsch, da die Klasse Object nicht von B erbt. Wenn du ein Objekt der Klasse A oder B nach Object castet (oder das implizit passiert), so weiss das Laufzeitsystem nicht mehr, dass es sich dabei um ein Objekt von A oder B handelt. Es ist einfach ein Object.

    Du versuchst auf den Attributen color und size (welche Typen haben die denn?) die Methode equals(...) aufzurufen. Haben die Typen von color und size denn eine Methode equals(...) definiert?

    Vielleicht hilft dir das etwas. Da ich noch nicht genau weiss was du machen moechtest ist es etwas schwierig dir einen konkreten Hinweis zu geben.



  • Mmmhh...ok, ich versuche mich noch einmal etwas konkreter auszudrücken.

    Ich habe die folgende Klasse A:

    public abstract class A {
      protected String title;
      protected int price;
    
      public A (String t, int p) {
       title = t;
       price = p;
    
      public abstract boolean equals(Object o);
     }
    }
    

    Nun habe ich Klasse B, die von A beerbt wird:

    public class B extends A {
      public B (String t, int p) {
       super(t,p);
    
      public boolean equals (Object O) {
      //...
      }
    
     }
    }
    

    Ich möchte ich, dass die Methode "equals" jetzt überprüft:

    1.) Ist o vom Typ B?
    2.) Wenn o vom Typ B ist, stimmt dann der Inhalt von "title" und "price" mit dem des aktuellen Objekts von B überein.

    Wenn der Ausdruck "boolean res = o instanceof B" immer falsch ist, dann frage ich mich, wie ich überprüfen soll, ob o vom Typ B ist (Ich muss "instanceof" verwenden).

    Und falls dann "o" vom Typ B ist, wie kann ich dann auf die Attribute "title" und "price" zugreifen?

    Ich hoffe, mein Anliegen ist etwas klarer geworden 🙂

    Vielen Dank
    lg, freakC++

    EDIT: Ich habe mit vertan. o muss vom Typ "A" sein und nicht vom Typ "B". Also muss es "o instanceof A" oder so ähnlich heißen.



  • Ich glaube ich habe die Loesung gefunden. Erstmals sorry, denn ich hatte falsch im Kopf, dass o instanceof A immer false liefert. Das stimmt so natuerlich nicht - mein Fehler.

    So muesste es klappen:

    public class B extends A { 
      public B (String t, int p) { 
       super(t,p); 
      }
    
      public boolean equals (Object o) { 
    	  A temp = null;
    	  if ( o instanceof A ) // (1)
    		  temp = (A) o;
    	  else
    		  return false;
    
    	  return this.title.equals(temp.title) && this.price == temp.price;
      } 
    
    }
    

    (1)
    Wenn o eine Instanz von A ist, dann castest du o vom Typ Object nach A. Sonst gibst du false zurueck.
    Mit dem Objekt temp der Klasse A (also o nach A gecastet) kannst du dann frei auf die Attribute zugreifen.

    Ist es das was du haben moechtest?

    *Edit
    Nur noch kurz, dass es keine Verwirrung gibt:
    Das equals bei

    this.title.equals(temp.title)
    

    hat nichts mit dem equals der Klasse B zu tun. Es ist das equals, das in der Klasse String definiert ist.



  • Hallo icarus2,

    jaa, das ist genau das, was ich brauche. Super! Jetzt funktioniert es. Herzlichen Dank!

    Noch zwei Anmerkungen:

    1.)

    icarus2 schrieb:

    temp = (A) o;
    

    Ist dieser expliziere Cast hier notwendig oder einfach nur schön? "temp" ist immerhin schon vom Typ A?

    2.)

    icarus schrieb:

    Das equals bei

    this.title.equals(temp.title)
    

    hat nichts mit dem equals der Klasse B zu tun. Es ist das equals, das in der Klasse String definiert ist.

    [/quote]

    Gut, dass Du es ansprichst. Es war mir zwar klar, aber doppelt hält besser. Der Unterschied zwischen "equals" und "==" ist wohl der vergleichbar mit "gleich" und "identisch" 😃

    Danke dir noch einmal!

    lg, freakC++



  • bzw. warum muss dieser Cast sein? Ich sehe ja bei mir, dass es sonst einen Fehler gibt 🙂

    edit: Irgendwie ist es mir klar, weil o ja vom Typ "object" ist. Aber durch die if-Abfrage weiß ich doch, dass es eine Instanz von Product ist....



  • Es braucht dort einen expliziten Cast, weil es ein Downcasting ist. Da Java eine typsichere Sprache ist wird verlangt, dass explizit gecastet wird. Es wird verlangt weil das Downcasten gefaehrlich ist, denn Object o koennte gar nicht von der Klasse A erben und dann wuerde der Cast eine Exception ausloesen. Deswegen brauchst du das if instanceof, dann weisst du, dass du es machen kannst. Da der Ausdruck allerdings nicht zur Compile Time sondern zur Laufzeit ausgewertet wird, kann das der Compiler nicht ueberpruefen. Deswegen expliziter cast.

    *Edit
    Wenn der Compiler intelligent waere, dann wurde es wohl ohne diese expliziten Casts gehen. Aber das koennen Compiler nicht.



  • icarus2 schrieb:

    Wenn der Compiler intelligent waere, dann wurde es wohl ohne diese expliziten Casts gehen. Aber das koennen Compiler nicht.

    Sowas ist IMHO auch nicht die Aufgabe des Compilers, sondern der statischen Codeanalyse, falls vorhanden. Wenn entsprechende Tools mitlaufen, bekäme man ohne vorherige Abfrage bei dem Cast eine Warnung "Possible ClassCastException", mit der if-Abfrage jedoch nicht.



  • Hallo zusammen,

    ich bin auf noch ein Problem gestossen, das eventuell etwas mit "instanceof" zu tun hat. Daher schreibe ich einfach mal in diesem Thread weiter.

    Es geht um folgendes:

    Ich habe drei Klassen A, B und C.

    public abstract class A {
     //...
    } 	
    
    public class B extends A {
      //..
      public int eineVariable;
    }
    
    public class C extends A {
      //..
      public int andereVariable;
    }
    

    Jetzt habe ich eine komplett unabhängige Methode, die außerhalb aller Klassen liegt. Diese Methode bekommt als Parameter eine Instanz der Klasse A.

    public void machWas(A myInstanz) {
    //...
    }
    

    Jetzt habe ich folgendes Problem. Wenn es sich bei "myInstanz" um ein Objekt der Klasse B handelt, so möchte ich den Wert von "eineVariable" ausgeben. Wenn "myInstanz" jedoch ein Objekt von C ist, so möchte ich "andereVariable" ausgeben.

    Wie mache ich das?

    Ich danke euch 😃
    lg, freakC++



  • Ungefaehr so:

    if (myIntance instanceof B) {
         // Mach etwas
    }
    else if (myInstance instanceof C) {
         // Mach etwas
    }
    


  • freakC++ schrieb:

    Ich habe drei Klassen A, B und C.

    public abstract class A {
     //...
    } 	
    
    public class B extends A {
      //..
      public int eineVariable;
    }
    
    public class C extends A {
      //..
      public int andereVariable;
    }
    

    Jetzt habe ich eine komplett unabhängige Methode, die außerhalb aller Klassen liegt. Diese Methode bekommt als Parameter eine Instanz der Klasse A.

    public void machWas(A myInstanz) {
    //...
    }
    

    Jetzt habe ich folgendes Problem. Wenn es sich bei "myInstanz" um ein Objekt der Klasse B handelt, so möchte ich den Wert von "eineVariable" ausgeben. Wenn "myInstanz" jedoch ein Objekt von C ist, so möchte ich "andereVariable" ausgeben.

    Wie mache ich das?

    Kannst es natürlich mit instanceof lösen:

    public void machWas(A myInstanz) {
      if(myInstanz instanceof B) {
        int wert = ((B) myInstanz).eineVariable;
      } else if(myInstanz instanceof C) {
        int wert = ((C) myInstanz).andereVariable;
      }
    
      // irgendwas mit wert
    }
    

    Schöner wäre es, die Methode zu überladen.

    public void machWas(B myInstanz) {
      irgendwasMitWert(myInstanz.eineVariable);
    }
    
    public void machWas(C myInstanz) {
      irgendwasMitWert(myInstanz.andereVariable);
    }
    
    public void irgendwasMitWert(int wert) {
      // ...
    }
    

    Eventuell wäre das aber auch ein Zeitpunkt, dein Design zu überdenken.



  • Das würde aber bedeuten, dass ich alle meine Klassen kennen muss, um diese if Abfrage zu erstellen. Was ist aber wenn ich 100 Klassen habe, die von A erben und jeweils eigene Attribute haben?

    Kann man das auch schöner lösen?

    Danke dir



  • freakC++ schrieb:

    Das würde aber bedeuten, dass ich alle meine Klassen kennen muss, um diese if Abfrage zu erstellen. Was ist aber wenn ich 100 Klassen habe, die von A erben und jeweils eigene Attribute haben?

    Kann man das auch schöner lösen?

    Danke dir

    Dann ist es an der Zeit ein neues Design zu suchen.

    Kommt etwas darauf an was du genau machen moechtest. Aber eventuell waere es nicht schlecht eine abstrakte Methode in der Basisklasse zu deklarieren und diese in den Subklassen zu ueberladen.

    Oder sich ueberlegen ob diese einzelnen Klassen ueberhaupt eine sinnvolle gemeinsame Basisklasse besitzten.

    *Edit
    Was moechtest du denn konkret haben?



  • Spendiere A eine abstrakte Methode "getVariable" und gib in den abgeleiteten Klassen den passenden Wert zurück.


Anmelden zum Antworten