Anzeige:
Ergebnis 1 bis 15 von 15

Thema: Constructor für überladene Klassen

  1. #1
    Registrierter Benutzer
    Registriert seit
    16.06.2002
    Beiträge
    18

    Question Constructor für überladene Klassen

    hallo allen zusammen,

    ich habe folgende Frage:

    Ich möchte eine abstrakte Klasse foo durch die Klasse myclass implementieren, so dass die volle Funktionalität in foo ist, jedoch eine Variable myvar spezifisch in myclass gesetzt wird.

    Code:
    abstract class foo {
    	int myvar;
    	
    	foo() {
    		dosomething();
    	}
    	
    	abstract void dosomething();
    }
    
    class myclass extends foo {
    	void dosomething() {
    		myvar=10;
    	}
    }
    Mein Problem ist nun, dass es nicht funktioniert: ich muss in myclass eine Konstruktor mitgeben, so dass ich folgendes habe:

    Code:
    class myclass extends foo {
    	myclass() {
    		super();
    	}
    		
    	void dosomething() {
    		myvar=10;
    	}
    }

    Tut das not? Warum wird der Konstruktur nicht ebenfalls abgeleitet? Kann ich es irgendwie so schreiben, dass ich mir den zweiten Konstruktor, der ja doch nur super() aufruft, spare?

    Ich freue mich über alle sachdienlichen Hinweise! Viele Grüße
    kit

  2. #2
    Registrierter Benutzer
    Registriert seit
    19.07.2004
    Beiträge
    50
    Ne, Konstruktoren werden nicht abgeleitet, soweit ich weiß. Das ginge aber in C++

  3. #3
    Registrierter Benutzer
    Registriert seit
    08.07.2002
    Beiträge
    377
    Das ist doch sehr gefaehrlich was du da vorhast. Wenn es funktionieren wuerde, dann wuerde die Sache sicher eine dicke Exception bringen. Spaetestens wenn du auf die noch nicht gesetzte Variable irgendwelche Operationen ausfuehren willst.
    Das Attribut in der Superklasse ist so lange null, bis du es in der Subklasse setzt, wenn ich dich reichtig verstehe.
    Wenn du also im Konstruktor der Superklasse eine Methode aufrufst, die mit dieser Variable arbeitet, dann ist die Variable immer noch null.
    Die Methode wird ausgefuehrt, dann kommt erst die Methode der Subklasse dran und setzt den Wert fuer die Superklasse (wenn du ueberhaupt dazu kommst).

    mfg nul
    Amilo D - 2,8 Ghz - ATI Radeon 9000
    Debian GNU/Linux 3.1 (Sarge)

  4. #4
    Registrierter Benutzer
    Registriert seit
    16.06.2002
    Beiträge
    18

    Lightbulb

    @nul:

    ich verstehe nicht, was daran gefährlich sein soll: um Deine argumentation zur vermeiden, ist die Klasse foo bzw. die Methode dosomething ja abstract. Das ist ganz simples überladen von Funktionen. Es funktioniert ja auch, nur eben mit einem aus meiner Sicht völlig überflüssigem Konstruktor, der aber auch nur den Konstruktor von foo aufruft.
    Stell Dir mal eine Tabelle zum Editieren vor, die für verschiedene Aufgaben verschiedene Spalten mit verschiedenen Formatierern hat. Dann wird der Zweck evident. Ich habe nur ein einfaches Beispiel dargestellt.

    @KL47:

    Danke für die Bestätigung, ich hatte auch nur in Erinnerung, dass es in C++ geht. Mir ist nur der Sinn der Einschränkung in Java nicht wirklich klar. Warum kann er nicht einfach den vorhandenen Konstruktor nehmen??? Ich finde Java ziemlich "redselig"...
    Geändert von kit (13-02-2005 um 19:12 Uhr)

  5. #5
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Wenn du die Variable im Konstruktor setzen willst und jede Subklasse muss sie setzen, wäre es nicht besser du machst es im Konstruktor?

    Code:
    public class Foo
    {
        private int myvar;
    
        protected Foo(int var)
        {
            myvaw = var;
        }
    }
    Code:
    public class MyClass extends Foo
    {
        public MyClass()
        {
            super(10);
        }
    }
    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  6. #6
    Registrierter Benutzer
    Registriert seit
    16.06.2002
    Beiträge
    18

    Cool

    guten Morgen anda_skoa,

    Du hast recht, ich könnte auch den gesamten Konstruktor ableiten und die Variable dort setzen oder die Variable als Parameter übergeben.

    Der Grund, warum ich dass dann doch nicht mache, ist die praktische Anwendung. Es geht um eine Tabelle, welche in den Spalten nur ein Datum oder eine Währungsangabe akzeptiert. Dazu gebe ich spezielle CellRenderer und CellEditoren mit. Diese Tabelle gibt es in meinem Programm in verschiedenen Versionen: mal mit 2 Spalten (Date,Decimal), mal mit 3 Spalten (Date, Date, Decimal), mal mit 5 Spalten (Decimal, Decimal, Date, Date, Decimal) usw.

    Der Konstruktor der Tabelle initialisiert nun die Tabelle und benötigt dafür zwei Arrays: eines für die CellEditoren, eines für die CellRenderer.
    Möchte ich das nun als Parameter übergeben und im Konstruktor selbst setzen, nehme ich die ganze Initialisierung und die Packete javax.swing.JTable und javax.swing.table.* in die Klasse, welche nachher meine Tabellen aufrufen und anzeigen soll. Da geht mir der Überblick verloren, es ist mir zuviel Code an der falschen Stelle.

    Stattdessen bevorzuge ich, die Arrays für die CellEditoren und die CellRenderer abstract zu deklarieren und dann für jede Implementierung der Tabelle mit 2,3,4,5 Spalten eine eigene Klasse abzuleiten, welche ausschließlich die Arrays setzt. Sieht nach meinem Empfinden sauber aus -- wenn der blöde Konstruktur nicht sein müsste.

    Viele Grüße
    kit

  7. #7
    Registrierter Benutzer
    Registriert seit
    16.06.2002
    Beiträge
    18

    Question

    by the way: kann ich Arrays auch nach der Deklaration mit geschweiften Klammern {} initialisieren? also statt
    Code:
    Object o={a, b, c};
    lieber ein
    Code:
    Object o;
    //ganz viele Zeilen Code
    o={a,b,c};
    Ich weiss, dass zweites Beispiel nicht geht, suche aber nach einer Möglichkeit, es genauso komfortabel zu machen.

    Viele Grüße
    kit

  8. #8
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Ich verstehe leider das Problem jetzt nicht mehr.

    Von deinem ursprünglichen Code ausgehend ist mein Ansatz wesentlich weniger Aufwand.

    Abgesehen davon das Fehlen eines Defaultkonstruktors und der Parameter im verfügbaren Konstruktor der Basisklasse die Wichtigkeit des Parameters hervorheben und auch garantieren, dass etwas gesetzt wurde.

    Worin besteht aus deiner Sicht der Unterschied zwischen Überschreiben einer Methode und Überschreiben eines Konstruktors?

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  9. #9
    Registrierter Benutzer
    Registriert seit
    16.06.2002
    Beiträge
    18
    Zitat Zitat von anda_skoa
    Ich verstehe leider das Problem jetzt nicht mehr.
    ;o) habe ich befürchtet, ist wohl auch mit Code besser zur erklären, als mit worten. ich habe nur leider das Teil nicht hier.

    Von deinem ursprünglichen Code ausgehend ist mein Ansatz wesentlich weniger Aufwand.
    ja, dass ist richtig. das Beispiel ist klar vereinfacht, um die Struktur (nicht den Sinn) meines Problems klar zu machen. ich hänge heute Abend mal den richtigen Code an.

    Worin besteht aus deiner Sicht der Unterschied zwischen Überschreiben einer Methode und Überschreiben eines Konstruktors?
    gehen wir mal davon aus, dass ich eine Methode habe, die aus einem festen, generischen Teil A und einem variablen, veränderlichen Teil B besteht. dann möchte ich natürlich A nur einmal schreiben und B muss ich für jede Ableitung einzeln schreiben.

    Ich wollte A als Konstruktor umsetzen, der dann B aufruft, so dass ich nur B schreiben muss.

    Alternativ könnte ich nun entweder A als Konstruktor schreiben, der B als Parameter bekommt. Das will ich aber nicht, weil aus meiner Sicht schlechte Struktur.

    Zuletzt kann ich A als Methode schreiben und B jeweils als Konstruktor, der dann A aufruft. Dass kommt dem, was ich möchte am nächsten, aht aber zwei Nachteile:
    1) Ich muss die Methode A in jedem abgeleiteten Konstruktor explizit aufrufen --> rendundant, fehleranfällig, häßlich
    2) Ich muss im Konstruktur Variable und Objekte initialisieren, was eigentlich zum fixen Teil A gehört --> wieder Redundanz.

    Somit werde ich wohl dabei bleiben, dass ich den überflüssigen Konstruktor umsetze, der super() aufruft.

    Ist nur eben schade, dass es mit JAVA nicht geht.

    Code:
    import javax.swing.JTable;
    import javax.swing.table.*;
    import java.util.Iterator;
    import java.util.Vector;
    import java.util.Date;
    import java.math.BigDecimal;
    import javax.swing.border.EmptyBorder;
    
    abstract class RuleTable extends JTable {
    	GlobalProperties GP;
    	DefaultTableModel dtm;
    	
    	String[] hs;
    	TableCellEditor[] tce;
    	DefaultTableCellRenderer[] dtcr;
    	
    	RuleTable(GlobalProperties GP) {
    		EmptyBorder EB=new EmptyBorder(0,0,0,0);
    		dtm = new DefaultTableModel();
    		this.GP=GP;
    		
    		initRuleTableColumns();
    		for (int i=0; i<hs.length; i++) {
    			dtm.addColumn(	GP.localizeStr(hs[i]) );
    		}
    		setModel(dtm);
    		for (int i=0; i<hs.length; i++) {
    			dtcr[i].setBorder(EB);
    			getColumnModel().getColumn(i).setCellRenderer( dtcr[i] );
    			getColumnModel().getColumn(i).setCellEditor( tce[i] );
    		}
    	}
    	
    	abstract void initRuleTableColumns();
    	
    	public void addRow() {
    		Object[] o={new Date(), new BigDecimal(0d)}; 
    		dtm.addRow(o);
    	}
    	
    	public void removeRow() {
    		int r=getSelectedRow();
    		dtm.removeRow(r);
    		if (r>1) { 
    			setRowSelectionInterval(r,r); 
    		} else {
    			clearSelection();
    		}
    	}
    }
    
    
    class CapitalRuleTable extends RuleTable {
    	CapitalRuleTable(GlobalProperties GP) {
    		super(GP);
    	}
    	
    	void initRuleTableColumns() {
    		String[] hs = {"i18n_Valuta","i18n_Amount"}; this.hs=hs;
    		TableCellEditor[] tce={new DateTextField(GP), new DecimalTextField(GP)}; this.tce=tce;
    		DefaultTableCellRenderer[] dtcr={new DateCellRenderer(), new DecimalCellRenderer("#,##0.00")}; this.dtcr=dtcr;
    	}
    }
    Geändert von kit (15-02-2005 um 17:34 Uhr)

  10. #10
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Hmm, ich verstehe das Problem jetzt wesentlich besser.

    Allerdings ist die Lösung noch nicht sehr gut, die Basisklasse nimmt einfach an, dass die Subklasse was richtiges macht, die API selbst erfordert das nicht, d.h. eine Subklasse könnte die abtrakte Methode auch einfach leer implementieren.

    Besser wären für alle drei Arrays jeweils eine Methode mit entsprechendem Rückgabewert, das ist schon mal ein guter Hinweis.
    Theoretisch brauchst du die drei Arrays dann nur als lokale Variablen im Basisklassenkonstrukto, außer du brauchst die konkreten Arrays noch später.

    Vermutlich gibt es noch sauberere Lösungen, vielleicht eine Klasse die die korrekten Arrays erzeugen kann, die Subklasse müsste dann nur einen Instanz davon an super() weitergeben.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  11. #11
    Registrierter Benutzer
    Registriert seit
    08.07.2002
    Beiträge
    377
    Zitat Zitat von kit
    by the way: kann ich Arrays auch nach der Deklaration mit geschweiften Klammern {} initialisieren? also statt
    Code:
    Object o={a, b, c};
    lieber ein
    Code:
    Object o;
    //ganz viele Zeilen Code
    o={a,b,c};
    Ich weiss, dass zweites Beispiel nicht geht, suche aber nach einer Möglichkeit, es genauso komfortabel zu machen.

    Viele Grüße
    kit

    Jup, mit
    Code:
    Object[] o;
    o = new Object[]{...};
    Sollte glaub ich so gehn, bin mir nicht 100% sicher
    Amilo D - 2,8 Ghz - ATI Radeon 9000
    Debian GNU/Linux 3.1 (Sarge)

  12. #12
    Registrierter Benutzer
    Registriert seit
    16.06.2002
    Beiträge
    18
    Zitat Zitat von anda_skoa
    Allerdings ist die Lösung noch nicht sehr gut, die Basisklasse nimmt einfach an, dass die Subklasse was richtiges macht, die API selbst erfordert das nicht, d.h. eine Subklasse könnte die abtrakte Methode auch einfach leer implementieren.
    Ja, das ist prinzipiell richtig. Aber ich bin überrascht, dass das ein Problem ist, denn letztendlich darf ich nicht erwarten, dass etwas funktioniert, wenn ich es nicht schreibe. Ich könnte die Initialisierung auch in der Basisklasse vergessen, da sehe ich keinen Unterschied...

    Besser wären für alle drei Arrays jeweils eine Methode mit entsprechendem Rückgabewert, das ist schon mal ein guter Hinweis.
    Ok, aber mir ist noch nicht klar, was ich dann gewinne: könnte ich wie oben nicht auch vergessen, etwas in die Arrays zu schreiben und dann leere Arrays zurückgeben???

    Theoretisch brauchst du die drei Arrays dann nur als lokale Variablen im Basisklassenkonstrukto, außer du brauchst die konkreten Arrays noch später.
    sehr gutes Argument, das verstehe ich.

    Vermutlich gibt es noch sauberere Lösungen, vielleicht eine Klasse die die korrekten Arrays erzeugen kann, die Subklasse müsste dann nur einen Instanz davon an super() weitergeben.
    Das verstehe ich auch, allerdings halte ich es dann für theoretisch sauber, praktisch aber für unübersichtlicher. das ist gewiss Ansichtssache.

    vielen Dank für Deine Hilfe und Kritik und viele Grüße
    kit

  13. #13
    Registrierter Benutzer
    Registriert seit
    16.06.2002
    Beiträge
    18
    Zitat Zitat von nul
    Jup, mit
    Code:
    Object[] o;
    o = new Object[]{...};
    Sollte glaub ich so gehn, bin mir nicht 100% sicher
    naja, gemäß meinem Beispiel habe ich versucht:
    Code:
    hs = String[]{"i18n_Valuta","i18n_Amount"};
    und erhalte:
    Code:
    compile:
        [javac] Compiling 2 source files to /home/are/src/buchungsplan/bin
        [javac] /home/are/src/buchungsplan/src/RuleTable.java:59: '.class' expected
        [javac]             hs = String[]{"i18n_Valuta","i18n_Amount"};
        [javac]                              ^
        [javac] 1 error
    scheint also nicht zu funktionieren. aber der Versuch war es wert.
    Viele Grüße
    kit

  14. #14
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von kit
    Ja, das ist prinzipiell richtig. Aber ich bin überrascht, dass das ein Problem ist, denn letztendlich darf ich nicht erwarten, dass etwas funktioniert, wenn ich es nicht schreibe. Ich könnte die Initialisierung auch in der Basisklasse vergessen, da sehe ich keinen Unterschied...
    Die eine Methode bietet selbst wenig Hinweise, welche Variablen eine Implementierung zu setzen jat.

    Ok, aber mir ist noch nicht klar, was ich dann gewinne: könnte ich wie oben nicht auch vergessen, etwas in die Arrays zu schreiben und dann leere Arrays zurückgeben???
    Klarer Fall, aber du könntest zB für jede der drei Methoden den Rückgabewert prüfen und im Bedarfsfall eine Exception werfen.
    Der wesentliche Vorteil ist aber der Hinweise welche drei Dinge von der Subklasse erwartet werden.

    Das verstehe ich auch, allerdings halte ich es dann für theoretisch sauber, praktisch aber für unübersichtlicher. das ist gewiss Ansichtssache.
    Ist praktisch ähnlich wie die Sache mit dem TableModel. Sicher auf den ersten Blick mehr Aufwand alsvon JTable direkt abzuleiten und ein paar Methoden zu implementieren, aber wesentlich besser abstrahiert und daher universeller einsetzbar.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  15. #15
    Registrierter Benutzer
    Registriert seit
    16.06.2002
    Beiträge
    18

    Talking

    hi,

    ich verstehe Deine argumente im Hinblick auf exportierte API's. Und Du hast recht, denn in Deinen Beispielen hast Du explicit public deklariert.
    Allerdings ging ich immer von einer private-Deklaration aus, wollte also meine Tabelle nicht zugänglich machen. Ich muss also wissen, welche Variablen ich zu setzen habe. Wenn ich es nicht weiss, sagt es mir spätestens der Compiler ;o) Deshalb bevorzuge ich hier weniger, schlanken Code.

    Viele Grüße
    kit

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •