プリミティブなJava型を表すクラスを動的に見つける
-
05-07-2019 - |
質問
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()の代替が含まれているようです。
解決
Springフレームワークには、ユーティリティクラス ClassUtils には、静的メソッドforNameが含まれます。このメソッドは、説明したとおりの目的に使用できます。
Springに依存したくない場合:メソッドのソースコードは、 eg こちら の公開リポジトリ。クラスのソースコードは、Apache 2.0モデルでライセンスされています。
ただし、アルゴリズムはプリミティブ型のハードコーディングされたマップを使用することに注意してください。
編集:壊れたリンクを指摘してくれたDá vid Horvá thとPatrickのコメントに感謝します。
他のヒント
プリミティブ型の 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
おそらく、プリミティブをマップするだけで、残りのクラスでは" 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を組み込みとして追加するか、このようなメソッドを潜在的に持つために、柔軟性を追加するために、外部構成ファイルからロードすることもできます。
&quot; doSomething string yes | no&quot;
OSプロジェクトには、Struts、Hibernate、Spring、Apache libs(ほんの数例を挙げます)などのこの種のコードがたくさんあるため、ゼロから始める必要はありません。
ところで。上記のコードはコンパイルしませんでしたが、少し変更を加えても動作することは間違いありません。
Apache Commons Lang にはClassUtils.getClass(String)(プリミティブ型をサポート)。
残念ながら、多くの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;
}
次のコードは、フィールド名がわかっているプリミティブ型のクラスを取得する方法について説明しています。この場合は「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}
}
}
}
Google Guavaは、この種のものに対して com.google.common.primitives.Primitives
を提供しています。