Abstrakte Klassen - Gebrauch von Konstruktor?

flashray

Erfahrenes Mitglied
Hallo,

Wie greift man auf den Konstruktor einer Abstrakten Klasse zu?

Folgendes Problem:

Code:
public abstract class Abstrakt {
	
	static String a = "a";
	
	public Abstrakt() {
		a = "b";
	}
	
	public static void test() {
		System.out.println(a);
	}
}

public class AbstraktUser {
	
	public static void main (String[] args) {
		Abstrakt.test();
	}
}

Ich möchte das wenn ich die statische Methode test() von Abstrakt aufrufe der Konstruktor aufgerufen wird. Hier im Beispiel sollte dann nicht a sondern b ausgegeben werden.

Oder ist das nur mit Singleton zu realisieren?

Vg Erdal
 
Ich habe noch nicht wirklich mit abstrakten Klassen gearbeitet, aber so weit ich weiß, sind sie nicht dazu da, wirklich instanziiert zu werden. So weit ich das verstanden habe musst du erst eine Klasse von der abstrakten Klasse erben lassen. Erst von dieser Klasse kannst du dann den Konstruktor aufrufen, welchen du schon in der abstrakten Klasse definiert hast. Deshalb machen auch statische Methoden in einer abstrakten Klasse keinen Sinn .. imho. Korrigiert mich, wenn ich falsch liege.

Also kurz: abstrakte Klassen sind nur Schablonen für konkrete Klassen und werden nicht instanziiert. (unter Vorbehalt :) )
 
teppi hat Recht (gute Erklärung)! :D

Abstrakte Klassen werden meines Wissens nach nur als Schablonen verwendet, dh es macht eigentlich keinen Sinn, eine abstrakte Klasse zu erstellen, ohne auch eine andere Klasse zu besitzen, welche die abstrakte Klasse erweitert.
Abstrakte Klassen sollten nur dazu benutzt werden, dass man gewisse Methoden vorgibt (mit abstract, ohne Implementierung), welche dann erst in den jeweiligen Sub-Klassen implementiert werden.

Außerdem - wofür brauchst du eine abstrakte Klasse ohne abstrakte Methode(n)?! :confused:
Oder verwechselst du da was mit Interfaces?!

Hope it helps...

lg D;-]c
 
Hi!

Abstrakte Klassen dienen eigentlich nur zur Vereinfachung und zum Erhöhen der Abstraktion (du mußt ja nur noch die neuen Methoden implementieren - der Rest ist in der abstrakten Klasse (oder eigentlich der Basisklasse). Also kurz: eine Schablone ^^

Du kannst allerdings sehr wohl auf die Basisklasse deiner konkreten Klasse zugreifen. Dein Beispiel macht wenig Sinn, aber es wäre möglich.

Ich habe hier mal ein kleines Beispiel zusammengestellt. Vielleicht hilft dir das weiter.

Zunächst die abstrakte Klasse:

Code:
public abstract class AbstractClass {
  public AbstractClass() {
    // code 
  }

  // diese methode ist eine abstrakte methode und muss von allen erbenden klassen implementiert werden. 
  public abstract void myTest();

  // eine typische methode die für alle abgeleiteten klassen gleich sein könnte. bei bedarf kann diese überschrieben werden. 
  public void print() {
    System.out.println("print method from abstract class");
  }

  // template method --> design pattern. wird relativ oft angewendet, wenn nach außenhin die schnittstelle gleich sein soll, aber die einzelnen objekte unterschiedlich auf diesen aufruf reagieren sollen. zeigt wozu man abstrakte methoden einsetzen kann / könnte
  public void test() {
    this.myTest();
  }

Hier die konkrete Klasse die von AbstractClass erbt:

Code:
public class ConcreteClass extends AbstractClass {
  public ConcreteClass() {
    // aufruf des constructors von AbstractClass (alles was nun im constructor passiert wird auch in dieser klasse gemacht.
   super();
  }

  // die abstrakte methode muss implementiert werden
  public void myTest() {
    System.out.println("concrete implementation of abstract method myTest");
  }

  // überschreiben der methode print()
  public void print() {
    System.out.println("print method from concrete implementation class");
    // aufrufen der methode print() der basisklasse - hier AbstractClass
    super.print();
  }
}

Die Ausgabe anhand der folgenden Mainmethode:

Code:
public static void main(String[] args) {
  ConcreteClass cc = new ConcreteClass();
  cc.print();
  cc.myTest();
}

Code:
print method from concrete implementation class
print method from abstract class
concrete implementation of abstract method myTest

Hoffe es hilft ein wenig.

Gruß
TOM
 
Hallo,

zunächst Danke an alle. Nach diesen umfangreichen Ausführungen bin ich zu dem Ergebnis gekommen, das abstrakte Klassen nicht geiegnet sind für das was ich möchte. Habe mein Beispiel nun auch mit Singleton ausprobiert, es funktioniert.

Der Hintergrund meines Problems ist folgendes. Ich möchte meine Implementation in eine Haupt und viele Nebenklassen aufteilen, wobei das gegenseitige Aufrufen von Methoden und Variablen beiderseits von Haupt und Nebenvariablen möglich sein soll. Mein Ansatz ist nun folgender: Die Hauptklasse ist die Superklasse und die Nebenklassen deren Subklassen. Somit kann ich von den Nebenklassen direkt auf die Hauptklasse zugreifen. Umgekehrt geht es leider noch nicht. Also von der Hauptklasse kann ich noch nicht auf die Nebenklassen zugreifen. Tue ich die Nebenklassen in der Hauptklasse instanzieren, gibt es Probleme wegen der Vererbung. Um das Instanzieren zu vermeiden und die Kommunikation zu gewährleisten habe ich dann in den Nebenklassen alles statisch definiert. Jetzt ist das gegenseitige aufrufen beiderseits gelöst. Da ich aber jetzt die Nebenklassen nicht instanziere, musste ich auf die Konstruktoren dieser verzichten. Wenn ich die Nebenklassen als Singleton definiere kann ich sowohl auf deren Methoden mit getInstance zugreifen als auch Gebrauch derer Konstruktoren machen. Auch gibt es keine Probleme bezüglich der Vererbungsbeziehungen.

Ich hoffe das war jetzt nicht zu sehr verwirrend :) , konnte nie gute Aufsätze schreiben.
Falls jemand eine bessere Idee hat, oder es eine einfachere Standardlösung gibt, die ich nicht kenne, würde ich auch gerne diese erfahren.

Vg Erdal
 
Ich bin mir jetzt nicht ganz sicher, und ich hoffe nicht, dass ich mich täusche bzw dein Problem falsch verstanden habe - aber hast du schon mal daran gedacht, eine Factory zu verwenden?!

Außerdem - ist es wirklich sinnvoll, dass du in der Hauptklasse auf die Subklassen zugreifst?! Wozu soll das gut sein?!

Correct me if it's wrong... ;)

lg D;-]c
 
