[Java] wie funktioniert Class.forName() denn?

Ich habe verschiedene Klassen Cmd_a, Cmd_b, Cmd_c, Cmd_x …
Nun möchte ich je nachdem was der String „command“ enthält, die entsprechende Klasse im darauffolgenden Codeteil verwenden.

Mein Code ist folgender:

Class handler = Class.forName("Cmd\_" + command);
Vector vec = splitParams(params, handler.pcount);

Ich kriege hierbei ein Problem, indem er mir sagt „Das Feld mit dem Namen pcount für den Typ mit dem Namen java.lang.Class ist nicht definiert“. Das stimmt ja auch, das pcount ist schliesslich in der Klasse Cmd_irgendwas definiert.

Wie kann ich das hinkriegen, dass er handler nicht als java.lang.Class behandelt, sondern eben als den Typen wie der Klassenname sagt.

Die Klassen haben übrigens nur static fields, also ich will keine Instanzen davon anlegen.

MfG Bruno Haller

Hi,

Wenn ich das richtig weiss, dann musst Du die erhaltene Instanz bei Verwendung noch casten!
Hier ein Auszug aus dem Buch GoToJava 2, das macht so ziemlich das, was du willst:

001 /\* Listing3101.java \*/
002 
003 import java.io.\*;
004 
005 interface HelloMeth
006 {
007 public void hello();
008 }
009 
010 class CA
011 implements HelloMeth
012 {
013 public void hello()
014 {
015 System.out.println("hello CA");
016 }
017 }
018 
019 class CB
020 implements HelloMeth
021 {
022 public void hello()
023 {
024 System.out.println("hello CB");
025 }
026 }
027 
028 class CC
029 {
030 public void hello()
031 {
032 System.out.println("hello CC");
033 }
034 }
035 
036 class CD
037 {
038 public void hallo()
039 {
040 System.out.println("hallo CD");
041 }
042 }
043 
044 public class Listing3101
045 {
046 public static void main(String[] args)
047 {
048 String buf = "";
049 BufferedReader in = new BufferedReader(
050 new InputStreamReader(
051 new DataInputStream(System.in)));
052 while (true) {
053 try {
054 System.out.print("Klassenname oder ende eingeben: ");
055 buf = in.readLine();
056 if (buf.equals("ende")) {
057 break;
058 }
059 Class c = Class.forName(buf);
060 Object o = c.newInstance();
061 ((HelloMeth)o).hello();
062 } catch (IOException e) {
063 System.out.println(e.toString());
064 } catch (ClassNotFoundException e) {
065 System.out.println("Klasse nicht gefunden");
066 } catch (ClassCastException e) {
067 System.out.println(e.toString());
068 } catch (InstantiationException e) {
069 System.out.println(e.toString());
070 } catch (IllegalAccessException e) {
071 System.out.println(e.toString());
072 }
073 }
074 }
075 }

Gruss,
Max

Wenn ich das richtig weiss, dann musst Du die erhaltene
Instanz bei Verwendung noch casten!

Danke für den Auszug, die Idee mit dem Cast hatte ich auch schon aber dann hatte ich das Problem, dass ich ja quasi den Typ wissen müsste den ich casten will, aber mit einer Superklass bzw. einem Interface wie in deinem Beispiel könnte dies gehen.

Jetzt frag ich mich nur noch wie ich drumrum komme um dieses newInstance(), ich will ja nur statische Methoden aufrufen und gar keine Objekte anlegen.

MfG Bruno

Moin,

Ich habe verschiedene Klassen Cmd_a, Cmd_b, Cmd_c, Cmd_x …

Schonmal schlecht.

Class handler = Class.forName(„Cmd_“ + command);
Vector vec = splitParams(params, handler.pcount);

Ich kriege hierbei ein Problem, indem er mir sagt „Das Feld
mit dem Namen pcount für den Typ mit dem Namen java.lang.Class
ist nicht definiert“. Das stimmt ja auch, das pcount ist
schliesslich in der Klasse Cmd_irgendwas definiert.

Bei Dir ist ‚handler‘ von der Klasse ‚Class‘, also hat javac ganz recht, die zweite Operation abzuweisen. Was Du im Sinn hattest, ist ein Objekt der Klasse ‚Class.forName(„Cmd_“ + command)‘, das Du mit ‚(Cmd) handler.newInstance()‘ erzeugen kannst.
‚Cmd‘ sollte übrigens die Superklasse von Cmd_a … Cmd_x sein, wenn Du es so machen willst.

Die Klassen haben übrigens nur static fields, also ich will
keine Instanzen davon anlegen.

Dann würde ich versuchen, Dein doch eher kompliziertes Gebilde durch etwas anderes ersetzen, entweder

  1. Durch ein einziges Singleton, das Du durch eine Methode ‚pcount(a)‘ … ‚pcount(x)‘ benutzt,
    oder
  2. Durch eine Abstrakte Fabrik, die Dir abhängig von ‚a‘ … ‚x‘ ein Objekt ‚handler‘ liefert.
    Wenn Du mehr darüber wissen willst, empfehle ich ‚Design Patterns‘ (0201633612) oder Du fragst nochmal nach.

