web-dev-qa-db-ja.com

プリミティブJava typeを表すクラスを動的に見つける

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

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

_doSomething int double
doSomethingElse Java.lang.String boolean
_

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

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

46
Mike Furtak

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

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

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


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

21
Synoli

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

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

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

intClass.equals(int.class);         // => true
26
Daniel Spiewak

おそらく、プリミティブをマップするだけで、残りのクラスでは「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 string yes | no"

Struts、Hibernate、Spring、Apache libsなどのOSプロジェクトには、この種のコードがたくさんあります(ほんの数例を挙げると)ので、ゼロから始める必要はありません。

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

17
OscarRyz

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

5
thSoft

残念ながら、多くの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;
}
3
Peter Lawrey

次のコードは、フィールド名がわかっているプリミティブ型のクラスを取得する方法について説明しています。この場合、「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}
            }
        }
    }
2
Arham

Google Guavaはcom.google.common.primitives.Primitivesこの種のものに。

1
Adrodoc55