Hallo Doc,

was eine Factory ist wüsste ich jetzt nicht, müsste erst mal nachlesen.

Wozu möchte ich von der Hauptklasse aus auf die Subklassen zugreifen? Ich möchte meinen Programmcode übersichtlich in viele kleine oder mittelgroße Klassen verteilen. Durch das verteilen des Codes habe ich nun mehr Übersicht, aber das gegenseitige Zugreifen auf Methoden und Attribute zwischen diesen ist dann nicht direkt Möglich. Die Vererbung benutze ich dann eben für dies.
Konkret heißt das folgendes:
Ich schreibe einen kleinen Texteditor vergleichbar mit dem Standart-Editor von Microsoft Windows. Die Codeverteilung habe ich mir jetzt so vorgestellt.

Main - Klasse -> Aufruf des Programms

Hauptguiklasse:
Editor - Klasse

Nebenklassen:
Datei - Klasse
Bearbeiten - Klasse
Format - Klasse
Ansicht - Klasse
Hilfe - Klasse

Als Beispiel Implementierung von der Klasse Datei (enthaltene Mehtoden):
Neu, Speichern, Speichern Unter, Öffnen, Drucken, Seite Einrichten, Beenden

Analog sieht die Implementierung der anderen aus. Beispielsweise habe ich in der Klasse Format einen FontChooser der aus der Klasse Editor aufgerufen werden soll. Umgekehrt soll der FontChooser aus der Klasse Format die Schrift der JTextArea verändern welche in der Editorklasse implementiert ist.

Hier ein kleines Beispiel:

Superklasse
Code:
public class Editor {

	static JTextArea ta = new JTextArea();

	static JButton button = new JButton();

	public Editor() {

		// ...
		
		ActionListener changefont = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Format.schrift();
			}
		};
		button.addActionListener(changefont);
	}
}

Subklasse
Code:
public class Format extends Editor{

	public static Font fontchooser() {
		
		// Implementierung Aufruf von FontChooser und Übergabe der neuen Werte
		
		return new Font ("Serif" , Font.BOLD, 20);
	}
	
	public static void schrift() {
		Font f = fontchooser();
		ta.setFont(f);
	}
}

So bestehen zwischen allen Klassen gegenseitige Beziehungen, welche sich offensichtlich aus der Funktionsweise des Editors ergibt. Wie gesehen benutze ich die statischen Methoden und die Vererbung nur Zwecks der Kommunikation zwischen den Klassen.

Vielleicht noch eines. Ich möchte den FontChooser natürlich initialisieren und dann immer nur jeweils nur aufrufen. Deswegen wird die Format - Klasse voraussichtlich eine Singleton - Klasse sein damit ich den Fontchooser in dem Konstruktor von Format implementiere und in der Methode schrift() von Format nur noch aufrufen muss.

Deswegen das ganze mit der Vererbung, static und Singleton.

Oder würdet Ihr vielleicht doch die ganze Implementierung in eine Klasse packen? Wie würde euer Ansatz aussehen?

Vg Erdal
 
Zuletzt bearbeitet:
Wenn du Informationen zwischen deinen Klassen austauschen möchtest schreibe dir doch einen eigenen eventlistener und feure bei bedarf events ab. So kannst du deine anderen Klassen darüber informieren das sich z.b. der Font geändert hat und entsprechend darauf reagieren..
 
