methoden Überladen



  • mehrfachvererbung gibt es in java nicht

    und wenn du mein program ausfuehrst wirst du merken
    das es nicht ins object springt sondern ins component
    eben weil JButton ein java.awt.Component ist

    und component leitet sich wiederrum von Object ab (jede klasse leitet sich von object ab)

    die vererbungshirarchie lautet

    Object
    -Component
    --JComponent
    ---JButton

    also tu mir den gefallen und poste etwas von deinem code

    dann kann ich dir wahrscheinlich helfen

    gomberl



  • gomberl schrieb:

    Object
    -Component
    --JComponent
    ---JButton

    Ups mein Fehler! Das stimmt wohl tatsächlich. Also mein sourcecode sieht so wie Deiner aus:

    public class  OneOfManyChoiceButtons extends SPanel implements OneOfManyChoice  {
    
        private ButtonGroup group          = new ButtonGroup ();
        private Vector      choices        = new Vector ();    
    
        public void add ( Object choice ){
          try {
            this.add(choice);              //<-- Gefährlich oder?
            choices.add ( choice );                  //Dies ist die add() aus java.util.vector
            group.add ( (JToggleButton)choice );     //  dito
    
          }
          catch ( Exception except ) {
          }
        }
    
        public static void main ( String args[] ) {
          OneOfManyChoiceButtons buttons = new OneOfManyChoiceButtons ();
          buttons.add ( new JList() );
        }
    }
    

    wobei wiederum SPanel von JPanel erbt und somit auch die add() Methode aus java.awt.Component und über das interface eine weitere add Methode implementieren muss.

    Zur gefährlichen Stelle: Hier soll ja nun die add() Methode aus java.awt.Container aufgerufen werden um das übergebene Object dem Panel zu adden. Wie kann ich es verhindern das hier ein rekursiver Aufruf statt findet?



  • gomberl schrieb:

    und wenn du mein program ausfuehrst wirst du merken
    das es nicht ins object springt sondern ins component
    eben weil JButton ein java.awt.Component ist

    Aber JButton ist doch auch ein Object! Wie soll er sich also entscheiden?



  • blauton.com schrieb:

    Wie soll er sich also entscheiden?

    Er nimmt immer das, was am weitesten unten in der Vererbungshierarchie ist, also "am besten passt".



  • SG1 schrieb:

    Er nimmt immer das, was am weitesten unten in der Vererbungshierarchie ist, also "am besten passt".

    hmm. Dann verstehe ich nicht warum der compiler bei mir meckert 😞 Oder übersehe ich einen Fehler?



  • okay

    bevor ich jetzt zu dem problem deinerseits komme fällt mir gleich eines ins auge

    public void add ( Object choice ){ 
          try { 
            this.add(choice);              //<-- Gefährlich oder? 
            choices.add ( choice );                  //Dies ist die add() aus java.util.vector 
            group.add ( (JToggleButton)choice );     //  dito 
          } 
    
    ...
    
    buttons.add ( new JList() );
    

    also soweit ich weiss ist eine JList kein toggle button - also wird das nicht funktionieren

    aber jetzt zu deinem fehler:

    das ganze ist ein logischer fehler
    du überschreibst eine methode die es bereits gibt - aber ohne auf den typ ruecksicht zu nehmen
    der compiler kann nun nicht entscheiden was er nehmen soll
    den es gibt eine methode in der superklasse und eine in der jetzigen klasse

    und überladung funktioniert nur in einer klasse
    dementsprechend musst du folgende funktion hinzufügen

    //damit ermoeglichst du die ueberladung in einer klasse
    //jetzt kann zur laufzeit die richtige methode benutzt werden
    //diese methode leitet nun nur den aufruf direkt an die super klass weiter
    public void add(JComponent choice){
            super.add(choice);
    }
    

    dann gibts kein problem mehr damit

    wenn du das genauer erklärt haben willst, erklär ich es dir
    aber jetzt lass ich es mal gut sein

    gomberl


  • Mod

    blauton.com schrieb:

    meine Klasse hat zwei Methoden:

    add(Object)

    add(java.awt.Component)

    [...]

    Schlechtes Klassendesign oder leicht zu beheben?

    Beides.

    1. Grundsätzlich sollte man so wenig wie möglich überladen.

    2. Gib einer Methode einfach einen anderen Namen.



  • Es kommt immer darauf an was die methode macht

    manchmal ist ueberladen schon sinnvoll

    aber generell hat georg recht

    gomberl



  • sowenig wie möglich ist mir nicht ganz einleuchtend..

    daß man in java damit hölle aufpassen muss, wegen solchen dingen:

    Somit bieten sich generell drei Möglichkeiten für Methoden in der Unterklasse an: Hinzufügen, Überladen oder Überschreiben. Wird die Signatur eines Funktionsblocks beim Überschreiben nicht aufmerksam genug beachtet, wird unbeabsichtigt eine Methode überladen. Dieser Fehler ist schwer zu finden. Insbesondere müssen wir uns damit abfinden, dass abgeleitete Klassen den Rückgabewert einer überschreibenden Methode bis zur Java-Version 1.5 nicht spezialisieren können.

    aus: java ist eine insel.. online

    aber wenn es sinn macht, konstuktoren oder methoden zu überladen...

    ich würde einer gleichen methode, also die das gleiche tut für unterschiedliche objekte, nicht einen anderen namen geben, das verwirrt doch nur den folgeentwickler..

    aber nur als diskussion, ich bin keine javaistin, vielleicht gibt es wichtige gründe.. 🙂


  • Mod

    Ich kann in diesem Zusammenhang nur auf das Buch "Effektiv Java programmieren" verweisen. Ich gebe gleich mal die Zusammenfassung des Kapitels 6.4. "Verwenden Sie Methodenüberladung vorsichtig" an:

    Zusammenfassend kann man sagen: Sie sollten keine Methoden bloß deswegen überladen, weil es möglich ist. Generell sollten Sie keine Methoden mit mehreren Signaturen überladen, die dieselbe Parameterzahl haben. In manchen Fällen, insbesondere bei Konstruktoren, kann die Befolgung dieser Regel jedoch unmöglich sein. Dann sollten Sie durch hinzufügen von Typumwandlungen zumindest verhindern, dass dieselbe Parametermenge verschiedenen Überladungen übergeben werden kann. Wenn eine solche Situation jedoch unvermeidlich ist - z.B. weil Sie eine bestehende Klasse so überarbeiten, dass sie ein neues Interface implementiert -, dann sollten Sie gewährleisten, dass sich alle Überladungen identisch verhalten, wenn man ihnen dieselben Parameter übergibt. Wenn Sie dies unterlassen, können die Programmierer die überladene (Konstruktor)-Methode nicht wirkungsvoll einsetzen und verstehen ihre Funktionsweise auch nicht.

    Ich muss dazu allerdings sagen, dass sich dies hier auf ein etwas anderes Problem bezieht. Es wird hier darauf Bezug genommen, dass das Verhalten bei Methodenüberladung statisch ist, während es bei Methodenüberschreibung dynamisch ist. Dies kann bei vielen Programmierern in bestimmten Fällen leicht dazu führen, dass nicht klar ist, welche Methode überhaupt ausgeführt wird.



  • jo..

    thanks, damit kann ich leben 🙂



  • @gomberl:

    gomberl schrieb:

    bevor ich jetzt zu dem problem deinerseits komme fällt mir gleich eines ins auge
    buttons.add ( new JList() );
    [/java]

    Klar, war ein copy-paste Fehler.

    Es funktioniert aber leider immer noch nicht. Mit super.add() kann man das Problem des rekursiven aufrufs lösen. Dafür schon mal Danke!

    Allerding besteht immer noch der Fehler: reference to add is ambiguous.

    gomberl schrieb:

    aber jetzt zu deinem fehler:

    //damit ermoeglichst du die ueberladung in einer klasse
    //jetzt kann zur laufzeit die richtige methode benutzt werden
    //diese methode leitet nun nur den aufruf direkt an die super klass weiter
    public void add(JComponent choice){
            super.add(choice);
    }
    

    dann gibts kein problem mehr damit

    Leider doch. da ich die Funktion add(Object ob) per interface implementieren muss und nicht add(JComponent comp).



  • bitte poste doch deinen code - ich muss mir das nochmal ansehen
    bei mir funkts ohne probleme

    interfaces sind sogenannte contracts - das heisst jetzt nichts anderes als das sich deine klasse verpflichtet diese methoden bereitzustellen
    also darf das keinen einfluss haben (IMO)

    wenn du mir den code herstellst debug ich ihn nochmal durch

    gomberl



  • @all: Da ich auch die Schnittstelle implemtiere stelle ich jetzt hier doch noch mal die Frage in die Runde ob mein Design so überhaupt gut ist.

    Situation ist die folgende:

    Wir haben hier eine Anuzahl von Klassen, ich nenne diese mal XYZPanel, die von javax.swing.JPanel erben. Alle diese Klassen sollen eine bestimmte add() Methode implementieren welche folgenden Zweck hat: Bei dem adden von einem JButton z.b zu so einer xyzPanel Klasse soll dieser Button nicht nur dem Panel hinzugefügt werden, so wie es die java.awt.Container.add() Methode tut, sondern es sollen weitere Aktionen ausgeführt werden.

    So z.b:

    add(Object component){
      if(component instanceof JButton){
        //Tue etwas spezielles
        super.add(component);
      }
      else super.add(component);
    }
    

    Jede der XYZPanel Klassen steht für einen Component Typ. In der einen Klasse sollen z.b. JButtons "abgefangen" werden, in einer anderen JLists. Also habe ihc mir gedacht alle diese Klassen müssen ein Interface implementieren welches die Klassen dazu zwingt eine solche add Methode zu implementieren.

    Irgendwie ist es aber unschön. Das testen auf isinstanceof könnte man z.b. vermeiden wenn man die Methode derart gestaltet:

    add(JButton but){
      //tue etwas spezielles
      super.add(but);
    }
    

    so würde von vornherein nur bei JButtons die obige methode aufgerufen werden. Allerdings müsste ich so die add(Object) Methode im Interface streichen da ja alle Klassen andere add Methoden implementieren müssen: add(JButton b), add(JList l) usw..

    Könnt Ihr mir folgen :)? und wie würdet Ihr das machen?



  • blauton.com schrieb:

    gomberl schrieb:

    bitte poste doch deinen code - ich muss mir das nochmal ansehen

    public interface OneOfManyChoice {
    
        public abstract void add (Object choice ) ;
    }
    
    public class  OneOfManyChoiceButtons extends JPanel implements OneOfManyChoice  {
      public OneOfManyChoiceButtons () {
        super ();
      }  
    
      add(Object component){
        if(component instanceof JButton){
          //Tue etwas spezielles
          super.add(component);
        }
        else super.add(component);
      } 
    
      public static void main(String args[]){
        OneOfManyChoiceButtons but = new OneOfManyChoiceButtons();
        but.add(new JButton());  //hier Fehler
      }
    }
    

    reference to add is ambiguous; both method add(java.awt.Component) in java.awt.Container and method add(java.lang.Object) in org.eml.adaptiveUI.CIO.OneOfManyChoiceButtons match at line 127 (127:16)



  • doppelpost.



  • okay

    hier nochmal von vorne
    lies dir bitte noch einmal meine antwort durch
    dann sieh dir dieses code stueck an -- bemerkung: test steht fuer oneofmanychoices und test2 fuer dein interface

    /*
     * test.java
     *
     * Created on 03. März 2004, 22:31
     */
    package org.gombsoft.MicroFuzz;
    
    import javax.swing.*;
    
    public class  test extends JPanel implements test2  { 
      public test () { 
        super (); 
      }
    
      public java.awt.Component add(java.awt.Component comp){
          return super.add(comp);
      }
    
      public void add(Object component){ 
        if(component instanceof JButton){ 
          //Tue etwas spezielles 
          super.add((JButton) component); 
        } 
        else 
        {
        }
      } 
    
      public static void main(String args[]){ 
        test but = new test(); 
        but.add(new JButton());  //hier Fehler 
      } 
    }
    

    jetzt lies dir nochmal meine letzte antwort durch

    dann stell ich dir ein paar fragen:

    1. was macht dein interface - ich habe den leisen verdacht das du dir noch nicht so ganz klar bist was ein interface ist und wie das funktioniert

    2)was willst du mit der add methode machen
    - du kannst auch nicht super.add() sagen wenn du ein object hast
    das in Container add als add(java.awt.Component) deklariert ist kannst du kein object reinschmeissen

    1. interface methoden brauchen nicht abstract zu sein - das sind sie automatisch

    2. kann es nicht sein das du einfach nur add(Component) als methode deines interfaces haben willst ???

    ich glaube das waere es

    bin erst wieder am abend online
    falls du noch fragen hast

    gruesse

    gomberl



  • Hallo gomberl, erst mal vielen Dank für Deine Mühen!!

    gomberl schrieb:

    dann stell ich dir ein paar fragen:

    1. was macht dein interface - ich habe den leisen verdacht das du dir noch nicht so ganz klar bist was ein interface ist und wie das funktioniert

    Es soll Methoden vorgeben welche von den Klassen die es "interfacen", implementiert werden müssen da es keine Mehrfachvererbung bei java gibt muss ich das über ein interface machen.

    2)was willst du mit der add methode machen
    - du kannst auch nicht super.add() sagen wenn du ein object hast
    das in Container add als add(java.awt.Component) deklariert ist kannst du kein object reinschmeissen

    die add Methode soll bestimmte Komponenten "abfangen". D.h. diese Bestimmten Komponenten die geadded werden, sollen vorher noch in eine andere Datenstruktur reingepackt werden bevor sie dem JPanel hinzugefügt werden.

    1. interface methoden brauchen nicht abstract zu sein - das sind sie automatisch

    da hast Du recht.

    1. kann es nicht sein das du einfach nur add(Component) als methode deines interfaces haben willst ???

    verstehe nicht was Du meinst, aber könnte stimmen 🙂
    ich glaube das waere es

    Habe ich Dich vielleicht so richtig verstanden: Das Problem bei mir ist das ich die Methode welche aus java.awt.COmponent stammt nicht überschreibe. Ich implementiere nur die Methode add(Object o) aus dem interface aber über schreibe die Methode die geerbt wird nicht.

    Wenn ja verstehe ich nicht ganz was es bringt die einfach mit

    public void add(java.awt.Component comp){
    super.add(comp);
    }

    zu überschreiben.

    Naja ich habs mal gemacht und nun kommt kein neuer Fehler mehr 🙂

    wie gesagt versthen tue ichs nicht ganz warum das überschreiben der Methode die ambiguität auflöst..



  • kein problem

    das stimmt schon so ca - ein interface ist ein vertrag das eine klasse bestimmte methoden implementiert.
    Das mit Mehrfachvererbung ist nur bedingt richtig. Aber lassen wir das. Die Feinheiten erklaer ich dir ein anderes mal. Im grossen und ganzen stimmt das.

    - jetzt haben wir das Problem
    Du willst nur Komponenten abfangen. Nicht aber objects.
    da komme ich auch gleich zu punkt 4.
    Ich glaube was du machen willst ist einfach die add(Component) methode der superklasse zu überladen.
    Die Fragestellung ist soll dein Interface generell Objects bearbeiten oder immer nur sub klassen von Component. Wenn du sagst Objects dann mach es so wie es jetzt ist.
    Wenn du sagst object dann lösche die add(Object) methode und mache alles in Component

    Habe ich Dich vielleicht so richtig verstanden: Das Problem bei mir ist das ich die Methode welche aus java.awt.COmponent stammt nicht überschreibe. Ich implementiere nur die Methode add(Object o) aus dem interface aber über schreibe die Methode die geerbt wird nicht.

    Wenn ja verstehe ich nicht ganz was es bringt die einfach mit

    public void add(java.awt.Component comp){
    super.add(comp);
    }

    zu überschreiben.

    Naja ich habs mal gemacht und nun kommt kein neuer Fehler mehr

    wie gesagt versthen tue ichs nicht ganz warum das überschreiben der Methode die ambiguität auflöst

    Genau so ist es.
    Überladen ist problematisch n diesem Fall. der Compiler weiss nicht ob er die super oder sub klasse aufrufen soll
    Du kannst nur Methoden innerhalb einer klasse überladen - dh mit verschiedenen parametern aufrufbar machen
    ueber klassengrenzen geht es nicht
    aber du kannst ja einfach die methode implementieren und über das super object aufrufen

    zu
    public void add(comp)
    { super.add() }
    usw

    jetzt sind beide methoden innerhalb der aktuellen klasse definiert
    das heisst zur laufzeit kann unterschieden werden welche methode von den 2 aufgerufen wird. das geht nicht ueber klassengrenzen hinaus.
    da du bei add(Component) hier nur dasselbe machen willst wie die superklasse reicht ein super.add(component)

    eins muss dir jetzt schon klar sein
    alles was ein component ist - also alles was in awt oder swing enthalten ist wird NICHT von der add(object) methode abgearbeitet sondern von der add(Component methode) - das heisst

    ein
    if(component instanceof JButton){
    in der add(object) bringt dir nichts
    er wird dort nicht hinkommen
    da JButton ein Component ist wird er immer
    add(Component) aufrufen

    ich hoffe ich habe nicht alle klarheiten beseitigt 😉



  • gomberl schrieb:

    Das mit Mehrfachvererbung ist nur bedingt richtig. Aber lassen wir das. Die Feinheiten erklaer ich dir ein anderes mal. Im grossen und ganzen stimmt das.

    Das brauchst Du nicht. Ich glaube ich weis welchen Sinn und Zweck interfaces haben. Das Problem ist vielleicht das ich damit designtechnisch noch nicht so viele Erfahrungen gemacht habe, sodass ich nicht genau weiss ob ich in diesem Fall ein Interface verwenden soll.

    eins muss dir jetzt schon klar sein
    alles was ein component ist - also alles was in awt oder swing enthalten ist wird NICHT von der add(object) methode abgearbeitet sondern von der add(Component methode)

    Yep das ist klar. ABer ich habe es trotzdem verstanden. Nun muss ich eben die add(Object o) Methode im Interface durch java.awt.Component ersetzen.


Anmelden zum Antworten