reflection in inner classes

Mewel

Aktives Mitglied
Moin,

um mein Problem zu verdeutlichen habe ich mal ein kleines Beispiel geschrieben.

Java:
/** Hauptklasse um eine Hashtable mit verschiedenen Term-Klassen zu verwalten. */
public class Manager {

    private static Map<String, Class<? extends Term>> termList;

    static {
        termList = new Hashtable<String, Class<? extends Term>>();
        try {
            registerTerm(A.class);
        } catch(Exception exc) {
            exc.printStackTrace();
        }
    }

    public static void registerTerm(Class<? extends Term> termClass) throws NoSuchMethodException, InvocationTargetException,
            IllegalAccessException, InstantiationException {
        // seltsam aber ok, auch wenn ich es lieber mit newInstance machen würde
        Constructor<? extends Term> c = termClass.getConstructor(Manager.class);

        // find ich nicht schön das ich hier ne neue instanz von Manager anlegen muss
        termList.put(c.newInstance(new Manager()).getSomething(), termClass);
    }

    public abstract class Term {
        public abstract String getSomething();
    }

    private class A extends Term {
        // benötigt zwingend einen konstruktur, auch wenn ich ihn nicht will
        public A() {
        }

        @Override
        public String getSomething() {
            return "B";
        }
    }
}
Java:
/** Ein weiterer Term der sich beim Manager registrieren soll. */
public class B extends Term {

    public B() {
        // auch sehr komisches konstrukt, was anscheinend auch nicht
        // funktioniert
        new Manager().super();
    }

    @Override
    public String getSomething() {
        return "B";
    }

    public static void main(String args[]) throws Exception {
        Manager.registerTerm(B.class);
        
    }
}

Das erste offensichtliche Problem ist, das ich immer eine NoSuchMethodException für die Klasse B bekomme (Konstruktor haut nicht). Keine Ahnung woran das liegt oder wie ich das sonst schreiben soll.
Ein eher kosmetisches Problem ist, das ich immer eine Instanz des Managers benötige. Ist in meinen Augen aber gerade nicht der Sinn einer statischen Verwaltung von Class-Objekten.

Bin über jede Hilfe dankbar,
Mewel
 
Das erste offensichtliche Problem ist, das ich immer eine NoSuchMethodException für die Klasse B bekomme (Konstruktor haut nicht). Keine Ahnung woran das liegt oder wie ich das sonst schreiben soll.
Die Klasse B hat keinen Konstruktor, der als Parameter ein Manager-Objekt fordert. Also kann er auch nicht gefunden bzw. aufgerufen werden.
 
die Klasse A auch nicht, das wird bei inneren Klassen dazugemogelt,
interessant, kannte ich noch nicht

> // benötigt zwingend einen konstruktur, auch wenn ich ihn nicht will

kann ich nicht bestätigen, bei mir gehts auch ohne, welche Fehlermeldung?

-----

ein neues Manager-Objekt brauchst du in A nicht, da kannst du überall, im Konstruktor und sonstwo,
Manager.this.xy();
schreiben

edit:
also das wird dann das Manager-Objekt sein, welches im Konstruktor übergeben wurde,
generell solltest du nur eines erstellen und das überall übergeben, ja,
das ist eine allgemeine Objektaufgabe, lege im einfachen Fall z.B. eines in einer statischen Variablen ab,
oder mache alles nicht-statisch in einem Manager-Objekt, dann this im Konstruktor übergeben

-------

HashMap statt Hashtable

----

bei der Klasse B genauso wie in A wenn sie innerhalb von Manager definiert ist,
außerhalb ist anscheinend überhaupt keine Klassendefinition möglich, die von Term innerhalb von Manager erbt

es sei denn die inneren Klassen werden alle als 'static' deklariert,
dann verschwindet die magische Verknüpfung mit dem umgebenden Manager-Objekt
 
Zuletzt bearbeitet von einem Moderator:
Also wenn ich von A den Konstruktor wegmache bekomme ich:
java.lang.NoSuchMethodException: org.mycore.common.Manager$A.<init>(org.mycore.common.Manager)
at org.mycore.common.Manager.registerTerm(Manager.java:23)
----

Wenn ich dich richtig verstehe sollte ich in der Manager Klasse zusätzlich noch eine eigene Instanz verwalten? Quasi wie bei nem Singleton nur ohne privaten Konstruktor?

----

warum HashMap statt Hashtable?

----
Das ist genau der Punkt wo mein Problem liegt 🙂. Klassen außerhalb der Manager-Klasse von Term ableiten zu lassen und sie trotzdem hinzufügen zu können. Das static Schlüsselwort bei Klassen ist auf jeden Fall interessant. Ich werde damit mal ein wenig rumspielen und schauen ob es mir was bringt.

Auf jeden Fall danke für deine Antwort
 
> Also wenn ich von A den Konstruktor wegmache bekomme ich: [Exception]

hast du noch einen zweiten Konstruktor mit Parametern definiert? dann bekomme ich auch die Exception wenn der DefaultKonstruktor fehlt,
wie auch immer, schreib ihn eben hin

> sollte ich in der Manager Klasse zusätzlich noch eine eigene Instanz verwalten? Quasi wie bei nem Singleton

was und wie du machst ist mir eher egal, nur zwei Aussagen:
1. in A brauchst du kein neues Manager-Objekt erstellen (wobei du das im ersten Post hauptsächlich in B gemacht hast),
Manager.this ist das im Reflection-Konstruktor übergebene Objekt
2. allen per registerTerm registierten Terms soll doch sicher dasselbe Manager-Objekt übergeben werden, mache das, wie auch immer (z.B. auch Manager als Parameter von registerTerm() )

> warum HashMap statt Hashtable?

das gebietet allein schon der saubere Name, HashMap ist eine Map,
bei Bedarf auch beide Begriffe zusammen in google eintippen

> Das static Schlüsselwort bei Klassen ist auf jeden Fall interessant.

genausogut könntest du dann Term außerhalb definieren, damit ist also nicht viel gewonnen,
außer eine neue .java-Datei eingespart (nur eine äußere public-Klasse pro Java-Datei)
 
Ok, das static bringt in dem Zusammenhang wirklich nichts.

Ich war wohl bei der Namenswahl der Klassen etwas unglücklich. Die Manager-Klasse ist eigentlich kein Manager 🙂. Es können schon mehrere Instanzen der Klasse existieren. Ist aber auch nicht so schlimm, da die Zugriffe innerhalb alle wunderbar funktionieren.

Das einzige Problem ist wie gesagt die Klasse B und deren Konstruktor.

Trotzdem nochmals vielen Dank

€ So funktionierts:
Java:
public class B extends Term {

    public B(Manager m) {
        m.super();
    }

    @Override
    public String getSomething() {
        return "B";
    }

    public static void main(String args[]) throws Exception {
        Manager.registerTerm(B.class);
        
    }
}
 
verrückt was es alles gibt, kompiliert bei mir auch,
hast du das nur durch Ausprobieren gefunden oder doch irgendwo in einer Anleitung?
 
Hab mir im debug modus mit getConstructors die Konstruktoren angezeigt. Und da stand halt der Manager drin. Also hab ich mir gedacht pack ich den einfach mal als Konstruktor rein und da gings 🙂.
 

Zurück
Oben