web-dev-qa-db-ja.com

Java)でラッパークラスタイプを取得する簡単な方法

メソッド内のフィールドのクラスを渡す必要があるコードがあります。私のコードの仕組みのために、私は参照オブジェクトのみを処理でき、プリミティブは処理できません。 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);

これは、すべてのプリミティブ型を明示的にチェックし、それらを適切なラッパークラスと交換する必要があるという事実を除いて、正常に機能します。プリミティブ型はそれほど多くないので、すべてをリストするだけでも問題はないことがわかりましたが、もっと簡単でエレガントな方法があるのではないかと思いました。

28

私はそのように甘やかされているので、私の答えでは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()およびその他のいくつかの付随的なものがあります。

37

Apache Commons Lang これを行うためのユーティリティメソッドがあります( ClassUtils.primitiveToWrapper() )、これは裏で同じように醜いですが、少なくともあなたはそれが素晴らしいと偽ることができます。

39
skaffman

高度に最適化されたコードが必要ない場合の別の方法は次のとおりです。

    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にあるすべてのプリミティブ型で機能します。

11
Fai Ng

Class.isPrimitive()を呼び出して、それがプリミティブであるかどうかを知ることができますが、JDK内のクラスを変換するためのボクシングメソッドはありません。これに関連して少なくとも1つ 未解決のバグ があります。

7
Yishai
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;
}
2
Jim Smith

(アイデア)クラス名を取得して最初の文字を大文字にしてから、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");
                                        }
                                    }

                                }
2
LMD

Com.Sun.beans.Finder.PrimitiveWrapperMap#getType(primitiveName)もあります。しかしもちろん、「com.Sun」パッケージのクラスを使用することはお勧めしません...

1
etrusco

したがって、ラッパークラスタイプを取得する必要があります。

あらすじ

フィールドを取得しているところ、プリミティブ型が含まれていることがわかりました。

_Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType();
_

ただし、代わりにラッパータイプが必要です。

Javaのプリミティブ型

すでにわかっているように、プリミティブクラスが適しているのは、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)
_

Nullラッパータイプにキャストできます。うん!\o /

_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!

0
nickl-