Hallo Elmato,

danke für den Tip. Bisher sind zwei Techniken genannt worden die ich noch nicht kenne. Einmal das "Factory" und jetzt der "Eventlistener". Werde mir das in der nächsten Zeit zu Gemüte führen. Das mit dem "Abfeuern - Eventlistener" hört sich garnicht schlecht an.

Vg Erdal
 
Ich habe hier noch ein altes und wahrscheinlich ziemlich gruseliges Beispiel als ich mir einen Listener für eine Jtable geschrieben habe, du kannst aber daraus ableiten wie es ungefähr auszusehen hat ;)
Code:
package sheets.models;

import java.util.List;
import java.util.Vector;

import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

import events.ContentListener;
import events.ModelEvent;


public class Model extends DefaultTableModel {
	
	static final long serialVersionUID =  -8717671986526504918L;
	
	private List listeners = new Vector(); // Hier werden alle Listener gespeichert
	/**
	 * 
	 */
	public Model() {
		super();
		
	}
	/**
	 * @param data
	 * @param columnNames
	 */
	public Model(Object[][] data, Object[] columnNames) {
		super(data, columnNames);
		
		
	}
	/**
	 * keine zelle ist editierbar
	 */
	public boolean isCellEditable(int row, int col){
	 	return false;
	}
	  /**
	   * Fuegt einen listener der liste hinzu
	   * @param listener
	   */
	  public void addContentChangeListener( ContentListener listener ){ 
	    listeners.add( listener ); 
	  } 

	  /**
		  * Und mit dieser Methode kann man schlussendlich ein Event an die Listener verschicken.
		  * @param m Jtable wird benoetigt um festzustellen wohin das event verschickt werden soll
		  * @param values beliebige values veschicken
		  * @param row eine einzelne reihe oder einzelne doubles verschicken
		  * @param id wird gebraucht um beim empfaenger festzustellen woher da event kam
		  */
		  public void fireContentChanged( JTable m, Object [][] values, double[] row, String id ){ 
		    // Ein neues Event generieren (mit irgendwelchen Informationen ... ) 
		    ModelEvent event = new ModelEvent(m, values, row, id); 
		   
		    // an die Listener verschicken 
		    for( int i = 0, n = listeners.size(); i<n; i++ ) {
		    	//System.out.println(listeners.get(i).getClass() +" @@@");
		    	if(listeners.get(i).getClass() == m.getClass()) {
			    	((ContentListener)listeners.get( i )).contentChanged( event );
		    	}
		    }
		  }
}
In dieser Klasse werden die Listener registriert..
Code:
package events;
import javax.swing.JTable;


public class ModelEvent  {
	
	private Object [][] values;
	private double[] row;
	private String id = "";
	private JTable table = null;
	
	
    public ModelEvent(JTable table, Object [][] values, double [] row, String id){
    	this.table = table;
    	this.id = id;
    	this.values = values;
    	this.row = row;
    }

	public Object[][] getValue() {
		return values;
	}

    public JTable getSource(){
	  	return this.table;
	  }
    
	public double[] getRow() {
		return row;
	}
	public String getID(){
		return this.id;
	}
}
das ist die eigentliche Event Klasse
Code:
public interface ContentListener {
	public void contentChanged(ModelEvent e);

}
das Interface zur typisierung und implementation für die JTables
Und hier Auszüg aus eine Jtable..
Code:
public class FYISTable extends JTable implements FiveYearIncomeStatementDATA, ContentListener{
....
//die LIstener die registriert werden müssen da diese Tabelle an deren Ereignissen interessiert ist
fyisModel.addContentChangeListener(DEBTable.getInstance());
fyisModel.addContentChangeListener(STTable.getInstance());
....
Auszüge aus der implemtierten Methode contentChanged(vom Interface....)
public void contentChanged(ModelEvent e) {
		if(e.getID() == "FC"){
			System.out.println("Content change in fyis von FC");
			dataFromFC = e.getRow();
			doFYIS();
		}
}
...
Ein Beispiel wo ein Event abgefeuert wurde..
fyisModel.fireContentChanged(IITable.getInstance(), dataForII, null, "FYIS");
Wie gesagt das hier ist bestimmt kein toller Code und ich kann unsere Profis hier förmlich erschauern sehen(einzige Verteidigung die ich habe das das schon ne weile her ist...) aber es soll dir auch nur einen kleinen Einblick geben wie so ein Event aussehen kann.
Du kannst auch mal nach propertyChangeEvent googeln, das ist der Mechanismus den die JavaBeans vorschreiben, evt. komme ich die Tage mal dazu ein generishces Beispiel zu schreiben...
hoffe ich konnte dir helfen..
mfg elmato

//edit
Im Prinzip ist der ganze Aufbau wie bei einem ActionListener
du hast das Interface ActionListener das bei mir ContentChanged heisst, du hast das ActionEvent, das bei mir ModelEvent heisst und du hast eine Komponente(z.b. JButton) was bei mir halt das Model wäre
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück