2016-07-29 7 views
10

Ich möchte einige Code wie folgt schreiben:Welche java.lang.Class-Methode generiert die richtige Eingabe für Class.forName()?

Object o = ...; 
String oTypeName = o.getClass().getName(); 

//on the other side of the wire: 

Class<?> oClass = Class.forName(oTypeName); 
Object oAgain = oClass.newInstance(); 

Allerdings ist es aus dem javadoc nicht klar, welche Methode ich oTypeName initialisieren verwenden soll, dh welche Methode die erwartete Eingang Class.forName() produzieren:

  • : "Gibt den kanonischen Namen der zugrunde liegenden Klasse gemäß der Java-Sprachspezifikation zurück. Gibt null zurück, wenn die zugrunde liegende Klasse keinen kanonischen Namen hat (dh wenn es sich um eine lokale oder anonyme Klasse oder ein Array handelt) Typ hat keinen kanonischen Namen). "
  • getName(): "Gibt den Namen der Entität (Klasse, Schnittstelle, Array-Klasse, primitiver Typ oder void), die von diesem Klassenobjekt dargestellt wird, als String zurück. Wenn dieses Klassenobjekt einen Referenztyp darstellt, der kein Array-Typ ist dann wird der binäre Name der Klasse zurückgegeben, wie von der Java ™ -Sprachspezifikation spezifiziert. "
  • getTypeName(): "Geben Sie eine informative Zeichenfolge für den Namen dieses Typs zurück."

Es ist ziemlich offensichtlich, dass ich nicht wollen, entweder von diesen:

  • getSimpleName(): „Gibt den einfachen Namen der zugrundeliegenden Klasse wie im Quellcode gegeben“
  • toString(): „Die Stringdarstellung wird die Zeichenfolge‚Klasse‘oder‚Schnittstelle‘, gefolgt von einem Leerzeichen und dann durch die vollständig qualifizierten Namen der Klasse in dem Format zurückgegeben von getName“

I don erwarte dies nicht für primitive Typen. Es ist in Ordnung, wenn es für Arrays nicht funktioniert. Die Hauptsache, um die ich besorgt bin, sind verschachtelte Klassen und Foo.Bar vs. Foo$Bar.

+1

Ich meine verschachtelt; Frage aktualisiert –

Antwort

8

Die definitive Antwort ist getName(). Obwohl etwas versteckt, dies im Javadoc- der Überlastung der forName(className, initialize, loader) angegeben ist:

der vollständig qualifizierte Name für eine Klasse oder eine Schnittstelle (im gleichen Format zurückgegeben durch getName) Dieses Verfahren versucht zu lokalisieren Gegeben, laden und verknüpfen Sie die Klasse oder Schnittstelle.

und es ist auch angegeben, dass forName(className) Aufruf entspricht diese Überlastung zu nennen, mit Standardwerten:

diese Methode aufgerufen ist äquivalent zu:

Class.forName(className, true, currentLoader) 

wo currentLoader bezeichnet die definierende Klassenlader der aktuellen Klasse.


Hier ist ein Beispielcode zeigt, dass es für verschachtelte Klassen arbeitet, lokale Klassen, anonyme Klasse, primitiven oder Objekt-Arrays. Es funktioniert nicht für Primitive, da Class.forName nicht mit primitiven Klassen arbeitet.

public class Main { 
    public static void main(String... args) throws ClassNotFoundException { 
     class LocalClass {} 

     System.out.println(Class.forName(name(StaticNestedClass.class))); //static nested class 
     System.out.println(Class.forName(name(InnerClass.class))); // inner class 
     System.out.println(Class.forName(name(Integer[].class))); // object array 
     System.out.println(Class.forName(name(int[].class))); // primitive array 
     System.out.println(Class.forName(name(List.class))); // interface 
     System.out.println(Class.forName(name(LocalClass.class))); // local class 
     System.out.println(Class.forName(name(new Object(){}.getClass()))); // anonymous class 
    } 

    private static String name(Class<?> clazz) { 
     return clazz.getName(); 
    } 