Thorsten

Moin,

Jetzt frag ich mich nur noch wie ich drumrum komme um dieses
newInstance(), ich will ja nur statische Methoden aufrufen und
gar keine Objekte anlegen.

Im Beispiel greifst Du nur auf Felder zu. Wenn Du nur auf statische Methoden zugreifen willst, kannst Du ein Singleton benutzen. Das ist im Pronzip eine Klasse mit privatem Konstruktor, die Du mit einer öffentlichen Methode um eine Instanz bittest.
Wenn Du es genauer wissen willst, solltest Du nochmal beschreiben, was genau Du machen willst.

Thorsten

Dann würde ich versuchen, Dein doch eher kompliziertes Gebilde
durch etwas anderes ersetzen, entweder

  1. Durch ein einziges Singleton, das Du durch eine Methode
    ‚pcount(a)‘ … ‚pcount(x)‘ benutzt,
    oder
  2. Durch eine Abstrakte Fabrik, die Dir abhängig von ‚a‘ …
    ‚x‘ ein Objekt ‚handler‘ liefert.
    Wenn Du mehr darüber wissen willst, empfehle ich ‚Design
    Patterns‘ (0201633612) oder Du fragst nochmal nach.

Ja, ich will mehr darüber wissen. Singleton hab ich jetzt noch gar nie gehört, Factory schon, aber ich kenn mich damit absolut gar nicht aus.

Muss ich pcount, als Methode benutzen? Das is eigentlich einfach ein Integer.

Ja ich habe die Klasse Cmd als Superklasse von Cmd_a … Cmd-x definiert, weil ansonsten kann ich überhaupt nicht casten, aber du hast recht, ich will eigentlich aus dem Class.forName() keine Class, sondern einen Typen eben dieser Klasse erhalten.

MfG Bruno

Moin,

Wenn Du mehr darüber wissen willst, empfehle ich ‚Design
Patterns‘ (0201633612) oder Du fragst nochmal nach.

Ja, ich will mehr darüber wissen.

Schön. Das Buch kann ich sehr empfehlen, ansonsten müßte ich auch noch mehr wissen, und zwar über Dein Problem.

Muss ich pcount, als Methode benutzen? Das is eigentlich
einfach ein Integer.

Statisch? Final? Wieviele dieser Werte gibt es?

Ja ich habe die Klasse Cmd als Superklasse von Cmd_a … Cmd-x
definiert, weil ansonsten kann ich überhaupt nicht casten,
aber du hast recht, ich will eigentlich aus dem
Class.forName() keine Class, sondern einen Typen eben dieser
Klasse erhalten.

Eine Klasse ist ein Typ, genau wie ein Interface oder ein primitiver Typ. Du willst eine Instanz haben.

Thorsten

Statisch? Final? Wieviele dieser Werte gibt es?

ja, statisch und vordefiniert.
Also da gibt es z.B. ein Feld „pcount“ mit Wert 5 oder so, das sagt meinem Code dann, dass ich bei diesem Kommando 5 Parameter erwarte.
Wenn ich wüsste was für ein Kommando es ist würde ich einfach beim Funktionsaufruf der den Wert benötigt, machen:

tudies(Cmd_x.pcount);

aber das weiss ich eben nicht, wenn z.b. Cmd_y nur 3 Parameter braucht, dann will ich an die Funktion tudies() eine 3 übergeben und die steht in Cmd_y.pcount.

Verstehst du es nun?

SÄMTLICHE Felder und Methoden sind in all den Klassen vorhanden und ALLE sind statisch, da ich recht viel auf Sie zugreifen werde will ich auch verhindern, dass sie instanziiert werden, obwohl dies natürlich rein theoretisch möglich wär, aber keinen Sinn macht.

MfG Bruno

Moin,

Statisch? Final? Wieviele dieser Werte gibt es?

ja, statisch und vordefiniert.

Warum brauchst Du dann verschiedene Klassen? Warum reicht nicht eine Utility-Klasse?

Verstehst du es nun?

Nein. Das klingt nach einem Vektor von Argumenten.
Gib mir mal ein konkretes Beispiel, keines mit tuDies() und EineKlasse. Schildere Dein Problem, nicht die Probleme, die Du mit Deiner Lösung hast.

SÄMTLICHE Felder und Methoden sind in all den Klassen
vorhanden und ALLE sind statisch, da ich recht viel auf Sie
zugreifen werde will ich auch verhindern, dass sie
instanziiert werden, obwohl dies natürlich rein theoretisch
möglich wär, aber keinen Sinn macht.

Die Laufzeitüberlegungen mal außen vor, ist es auch gutes Design, einen statischen Wert in der Klasse zu lassen.

Thorsten

Ich weiss nicht mehr wie ich es noch genauer erklären soll.

Der user gibt ein Kommando ein und dann gibt es zu jedem bekannten Kommando eine Klasse Cmd_irgendwas, wo z.b. drinsteht wieviel Parameter erwartet werden und was eigentlich überhaupt geschehen soll bei dem Kommando, also z.b. schreibe „xyz auf den Bildschirm“.

