2010-02-06 12 views
8

Ich mag würde, warum die folgenden verstehen, funktioniert nicht:Dynamische Instanz Schöpfung ohne Generika

public class HelloClass { 

    private class MyClass 
    { 
     public MyClass() 
     { 
      System.out.println ("Oh heck this is me!"); 
     } 
    } 

    public Object newInstance (Object o) 
    { 
     try { 
      // java.lang.InstantiationException here 
      return o.getClass().newInstance();   
     } catch (Exception e) { 
      e.printStackTrace(System.out); 
      return null; 
     } 
    } 

    public void run() 
    { 
     MyClass m = new MyClass(); 
     Object o = newInstance(m); 
    } 

    public static void main(String[] args) 
    { 
     HelloClass hd = new HelloClass(); 
     hd.run(); 
    } 
} 

Ich weiß, der richtige Weg, dies die newInstance Argument über Deklaration der Klasse <T>, zu erreichen, sondern würde Ich mag es zu verstehen, warum es nicht so wie oben gemacht werden kann.

UPD: Hier ist die Ausnahme, die ich bin immer:

java.lang.InstantiationException: HelloClass$MyClass 
    at java.lang.Class.newInstance0(Class.java:340) 
    at java.lang.Class.newInstance(Class.java:308) 
    at HelloClass.newInstance(HelloClass.java:14) 
    at HelloClass.run(HelloClass.java:24) 
    at HelloClass.main(HelloClass.java:30) 
+0

Welche Klasse versuchen Sie zu instanziiert? Wenn es sich um eine abstrakte Klasse oder eine Schnittstelle handelt, funktioniert dies nicht und Sie erhalten eine InstantiationException. Vielleicht wäre es hilfreich, den Stack-Trace der Exception zu verwenden. – JasCav

+0

Ich versuche, MyClass instanziieren, dachte, es ist ziemlich offensichtlich, wie ich NewInstance (m) aufrufen, wobei m eine Instanz von MyClass ist;). Die Ausnahme zum ursprünglichen Post wurde hinzugefügt. – azerole

+0

Warum die Erwähnung von Generika im Titel? Was haben sie mit diesem Problem zu tun? – skaffman

Antwort

6

Konstruktoren für innere Klassen haben ein verborgenes erstes Argument, das Sie angeben müssen, wenn Sie Reflektion verwenden. Übergeben Sie eine Instanz der äußeren Klasse.

Statt

return o.getClass().newInstance(); 

Verwendung:

return o.getClass().getConstructor(getClass()).newInstance(this); 
+0

Und als ein bestimmter Konstruktor nach Position anzugeben ist nicht sehr robust Ich denke, ich verstehe jetzt, warum FindBugs beschwert sich in solchen Fällen, dass die Klasse eine * statische * innere Klasse sein sollte. Interessant! –

+0

Vielen Dank. Jetzt sehe ich. – azerole

+0

Oh ja, so ist es ganz nett. –

1

Das Problem scheint zu sein, dass es sich um eine nicht-statische Member-Klasse ist, wie es funktioniert, wenn sowohl Sie erklären MyClass als statisch, und wenn Sie machen es ist eine erstklassige Klasse. Nicht ganz sicher warum.

1

Sehr gute Frage!

Dies liegt daran, dass die innere Klasse ein implizites Argument in jedem Konstruktor hat - seine äußere Klasse. Daher hat es keinen Standardkonstruktor.

Um eine Instanz davon zu erhalten, müssen Sie sie instanziieren, indem Sie die äußere Klasse als Argument übergeben.

Constructor constructor = o.getClass().getConstructor(HelloClass.class); 
return constructor.newInstance(this); 
+0

Das ist, was ich auch dachte, aber es scheint, dass 'newInstance()' keine Version hat, die ein umschließendes Objekt nimmt, müssen Sie 'Konstruktor' Objekte verwenden. – skaffman

+0

das habe ich gerade auch gesehen :) behoben. – Bozho

+0

Angenommen, Sie haben 'HelloClass.class' gemeint, funktioniert das nicht für mich, sondern löst eine' IllegalArgumentException' aus: * falsche Anzahl von Argumenten *. –

0

Die Methode newInstance in einem Klassenobjekt funktioniert nur für eine konkrete Klasse mit einem Konstruktor ohne Argumente.

Wenn Sie MyClass als statisch ändern, würde es sich qualifizieren und der Code würde funktionieren. So wie es ist, hat es einen impliziten Konstruktor mit dem äußeren Objekt als Parameter und keinen Konstruktor ohne Arg.

Sie könnten Ihre eigene newInstance Methode funktioniert durch den Konstruktor der newInstance Methode:

public Object newInstance (Object o) 
{ 
    try { 
     final Constructor<? extends Object> constructor = 
        o.getClass().getConstructor(this.getClass()); 
     return constructor.newInstance(this); 
    } catch (Exception e) { 
     e.printStackTrace(System.out); 
     return null; 
    } 
} 
+0

Erst nachdem ich das gepostet habe, habe ich aktualisiert und gesehen, dass andere im Wesentlichen die gleiche Antwort gegeben haben. Ich werde es trotzdem verlassen, aber fühle mich ein bisschen albern! –