53

Java でリフレクティブ メソッドを呼び出す必要があります。これらの呼び出しには、プリミティブ型 (int、double など) の引数を持つメソッドが含まれます。メソッドをリフレクティブに検索する際に、そのような型を指定する方法は、int.class、double.class などです。

課題は、型を動的に指定する外部ソースからの入力を受け入れることです。したがって、これらのクラス参照も動的に作成する必要があります。パラメータ型のリストを含むメソッド名のリストである区切りファイルを想像してください。

doSomething int double
doSomethingElse java.lang.String boolean

入力が のようなものだった場合、その Class インスタンスをjava.lang.String使用できることがわかります。Class.forName("java.lang.String")そのメソッドまたは別のメソッドを使用して、プリミティブ型のクラスを取り戻す方法はありますか?

編集: すべての回答者に感謝します。私がやりたいことをきれいに行う組み込みの方法がないことは明らかなのでClassUtils、Spring フレームワークのクラスを再利用することにします。私の要件で動作する Class.forName() の代替品が含まれているようです。

4

8 に答える 8

31

プリミティブ型のClassインスタンスは、あなたが言ったように eg を使用int.classして取得できますが、 のようなものを使用して同じ値を取得することも可能ですInteger.TYPETYPE各プリミティブ ラッパー クラスには、対応するプリミティブ クラス インスタンスを持つ静的フィールド が含まれます。

からプリミティブ クラスを取得することはできませんが、forNameすぐに利用できるクラスから取得できます。絶対にリフレクションを使用する必要がある場合は、次のようなことを試すことができます。

Class clazz = Class.forName("java.lang.Integer");
Class intClass = clazz.getField("TYPE").get(null);

intClass.equals(int.class);         // => true
于 2008-10-07T20:02:24.593 に答える
21

Spring フレームワークには、静的メソッド forName を含むユーティリティ クラスClassUtilsが含まれています。この方法は、説明した正確な目的に使用できます。

Spring に依存したくない場合:メソッドのソース コードはe . g. こちらの公開リポジトリにあります。クラスのソース コードは、Apache 2.0 モデルでライセンスされています。

ただし、アルゴリズムはプリミティブ型のハードコーディングされたマップを使用することに注意してください。


編集:リンク切れを指摘してくれたコメンターの Dávid Horváth と Patrick に感謝します。

于 2008-10-07T20:12:30.127 に答える
20

おそらく、プリミティブをマップし、残りのクラスに対して「forName」メソッドを実行する必要があるだけです。

私は次のようなことをします:

void someWhere(){
     String methodDescription = "doSomething int double java.lang.Integer java.lang.String"
     String [] parts = methodDescription.split();
     String methodName= parts[0]
     Class [] paramsTypes = getParamTypes( parts ); // Well, not all the array, but a, sub array from 1 to arr.length..  

    Method m = someObject.class.getMethod( methodName, paramTypes );
    etc. etc etc.
}

public Class[] paramTypes( String [] array ){
     List<Class> list = new ArrayList<Class>();
     for( String type : array ) {
         if( builtInMap.contains( type )) {
             list.add( builtInMap.get( type ) );
          }else{
             list.add( Class.forName( type ) );
          }
     }
     return list.toArray();
}  

    // That's right.
Map<String,Class> builtInMap = new HashMap<String,Class>();{
       builtInMap.put("int", Integer.TYPE );
       builtInMap.put("long", Long.TYPE );
       builtInMap.put("double", Double.TYPE );
       builtInMap.put("float", Float.TYPE );
       builtInMap.put("bool", Boolean.TYPE );
       builtInMap.put("char", Character.TYPE );
       builtInMap.put("byte", Byte.TYPE );
       builtInMap.put("void", Void.TYPE );
       builtInMap.put("short", Short.TYPE );
}

つまり、プリミティブ型が格納されているマップを作成し、記述がプリミティブに属している場合は、マップされたクラスを使用します。このマップは、柔軟性を追加するために外部構成ファイルからロードすることもできます。そのため、java.lang.String の代わりに String をビルトインとして追加するか、このようなメソッドを持つ可能性があります。

"doSomething 文字列 yes|no "

Struts、Hibernate、Spring、Apache ライブラリなどの OS プロジェクトには、この種のコードがたくさんあるので (いくつか挙げるとすれば)、ゼロから始める必要はありません。

ところで。私は上記のコードをコンパイルしませんでしたが、少し変更を加えるだけで動作すると確信しています。

于 2008-10-07T21:18:27.683 に答える
5

Apache Commons Langには、プリミティブ型をサポートするClassUtils.getClass(String)があります。

于 2013-06-25T08:06:35.093 に答える
3

残念ながら、いくつかの Class メソッドは一貫した方法でプリミティブを処理しません。forName でこれを回避する一般的な方法は、次のようなテーブルを作成することです。

private static final Map<String, Class> BUILT_IN_MAP = 
    new ConcurrentHashMap<String, Class>();

static {
    for (Class c : new Class[]{void.class, boolean.class, byte.class, char.class,  
            short.class, int.class, float.class, double.class, long.class})
        BUILT_IN_MAP.put(c.getName(), c);
}

public static Class forName(String name) throws ClassNotFoundException {
    Class c = BUILT_IN_MAP.get(name);
    if (c == null)
        // assumes you have only one class loader!
        BUILT_IN_MAP.put(name, c = Class.forName(name));
    return c;
}
于 2009-03-14T21:10:13.907 に答える
2

次のコードは、フィールド名がわかっているプリミティブ型のクラスを取得する方法について説明しています。たとえば、この場合は「sampleInt」です。

public class CheckPrimitve {
    public static void main(String[] args) {
        Sample s = new Sample();
        try {
            System.out.println(s.getClass().getField("sampleInt").getType() == int.class); // returns true
            System.out.println(s.getClass().getField("sampleInt").getType().isPrimitive()); // returns true
        } catch (NoSuchFieldException e) {          
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }       
    }
}

class Sample {
    public int sampleInt;
    public Sample() {
        sampleInt = 10;
    }
}

それぞれのラッパー クラスまたはフィールド値を取得することで、指定された値がプリミティブかどうかを確認することもできます。

    public class CheckPrimitve {
        public static void main(String[] args) {
            int i = 3;
            Object o = i;
            System.out.println(o.getClass().getSimpleName().equals("Integer")); // returns true
            Field[] fields = o.getClass().getFields();
            for(Field field:fields) {
                System.out.println(field.getType()); // returns {int, int, class java.lang.Class, int}
            }
        }
    }
于 2012-10-01T06:26:13.967 に答える