2016-07-29 8 views
10

私はこのようないくつかのコードを記述したいと思います:どのjava.lang.Classメソッドが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(); 

しかし、この方法はClass.forName()に期待される入力が生成されますどのすなわち、私はoTypeNameを初期化するために使用すべきメソッドのjavadocから明らかではありません

  • getCanonicalName():Java言語仕様で定義されているように、基になるクラスの正式名を返します。基底クラスが正規名を持たない場合(つまり、ローカルクラスまたは匿名クラスの場合、またはコンポーネント型には正式な名前はありません)。 "
  • getName(): "このClassオブジェクトが表すエンティティ(クラス、インタフェース、配列クラス、プリミティブ型、またはvoid)の名前をStringとして返します。このクラスオブジェクトが配列型ではない参照型を表す場合「Java™言語仕様」で指定されているように、クラスのバイナリ名が返されます。
  • getTypeName() "このタイプの名前のための有益な文字列を返します。"

それは、私はこれらのいずれかを望んでいないことをかなり明白です:

  • getSimpleName():「ソースコード内で指定されたとおり、基本となるクラスの単純名を返します。」
  • toString():クラス 『または「インタフェース『文字列表現が文字列である』』空白が続き、その後、クラスの完全修飾名でのgetNameによって返された形式で」

Iドンこれがプリミティブ型で動作することを期待していません。アレイでうまくいかない場合は問題ありません。私が心配している主なものは、ネストされたクラスとFoo.BarFoo$Barです。

+1

私はネストしています。質問が更新されました –

答えて

8

確定回答はgetName()です。ビット隠されているが、これはforName(className, initialize, loader)の過負荷のJavadocで指定されている:クラスまたはインタフェース(getNameによって返される同じフォーマットで)このメソッドの完全修飾名を与えられ

を見つけようとし、クラスまたはインタフェースをロードし、リンクします。

そして、またforName(className)を呼び出すと、デフォルト値で、このオーバーロードを呼び出すことと同等であることが明記されています。このメソッドを呼び出す

は同等です:

currentLoaderは定義を示し
Class.forName(className, true, currentLoader) 

現在のクラスのクラスローダーです。


ここでは、ネストされたクラス、ローカルクラス、匿名クラス、プリミティブまたはオブジェクトの配列のために働くことを示すサンプルコードです。 Class.forNameはプリミティブクラスを処理しないため、プリミティブでは機能しません。

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

逆に、 'getTypeName'も' getCanonicalName'も例えば、プリミティブ配列のために働く。 Class.forName(int []。class)は、ClassNotFoundExceptionをスローしますが、Class.forName(int []。class.getCanonicalName())はスローします。 class.getName()) 'はできません。 – palimpsestor

+0

埋め込まれたjavadocリファレンスを見つけてくれてありがとう - それは私が探していて見つけられなかった正式な言葉です! –

2

それは、少なくとも簡単な場合には、いずれかgetName()またはgetTypeName()作品のようになります。私はいつもあなたのようなgetCanonicalName()内部のオブジェクトを(使用

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

それはまさに私がやったところです。うわー、あなたは何かを知っていると思います(私は確かに** Foo.Bar'でした)。そして、あなたはそれをテストしようとします。 –

1

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{} 
} 

生成される出力がありますFoo $ Bar静的なパブリックとインラインの実装の場合)も同様に構築できます。

また、プリミティブで動作させることもできます。たとえば、 'int.class'などは存在します。しかし、おそらくプリミティブクラスのチェックを行い、Objectインスタンス(Integer vs int)を作成してから、intValue()のようなアクセサを呼び出してください。このため、私は多くのObjectインスタンスとプリミティブを使用していますが、それは私の推測です。

-1
Object oAgain = oClass.newInstance(); 

[EDIT]は非静的内部クラスのオブジェクトを作成するためのnewInstance()メソッドを使用することができない方法(のgetName()、getCanonicalName()、等。) どんなに

newInstance()を使用してオブジェクトを作成する場合、必須のクラスには引数なしのコンストラクタが含まれている必要があります。私たちは、明示的に1つの引数のコンストラクタを挿入しない場合であっても、コンパイラは(唯一の非静的内部クラスの場合には)いくつかの引数を持つコンストラクタに

を変換します[ENDのEDIT]以下

は簡単のためのリンクです私が見つけたコード。上記の説明を示しています。

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

+0

引数なしのコンストラクタをデフォルトのコンストラクタにする必要はありません。 –

+1

答えを編集しました。つまり、newInstance()メソッドでは、引数なしのコンストラクタがクラスに存在すると想定しています。 –

関連する問題