    public static class StaticNestedClass {} 
    public class InnerClass {} 
} 
+0

Und umgekehrt, wird weder' getTypeName' noch 'getCanonicalName' arbeiten zum Beispiel für primitive Arrays. Sowohl 'Class.forName (int []. Class.getTypeName())' als auch 'Class.forName (int []. Class.getCanonicalName())' werden 'ClassNotFoundException', aber' Class.forName (int []. class.getName()) 'wird nicht. – palimpsestor

+0

Vielen Dank, dass Sie diese begrabene Javadoc-Referenz gefunden haben - das ist das offizielle Wort, nach dem ich gesucht habe und das ich nicht finden konnte! –

2

Es sieht aus wie entweder getName() oder getTypeName() Werke, zumindest im einfachen Fall:

public final class ForNameTest{ 

    public static void main(String[] args) throws Exception{ 
     Object o = new Foo(); 
     System.out.println("class is: " + o.getClass()); 

     for(String getterMethodName : Arrays.asList("getName", "getTypeName", "getCanonicalName")){ 
      Method m = Class.class.getMethod(getterMethodName); 
      String oTypeName = m.invoke(o.getClass()).toString(); 
      System.out.println(getterMethodName + " yields " + oTypeName); 
      try{ 
       Class<?> oType = Class.forName(oTypeName); 
       Object oAgain = oType.newInstance(); 
       System.out.println(" ... and it works: " + oAgain); 
      } catch (Exception e){ 
       System.err.println(" ... and it fails: " + e); 
      } 
     } 
    } 

    public static class Foo{} 
} 

Der Ausgang erzeugt ist:

class is: class ForNameTest$Foo 
getName yields ForNameTest$Foo 
... and it works: [email protected] 
getTypeName yields ForNameTest$Foo 
... and it works: [email protected] 
getCanonicalName yields ForNameTest.Foo 
... and it fails: java.lang.ClassNotFoundException: ForNameTest.Foo 
+1

Genau dahin kam ich auch. Wow, du denkst du weißt etwas (ich war mir sicher ** es war 'Foo.Bar') und dann gehst du es zu testen und, nun .... –

1

Ich benutze getCanonicalName() Interne Objekte immer (wie Ihre Foo $ Bar Wenn statische public vs Inline-Implementierung) kann auch konstruiert werden.

Auch Sie können es mit Primitiven arbeiten .. 'int.class' zum Beispiel existiert. Allerdings müssen Sie wahrscheinlich die primitiven Klassen überprüfen und die Objektinstanz (Integer vs int) erstellen und dann den Accessor wie intValue() aufrufen. Aus diesem Grund benutze ich viele Objektinstanzen gegen primitive, aber das ist nur meine Präferenz, denke ich.

-1
Object oAgain = oClass.newInstance(); 

[EDIT] Unabhängig davon, welche Methode (getName(), getCanonicalName(), etc ..) Sie kann nicht Verwendung newInstance() -Methode ein Objekt für eine nicht statische innere Klasse zu erstellen

Wenn Sie ein Objekt mithilfe von newInstance() erstellen, ist es zwingend erforderlich, dass die zugrunde liegende Klasse einen Konstruktor "no arg" enthält. Auch wenn wir ausdrücklich ein kein Argument Konstruktor einfügen, wird der Compiler es zu einem Konstruktor mit einigen Argumenten konvertieren (nur im Falle einer nicht statischen inneren Klasse)

[END EDIT]

Unter dem Link für kurz ist Code, den ich gefunden habe. Es zeigt die obige Erklärung.

http://thecodersbreakfast.net/index.php?post/2011/09/26/Inner-classes-and-the-myth-of-the-default-constructor

+0

Es ist nicht notwendig, dass der Konstruktor no-arg tatsächlich der Standardkonstruktor ist. –

+1

Bearbeitet die Antwort, was ich meine ist NewInstance() -Methode erwartet, dass ein Konstruktor keine Argumente in Ihrer Klasse vorhanden ist. –