Dynamisch Konstruktor aufrufen

xZise

Aktives Mitglied
Moin,
ich versuche folgendes Problem zu lösen:
Es gibt mehrere Klassen die von einer anderen abgeleitet sind. Zu jeder Klasse gibt es eine entsprechende Gegenstückklasse (wenn man so will). Und ich möchte jetzt einfach eine Instanz davon erstellen, anhand der Gegenstückklasse.

Konkret:
Es gibt mehrere Klassen die alle (mehr oder weniger tief) von Field abgeleitet sind. Die möchte ich aber nicht bearbeiten. Stattdessen habe ich einen FieldDrawer. Davon leiten sich verschiedene andere Klassen ab, die anhand eines Fields jetzt was zeichnen.

So sieht die Hauptklasse aus:
Java:
package org.ojim.client.gui.GameField.fielddrawer;

import java.awt.Graphics;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.ojim.logic.state.fields.Field;
import org.ojim.logic.state.fields.GoField;
import org.ojim.logic.state.fields.Jail;

/**
 * A abstract drawer to draw a field. For every field class at least one drawer
 * has to exists.
 * 
 * Any new drawer has to be set in the internal drawermap. Either by register
 * himself or by adding this class in the static block.
 * 
 * Because this is an abstract class it is not possible to create an instance of
 * this class. Therefore a {@link #getDrawer(Field)} exists, which returns a
 * drawer for a given field-class.
 * 
 * @author Fabian Neundorf.
 */
public abstract class FieldDrawer {

	/** Internal map to store which drawer belongs to which fieldclass. */
	private static final Map<Class<? extends Field>, Class<? extends FieldDrawer>> drawerMap = new HashMap<Class<? extends Field>, Class<? extends FieldDrawer>>();

	/*
	 * Add here all drawers to the internal map! Or call somewhere in the
	 * subclass the static method register. This has to be done BEFORE the first
	 * need of the class.
	 */
	static {
		drawerMap.put(GoField.class, GoFieldDrawer.class);
		drawerMap.put(Jail.class, JailDrawer.class);
	}

	protected Field field;

	public FieldDrawer(Field field) {
		this.field = field;
	}

	public abstract void drawTo(Graphics g);

	protected static void register(Class<? extends Field> fieldClass,
			Class<? extends FieldDrawer> drawerClass) {
		drawerMap.put(fieldClass, drawerClass);
	}

	/**
	 * Returns the drawer to the given field and sets the field property of this
	 * new drawer to the given field.
	 * 
	 * @param field
	 *            The field.
	 * @return The new drawer.
	 * @throws InstantiationException
	 *             if this Class represents an abstract class, an interface, an
	 *             array class, a primitive type, or void; or if the class has
	 *             no nullary constructor; or if the instantiation fails for
	 *             some other reason.
	 * @throws IllegalAccessException
	 *             if the class or its nullary constructor is not accessible.
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws SecurityException 
	 * @throws IllegalArgumentException 
	 */
	public static FieldDrawer getDrawer(Field field)
			throws InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException {
		Class<? extends FieldDrawer> drawer = drawerMap.get(field.getClass());
		if (drawer == null) {
			throw new IllegalArgumentException("The given field has no drawer.");
		}
		FieldDrawer newDrawer = drawer.getConstructor(Field.class).newInstance(field);
//		FieldDrawer newDrawer = drawer.newInstance();
//		newDrawer.setField(field);
		return newDrawer;
	}
}

Davon abgeleitet gibt es (wie man an der Map sieht):
Java:
package org.ojim.client.gui.GameField.fielddrawer;

import java.awt.Graphics;

import org.ojim.logic.state.fields.Jail;

public class JailDrawer extends FieldDrawer {
	
	public JailDrawer(Jail field) {
		super(field);
	}

	@Override
	public void drawTo(Graphics g) {
		// TODO Auto-generated method stub

	}
}

Jetzt kommt es aber zu einem Fehler, wenn ich folgendes mache:
Java:
FieldDrawer d = FieldDrawer.getDrawer(new Jail());

