methoden Überladen



  • Hi

    meine Klasse hat zwei Methoden:

    add(Object)

    add(java.awt.Component)

    Da ja COmponent von Object erbt, bekomme ich immer einen ambiguous Method Fehler wenn ich add(aComponent) aufrufe.

    Schlechtes Klassendesign oder leicht zu beheben?

    Ich muss halt in einer Klasse die von Jframe erbt eine Klassen interfacen die auch eine add Methode hat.



  • blauton.com schrieb:

    Hi
    Da ja COmponent von Object erbt, bekomme ich immer einen ambiguous Method Fehler wenn ich add(aComponent) aufrufe.

    Soweit ich weiss ist was du hier sagst nicht wirklich korrekt.
    das ist ja der sinn der überladung

    poste doch mal deinen code

    ich will mir das mal ansehen

    weil folgender extrem simpler code funktioniert: (powered by Netbeans 😉 )

    public class frmTest extends javax.swing.JFrame {
    
        public frmTest() {
            javax.swing.JButton cmdBut = new javax.swing.JButton("test");
            addObject(cmdBut);
            initComponents();
        }
    
        public void addObject(Object a){
            System.out.println("adding object");
        }
    
        public void addObject(java.awt.Component a){
            System.out.println("adding component");
        }
    
        private void initComponents() {
    
            addWindowListener(new java.awt.event.WindowAdapter() {
                public void windowClosing(java.awt.event.WindowEvent evt) {
                    exitForm(evt);
                }
            });
            pack();
        }
    
        private void exitForm(java.awt.event.WindowEvent evt) {
            System.exit(0);
        }
    
        public static void main(String args[]) {
            new frmTest().show();   
        }       
    }
    


  • Hi bei Dir funktioniert es weil Dein javax.swing.JButton cmdBut
    zwar ein Object ist aber kein java.awt.Component. Daher weiss java welche Methode gemeint ist (nämlich die add(Object) Methode)

    Bei mir erbt das übergebene Object allerdings sowohl von java als auch von java.awt.Container.

    JBuilder meint dazu:

    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 36 (36:11)



  • 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


Anmelden zum Antworten