Bisher hatte ich eine Lösung
if (kommando == soundso) dann mache dies und das
ich will aber jetzt lieber:

commandoklasse = soundso;

und dann fuehre ich Methoden in der Klasse aus die alle gemeinsam haben, z.b. execute() oder wie man das auch immer nennen will.

MfG Bruno

Moin,

Der user gibt ein Kommando ein und dann gibt es zu jedem
bekannten Kommando eine Klasse Cmd_irgendwas, wo z.b.
drinsteht wieviel Parameter erwartet werden und was eigentlich
überhaupt geschehen soll bei dem Kommando, also z.b. schreibe
„xyz auf den Bildschirm“.

OK, dafür gibt es auch ein Muster. Du solltest Dir das Buch kaufen.
Wie wird das Kommando ausgelöst? Durch ein Menü zB.? Dann enthält das Menü ein Objekt des Typs ‚Command‘, dessen Methode execute() ausgeführt wird. die Zuweisung Benutzeraktion->Kommando nimmst Du vor, indem Du das Kommando-Objekt dem passenden Menüpunkt zuweist.
In Java wäre ‚Command‘ ein Interface.

Thorsten

Wie wird das Kommando ausgelöst? Durch ein Menü zB.?

Nein, der User hat eine Eingabezeile, vergleichbar von mir aus einer Shell, daraus lese ich zeilenweise Strings aus und parse sie nach dem Kommando vorne dran.
In pcoutn steht dann z.b. wieviel Parameter dieses Kommando braucht und wenn der Wert nicht übereinstimmt hau ich ne Fehlermeldung zurück.

Bruno

Moin,

Wie wird das Kommando ausgelöst? Durch ein Menü zB.?

Nein, der User hat eine Eingabezeile, vergleichbar von mir aus
einer Shell, daraus lese ich zeilenweise Strings aus und parse
sie nach dem Kommando vorne dran.
In pcoutn steht dann z.b. wieviel Parameter dieses Kommando
braucht und wenn der Wert nicht übereinstimmt hau ich ne
Fehlermeldung zurück.

OK, da paßt das muster nicht mehr.
So ganz spontan würde ich sagen:

public interface Command
{
 public void execute(String cmdString)
 throws IllegalArgumentException;
}

(Sinngeäß, ich weiß jetzt nicht, ob man in einem Interface einen Throw deklarieren kann.)
Dann rufst Du das jeweilige Command auf.
Wie man das feststellt? Wieder so ganz spontan würde ich einen Hash wählen, key = Kommando, also der String, value = Command-Objekt.

Thorsten

Wie man das feststellt? Wieder so ganz spontan würde ich einen
Hash wählen, key = Kommando, also der String, value =
Command-Objekt.

Ok, das wäre eine Möglichkeit die ich auch ins Auge gefasst habe, ich könnte jede Klasse genau einmal instanziieren und diese sind die ganze Zeit vorhanden. Das würde mich zwar nicht ganz vor einem sinnlosen Anlegen eines Objektes, dass keine Instanz-Methoden oder Felder hat schützen, aber wäre praktikabel.

Wenn ich nix besseres finde, werd ichs wohl so machen.

MfG Bruno

Sorry, aber da hab’ ich keine Ahnung… aber vielleicht kann ja ein anderer helfen…

Gruss, Max

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Moin,

Ok, das wäre eine Möglichkeit die ich auch ins Auge gefasst
habe, ich könnte jede Klasse genau einmal instanziieren und
diese sind die ganze Zeit vorhanden. Das würde mich zwar nicht
ganz vor einem sinnlosen Anlegen eines Objektes, dass keine
Instanz-Methoden oder Felder hat schützen, aber wäre
praktikabel.

Du könntest auch die Klasse speichern, aber ich she keinen echten Gewinn darin.
Abgesehen davon: Aus OO-Sicht handelt es sich sehr wohl um Objekte; denkbar ist zB., daß ein zweiter Benutzer den gleichen Befehl ausführen will.

Thorsten

Abgesehen davon: Aus OO-Sicht handelt es sich sehr wohl um
Objekte; denkbar ist zB., daß ein zweiter Benutzer den
gleichen Befehl ausführen will.

Damit rechne ich sogar, evtl. sogar gleichzeitig, aber das sollte kein Problem mit den statischen Methoden geben. Wegen der Vielzahl der Eingaben will ich auch ein ständiges erstellen von Objekten verhindern, weil es gar nicht nötig ist. Die Klasse dient mir eher als Sammlung von Informationen zu einem Befehl

Moin,

Abgesehen davon: Aus OO-Sicht handelt es sich sehr wohl um
Objekte; denkbar ist zB., daß ein zweiter Benutzer den
gleichen Befehl ausführen will.

Damit rechne ich sogar, evtl. sogar gleichzeitig, aber das
sollte kein Problem mit den statischen Methoden geben.

Es geht mir hier nicht so sehr um die Implementierung, sondern um das Design. Ich weiß ja nicht, worum es geht, aber ich kann mir sehr gut vorstellen, daß ein Kommando auch einen Zustand haben muß. Wenn jedes Kommando ein Objekt ist, fällt das nicht schwer.

Thorsten