メソッド内のフィールドのクラスを渡す必要があるコードがあります。私のコードの仕組みのために、私は参照オブジェクトのみを処理でき、プリミティブは処理できません。 Field
の型がプリミティブであるかどうかを簡単に判断し、適切なラッパークラスと交換する方法が必要です。したがって、コードでは、これまでに行ったことは次のようなものです。
Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType();
if (c == int.class) {
c = Integer.class;
}
else if (c == float.class) {
c = Float.class;
}
// etc
myMethod(c);
これは、すべてのプリミティブ型を明示的にチェックし、それらを適切なラッパークラスと交換する必要があるという事実を除いて、正常に機能します。プリミティブ型はそれほど多くないので、すべてをリストするだけでも問題はないことがわかりましたが、もっと簡単でエレガントな方法があるのではないかと思いました。
私はそのように甘やかされているので、私の答えではGoogleコレクションライブラリを使用しますが、必要に応じて、プレーンなHashMapでそれを行う方法をおそらく見ることができます。
// safe because both Long.class and long.class are of type Class<Long>
@SuppressWarnings("unchecked")
private static <T> Class<T> wrap(Class<T> c) {
return c.isPrimitive() ? (Class<T>) PRIMITIVES_TO_WRAPPERS.get(c) : c;
}
private static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS
= new ImmutableMap.Builder<Class<?>, Class<?>>()
.put(boolean.class, Boolean.class)
.put(byte.class, Byte.class)
.put(char.class, Character.class)
.put(double.class, Double.class)
.put(float.class, Float.class)
.put(int.class, Integer.class)
.put(long.class, Long.class)
.put(short.class, Short.class)
.put(void.class, Void.class)
.build();
このためにJDKに何も存在しないのは奇妙ですが、実際には何もありません。
編集:私たちはこれをリリースしたことを完全に忘れていました:
http://google.github.io/guava/releases/21.0/api/docs/com/google/common/primitives/Primitives.html
これには、wrap()メソッドに加えて、unwrap()およびその他のいくつかの付随的なものがあります。
Apache Commons Lang これを行うためのユーティリティメソッドがあります( ClassUtils.primitiveToWrapper() )、これは裏で同じように醜いですが、少なくともあなたはそれが素晴らしいと偽ることができます。
高度に最適化されたコードが必要ない場合の別の方法は次のとおりです。
Class<?> primitive=long.class;
Class<?> boxed=Array.get(Array.newInstance(primitive,1),0).getClass();
System.out.println(primitive.getName());
System.out.println(boxed.getName());
(説明の編集・追加)
最初は、Javaに、プリミティブ型が与えられたときにラッパークラスを与えるメソッドがあるかどうかを確認することでした。何も見つかりませんでした。
次に、プリミティブ型を指定するときにJavaでプリミティブ値を作成できるかどうかを確認しました(その後、何らかの方法でオブジェクトを取得できます)。その方法が見つかりませんでした。この。
しかし、その後、プリミティブ型が与えられたときにJavaプリミティブ値の配列を作成することができることがわかりました。そして、Java配列要素のラッピング型のオブジェクト(プリミティブ)です。オブジェクトを取得したら、型を取得できます。
したがって、全体がどのように機能するかを次に示します。
Array.newInstance()メソッドは、プリミティブかオブジェクトかに関係なく、指定したタイプの配列を作成します。オブジェクトの場合、すべての要素はオブジェクトタイプですが、nullに初期化されます。プリミティブの場合、要素はプリミティブ型です。ただし、プリミティブ変数/配列要素をnullにすることはできないため、プリミティブ型のデフォルト値があります。 intはゼロになります。したがって、nullになる要素はありません。そして今、Array.get()を使用して要素の値を取得しようとすると、Array.get()は、そのプリミティブ値をオブジェクトにボックス化する以外に選択肢がありません。 Array.get()はプリミティブ値を返すことができないため、intを整数に変換します。これで、元のプリミティブ型のボクシング(ラッピング)型のオブジェクトができました。最後にObject.getClass()を呼び出すと、ボクシング(ラッピング)タイプが得られます。
このトリックは、現在および将来のJavaにあるすべてのプリミティブ型で機能します。
Class.isPrimitive()を呼び出して、それがプリミティブであるかどうかを知ることができますが、JDK内のクラスを変換するためのボクシングメソッドはありません。これに関連して少なくとも1つ 未解決のバグ があります。
Class<?> toWrapper(Class<?> clazz) {
if (!clazz.isPrimitive())
return clazz;
if (clazz == Integer.TYPE)
return Integer.class;
if (clazz == Long.TYPE)
return Long.class;
if (clazz == Boolean.TYPE)
return Boolean.class;
if (clazz == Byte.TYPE)
return Byte.class;
if (clazz == Character.TYPE)
return Character.class;
if (clazz == Float.TYPE)
return Float.class;
if (clazz == Double.TYPE)
return Double.class;
if (clazz == Short.TYPE)
return Short.class;
if (clazz == Void.TYPE)
return Void.class;
return clazz;
}
(アイデア)クラス名を取得して最初の文字を大文字にしてから、Class.forInstance(className).newInstance(primitive)を呼び出します。例外は、「char」->文字および「int」->整数です。
Class c=Primitive class object
if (c.isPrimitive()) {
if (c == char.class) {
Object wrapper=new Character(primitive var);
}
if (c == int.class) {
Object wrapper=new Integer(primitive var);
}
else {
String name=c.getName();
try {
Class<?> c2=Class.forName("Java.lang."+name.substring(0,1).toUpperCase()+name.substring(1,name.length()));
Object wrapper=c2.getConstructor(c).newInstance(primitve_var);
} catch (ClassNotFoundException ex) {
System.out.println("RROR");
}
}
}
Com.Sun.beans.Finder.PrimitiveWrapperMap#getType(primitiveName)もあります。しかしもちろん、「com.Sun」パッケージのクラスを使用することはお勧めしません...
フィールドを取得しているところ、プリミティブ型が含まれていることがわかりました。
_Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType();
_
ただし、代わりにラッパータイプが必要です。
すでにわかっているように、プリミティブクラスが適しているのは、c.isPrimitive();
に対してtrueを返すことだけです。
から ウィキブックス-Javaプログラミング :
プリミティブ型は、Java言語で使用できる最も基本的なデータ型です。boolean、byte、char、short、int、long、float、doubleの8つがあります。これらの型はビルディングブロックとして機能します。このような型は、ある種の純粋で単純な値を含むという1つの目的にのみ役立ちます。
他の方法でそれらを使用しようとすると、あなたは多くの傷を負っています。
_Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.newInstance();
// Java.lang.InstantiationException thrown: int
// at Class.newInstance (Class.Java:545)
_
_Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.cast(0);
// Java.lang.ClassCastException thrown: Cannot cast Java.lang.Integer to int
// at Class.cast (Class.Java:3578)
_
_Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.cast(null);
_
例外はなく、変数wrapper
のタイプは_class Java.lang.Integer
_ですが、値がnull
であるため、非常に役立ちます。
_boolean isSuperClass = Integer.class.isAssignableFrom(int.class); // false
_
これは明らかに私たちをどこにも連れて行っていないので、問題から一歩後退して全体像を見てみましょう。
要約すると、_Java.lang.reflect.Field
_がfinalとマークされており、パブリックコンストラクターが公開されていないため、どこかから取得する必要のあるフィールドを取得しています。
ギャップを埋めるとしたら、こんな感じかもしれません。
_public class Simple {
public static int field;
public static void main(String[] args) {
Field f = Simple.class.getField("field"); // Actual method that returns my Field
Class<?> c = f.getType();
}
}
_
マシンと戦う代わりに、むしろそれを使って作業しましょう。プリミティブの利点の1つは、null
ではなくデフォルト値_0
_に初期化されることです。それが使えるか見てみましょう。
_public class Simple {
public static int field;
public static void main(String[] args) {
Simple boxer = new Simple();
Field f = Simple.class.getField("field");
Object wrapped = f.get(null); // Integer value 0
Class<?> c = wrapped.getClass(); // class Java.lang.Integer
}
}
_
それは以前よりずっと簡単で、私たちは何もする必要さえありませんでした、すべてが私たちのために行われました。ストリームに逆らおうとしないことに対するさらに別の特典。
それを改善し、リファクタリングして、メソッドを抽出することでもう少し再利用可能にしましょう。
_public class Simple {
public static int field;
public static <T> T wrap(T t) {
return t;
}
public static void main(String[] args) {
Field f = Simple.class.getField("field");
Class<?> c = Simple.wrap(f.get(null)).getClass(); // class Java.lang.Integer
}
}
_
Javaはとにかくすでにそれを行っているので、型を見たり、ルックアップテーブルを使用したりする必要のない単純なプリミティブラップ。
_Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.get(null).getClass();
_
または、フィールドが静的でない場合は、nullをインスタンスに置き換えることができます。
nJoy!