Code:
java.lang.NoSuchMethodException: org.ojim.client.gui.GameField.fielddrawer.JailDrawer.<init>(org.ojim.logic.state.fields.Field)
	at java.lang.Class.getConstructor0(Class.java:2723)
	at java.lang.Class.getConstructor(Class.java:1674)
	at org.ojim.client.gui.GameField.fielddrawer.FieldDrawer.getDrawer(FieldDrawer.java:107)
	at org.ojim.Test.main(Test.java:49)
Anscheinend ignoriert er, dass ich eine Instanz vom Typ Jail übergebe. Ändere ich den Typ im Konstruktor zu „Field“ geht es wunderbar, aber dann möchte ich eigentlich verhindern. Geht das oder muss ich den Typ ändern?

MfG
Fabian
 

XHelp

Top Contributor
Dein Konstruktor erwartet ja
Code:
Jail
und du suchst nach einem Konstruktor mit
Code:
Field
 

xZise

Aktives Mitglied
Moin,
ich weiß, aber wie kann ich sagen, suche nach der Klasse die ich übergeben habe? Also nicht das die Information das es vom Typ „Jail“ ist, beim übergeben als Parameter verloren geht.

MfG
Fabian
 

Marco13

Top Contributor
Bin noch nicht ganz wach, aber ... es KANN sein, dass du dir alle Konstruktoren holen mußt, und bei allen schauen musst, ob sie nur einen Parameter haben, und dessen Klasse mit classA.isAssignableFrom(classB) zur übergebenen Klasse passt.
 

Paeddah

Mitglied
Moin!

Wie XHelp bereits erwähnte, erwartet der Konstruktor von
Code:
JailDrawer
Code:
Jail
als Parameter und nicht
Code:
Field
.

Mit dem ...

-- snip --
Java:
FieldDrawer newDrawer = null;
    Constructor<?>[] constructors = drawer.getConstructors();
    for (Constructor<?> constructor : constructors) {
      Class<?>[] parameterTypes = constructor.getParameterTypes();
      if (parameterTypes.length == 1 && Field.class.isAssignableFrom(parameterTypes[0])) {
        newDrawer = drawer.getConstructor(parameterTypes[0]).newInstance(field);
        break;
      }
    }
    return newDrawer;
-- snip --

.. funktionierts. Also so, wie Marco13 es vermutet hatte.

Grüße

Päddah
 

me.toString

Bekanntes Mitglied
Auch wenn ich erstmal keinen besseren Vorschlag habe, kommt mir die Lösung von Päddah nicht so ganz geeignet vor. Es scheint zu gehen (hab's jetzt nicht ausprobiert) ... aber das Problem wird sein, wenn das Programm später erweitert wird. Wenn z.B. eine weitere Drawer-Klasse mit einem neuen Parameter-Typ dazu kommt, muss die Methode jedes mal um den neuen Parameter-Typ erweitert werden - oder sehe ich das falsch?

@xZise: du hast geschrieben: Es gibt mehrere Klassen die alle (mehr oder weniger tief) von Field abgeleitet sind. Die möchte ich aber nicht bearbeiten.
Ist das denn ein MUSS (also das mit dem "nicht bearbeiten")?
 

Marco13

Top Contributor
Falls ich das richtig verstanden habe: Änderungen sind eben gerade nicht notwendig, wenn die neuen Parametertypen immer von Field erben.
 

Paeddah

Mitglied
... wenn das Programm später erweitert wird. Wenn z.B. eine weitere Drawer-Klasse mit einem neuen Parameter-Typ dazu kommt, muss die Methode jedes mal um den neuen Parameter-Typ erweitert werden ...

Ich hatte xZises Ausführung und Quellcode so verstanden, dass es jede neue Drawer-Klasse einen Konstruktor mit einem Parameter bereitstellen muss. Dieser Parameter muss eine von Field (indirekt) abgeleitete Klasse sein.

Sollte es natürlich so sein, dass hier auch beliebige Konstruktoren bedient werden sollen, so wäre der Ansatz sehr wartungsintensiv.
 

me.toString

Bekanntes Mitglied
Falls ich das richtig verstanden habe: Änderungen sind eben gerade nicht notwendig, wenn die neuen Parametertypen immer von Field erben.
Dann dürfte die Fehlermeldung ja nicht kommen ... denn dann wäre ja Jail von Field abgeleitet und alles wäre OK.

Wie wäre es denn mit einem Interface, welches von allen Parametertypen implementiert werden muss. z.B.
Java:
public interface FieldInterface {
   public FieldDrawer getDrawer();
}
Dieses interface muss von Field und Jail (und allen kommenden Parametertypen) implementiert werden. In der Klasse FieldDrawer würde dann in die Methode getDrawer so aussehen:
Java:
public static FieldDrawer getDrawer(FieldInterface field){
  return field.getDrawer();
}
Damit haben wir die Objekterzeugung an die entsprechende Fieldklasse, die sich damit eh besser auskennt, abgegeben (also Field erzeugt einen FieldDrawer, Jail erzeugt einen JailDrawer usw.) . Problem ist nur, wenn eine Drawer-Klasse keinen "eigenen Parametertyp" mitbringt und stattdessen ein "fremden Parametertyp" einfach nutzt.
 

Marco13

Top Contributor
Hm. Kann sein, dass (mindestens) einer von uns den jeweils anderen Falsch versteht. Ich hatte das so iterpretiert:
Code:
class Field {}
class SpecialField extends Field {}

class SpecialClass
{
    public SpecialClass(SpecialField f) {}
}

Beim Aufruf
[c]specialClass.getConstructor(Field.class).newInstance(field);[/c]
wird kein Konstruktor gefunden, weil es keinen Konstruktor gibt, das nur ein "Field" erwartet. Es gibt nur einen, der ein SpecialField erwartet. Deswegen braucht man einen Befehl, mit dem man einen (beliebigen) Konstruktor finden kann, der irgendein Objekt übergeben bekommt, das von Field erbt. (Dass das konkrete Objekt dann auch zu diesem Typ passt, muss man auch überprüfen, aber auch das sollte gehen, ohne den konkreten Typ zu kennen)
 

me.toString

Bekanntes Mitglied
Beim Aufruf
[c]specialClass.getConstructor(Field.class).newInstance(field);[/c]
Das Änderungs-Problem ist aber weiterhin vorhanden ... denn du brauchst ja ersteinmal eine Instanz der SpecialClass. Im ersten Post von xZise hatte er ja im static-Block jede vorhandene Field-Klasse mit der dazugehörigen Drawer-Klasse in eine Map gepackt. D.h. also, dass bei jeder Änderung der Code von FieldDrawer angepasst werden muss!
Würde man aber, wie bei meiner Idee, die Drawer-Objekt-Erzeugung auslagern in die SpecialField-Klasse, braucht alter Code nicht mehr geändert werden ... es muss lediglich eine spezielle Field- und eine entsprechende Drawer-Klasse, die die Vorgaben des Interfaces bzw. der abstracten FieldDrawer-Klasse erfüllen, hinzugefügt werden.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Klassen Klasse Dynamisch laden und Konstruktor aufrufen Allgemeine Java-Themen 1
berserkerdq2 Jemand einen Tipp wie man ein Javafx-Hintergrund "dynamisch" macht Allgemeine Java-Themen 3
E RMI FWH: RMI- Wie erstelle ich stubs dynamisch, bzw. unterdrücke eine Statisch-Warnung? Allgemeine Java-Themen 0
S Maven Jars dynamisch laden / Plugin-Struktur erstellen Allgemeine Java-Themen 14
T Statisch und dynamisch Allgemeine Java-Themen 1
MiMa Variableninhalte dynamisch abfragen Allgemeine Java-Themen 12
D Methode dynamisch aufrufen Allgemeine Java-Themen 2
S Externe Eclipse Projekte dynamisch einbinden Allgemeine Java-Themen 3
Thallius Externe .jar dynamisch einbinden Allgemeine Java-Themen 5
C Erste Schritte Baumstruktur (dynamisch) Allgemeine Java-Themen 9
F JTree: Nodes dynamisch anlegen via LinkedHashMap Allgemeine Java-Themen 2
B Reflection, invoke dynamisch befüllen Allgemeine Java-Themen 3
J rxtxserial.dll für 32 oder 64bit dynamisch einbinden Allgemeine Java-Themen 9
F Dynamisch ein Objekt einer bestimmten Subklasse erstellen Allgemeine Java-Themen 7
W Dateinamen dynamisch Parsen Allgemeine Java-Themen 12
T Classpath Klassen dynamisch erstellen Allgemeine Java-Themen 4
F Schlüsselworte Einstellungen dynamisch deserialisieren Allgemeine Java-Themen 5
S LaTeX Code in dynamisch erzeugten PDF's Allgemeine Java-Themen 8
hdi Ressourcen dynamisch zur Laufzeit laden Allgemeine Java-Themen 15
A Klassen dynamisch aus jar-datei laden Allgemeine Java-Themen 5
J instanceof vermeiden und stattdessen dynamisch binden Allgemeine Java-Themen 6
M Konstruktoraufruf dynamisch auswerten und SQL bauen Allgemeine Java-Themen 10
E Variable dynamisch ausgeben Allgemeine Java-Themen 5
Tandibur pattern dynamisch vorkompilieren Allgemeine Java-Themen 9
T Objekt dynamisch neu erstellen/ austauschen Allgemeine Java-Themen 9
T Dynamisch getypte Klasseninstanz? Allgemeine Java-Themen 6
H getText(); bei dynamisch generierten JTextFiled Allgemeine Java-Themen 2
F Wie erfahre ich dynamisch den namen eines aktuellen Objektes Allgemeine Java-Themen 2
S Asymmetrisches Array dynamisch erzeugen Allgemeine Java-Themen 4
T Objekte dynamisch über eine Methode erzeugen Allgemeine Java-Themen 10
R Object Dynamisch erzeugen (Reflection API) Allgemeine Java-Themen 22
P RTF dynamisch machen (IText, Swing) Allgemeine Java-Themen 4
B Listener dynamisch setzen Allgemeine Java-Themen 6
P Klasse Dynamisch laden und zurückgeben Allgemeine Java-Themen 17
P Array Dynamisch vergrößern Allgemeine Java-Themen 7
B objekt einer klasse dynamisch erzeugen Allgemeine Java-Themen 6
G Objekt dynamisch erstellen und Inhalte kopieren Allgemeine Java-Themen 6
C Dynamisch Objekte unterschiedlicher Typen erzeugen Allgemeine Java-Themen 6
D Klassen dynamisch laden Allgemeine Java-Themen 5
E Arrays -> dynamisch Allgemeine Java-Themen 21
K Methoden dynamisch erstellen Allgemeine Java-Themen 12
P Dynamisch casten - möglich? wie? Allgemeine Java-Themen 5
T Klassen dynamisch ausführen Allgemeine Java-Themen 3
N Graphische Oberfläche dynamisch erweitern möglich? Allgemeine Java-Themen 4
B Absolute Paf einer Klasse in dieser dynamisch auslesen? Allgemeine Java-Themen 5
K Klasse dynamisch casten Allgemeine Java-Themen 14
Reeny Dynamisch Klassen kompilieren Allgemeine Java-Themen 5
G JDO Dynamisch ? Allgemeine Java-Themen 2
H Objekte m. versch. Interf. dynamisch erzeugen Allgemeine Java-Themen 11
E Klasse dynamisch über main-Methode aufrufen Allgemeine Java-Themen 9
D Strings dynamisch füllen Allgemeine Java-Themen 5
A Dynamisch Attribute hinzufügen Allgemeine Java-Themen 3
B Parameter Konstruktor plus rechnen Allgemeine Java-Themen 6
M Konstruktor einer Methode Allgemeine Java-Themen 35
M Frage zum Konstruktor Allgemeine Java-Themen 2
B Klassen Objekt erzeugen und Konstruktor aufrufen - Welche Lösung ist besser? Allgemeine Java-Themen 2
D Konstruktor - jedes Objekt einzeln erzeugen - alternative? Allgemeine Java-Themen 8
J Konstruktor in JSP beim Kompilieren nicht gefunden Allgemeine Java-Themen 3
J Inner class + Leer-Konstruktor Allgemeine Java-Themen 1
P Threads Objekt im Konstruktor anders wie im Run()-Block Allgemeine Java-Themen 10
H Beim Konstruktor "this" Allgemeine Java-Themen 4
K Variablen Konstruktor, unendlich viele Allgemeine Java-Themen 3
T Konstruktor löst exception aus Allgemeine Java-Themen 7
C Klassen und Konstruktor Allgemeine Java-Themen 2
W Threads NullPointer: Konstruktor "zu langsam"? Allgemeine Java-Themen 3
L Klassen Konstruktor soll Objekt anderer Klasse erzeugen Allgemeine Java-Themen 2
DStrohma In abstrakter Klasse Konstruktor von Instanz implementieren Allgemeine Java-Themen 11
C Reflektions, Benutzer soll Konstruktor auswählen und Parameter übergeben können Allgemeine Java-Themen 5
S OOP this-Referenz als Konstruktor-Übergabe Allgemeine Java-Themen 8
ruutaiokwu NullPointerException auf member, die per konstruktor gesetzt wird (multithread-kontext) Allgemeine Java-Themen 2
ruutaiokwu auf priv. konstruktor von "aussen" zugreifen? Allgemeine Java-Themen 4
A Methoden laufen im Konstruktor, außerhalb allerdings nicht Allgemeine Java-Themen 2
E Array im Konstruktor übergeben Allgemeine Java-Themen 3
A Reflection Konstruktor Parameter Supertyp Allgemeine Java-Themen 2
J abstrakte Klassen, Konstanten und Konstruktor Allgemeine Java-Themen 9
E Finale Attribute und Konstruktor Allgemeine Java-Themen 3
S Konstruktor ermitteln Allgemeine Java-Themen 3
B Konstruktor wird nicht aufgerufen Allgemeine Java-Themen 4
T class.newinstance + try/catch-konstruktor Allgemeine Java-Themen 6
S Neue Instanz eines Objekts erzeugen - Konstruktor erhaelt Parameter. Allgemeine Java-Themen 5
B Konstruktor - Vererbungsproblem Allgemeine Java-Themen 2
S konstruktor vererben Allgemeine Java-Themen 5
B Problem mit Methodenaufruf in Konstruktor Allgemeine Java-Themen 6
D [SOLVED] Collection wird nicht richtig per Konstruktor übernommen Allgemeine Java-Themen 8
S Instanz in einer Klasse erstellen, und dem Konstruktor die eigene Klasse mitgeben Allgemeine Java-Themen 4
M Konstruktor / statischer Block Allgemeine Java-Themen 13
Ark Konstruktor per Reflection nicht bekannt Allgemeine Java-Themen 4
J Klasse auf Konstruktor oder Methode testen? Allgemeine Java-Themen 3
Junktyz Konstruktor Allgemeine Java-Themen 9
T Schleife im Konstruktor? Allgemeine Java-Themen 9
conan2 super-super-Konstruktor? Allgemeine Java-Themen 3
P static-Methode aus dem Konstruktor aufrufen Allgemeine Java-Themen 6
F Werte von Member-Variablen erst im Konstruktor setzen? Allgemeine Java-Themen 7
MQue zaehlen im Konstruktor Allgemeine Java-Themen 3
V Initialisierung nur im Konstruktor? Allgemeine Java-Themen 14
J Konstruktor-Aufruf nur aus einem bestimmten Package erlauben Allgemeine Java-Themen 5
T Konstruktor von Hashtable unter Java 5.0! Allgemeine Java-Themen 3
M Feld initialisieren, direkt oder Konstruktor Allgemeine Java-Themen 2
D super-Konstruktor ist nicht super ;) Allgemeine Java-Themen 6
A Objektmethode aus Konstruktor aufrufen? Allgemeine Java-Themen 14

Ähnliche Java Themen

Neue Themen


Oben