web-dev-qa-db-ja.com

返されるオブジェクトをジェネリック型にキャスト

オブジェクトをキャストしてメソッドの値を返す方法はありますか?私はこの方法を試しましたが、「instanceof」部分でコンパイル時の例外が発生しました:

public static <T> T convertInstanceOfObject(Object o) {
    if (o instanceof T) {
        return (T) o;
    } else {
        return null;
    }
}

私もこれを試してみましたが、実行時例外ClassCastExceptionが発生しました。

public static <T> T convertInstanceOfObject(Object o) {
    try {
        T rv = (T)o;
        return rv;
    } catch(Java.lang.ClassCastException e) {
        return null;
    }
}

これを簡単に行う方法はありますか?

String s = convertInstanceOfObject("string");
System.out.println(s); // should print "string"
Integer i = convertInstanceOfObject(4);
System.out.println(i); // should print "4"
String k = convertInstanceOfObject(345435.34);
System.out.println(k); // should print "null"

編集:正解の作業コピーを書きました:

public static <T> T convertInstanceOfObject(Object o, Class<T> clazz) {
    try {
        return clazz.cast(o);
    } catch(ClassCastException e) {
        return null;
    }
}

public static void main(String args[]) {
    String s = convertInstanceOfObject("string", String.class);
    System.out.println(s);
    Integer i = convertInstanceOfObject(4, Integer.class);
    System.out.println(i);
    String k = convertInstanceOfObject(345435.34, String.class);
    System.out.println(k);
}
117
sedran

コンパイル中にジェネリック型が消去されるため、Classインスタンスを使用する必要があります。

public static <T> T convertInstanceOfObject(Object o, Class<T> clazz) {
    try {
        return clazz.cast(o);
    } catch(ClassCastException e) {
        return null;
    }
}

そのメソッド の宣言は次のとおりです。

public T cast(Object o)

これは配列型にも使用できます。次のようになります。

final Class<int[]> intArrayType = int[].class;
final Object someObject = new int[]{1,2,3};
final int[] instance = convertInstanceOfObject(someObject, intArrayType);

someObjectconvertToInstanceOfObjectに渡すと、コンパイル時のタイプはObjectになります。

182
SpaceTrucker

私はこの質問に出くわし、それが私の興味をひいた。受け入れられた答えは完全に正しいですが、OPバイトがClassCastExceptionに遭遇する理由を説明するために、JVMバイトコードレベルで調査結果を提供すると思いました。

私はOPのコードとほとんど同じコードを持っています:

public static <T> T convertInstanceOfObject(Object o) {
    try {
       return (T) o;
    } catch (ClassCastException e) {
        return null;
    }
}

public static void main(String[] args) {
    String k = convertInstanceOfObject(345435.34);
    System.out.println(k);
}

対応するバイトコードは次のとおりです。

public static <T> T convertInstanceOfObject(Java.lang.Object);
    Code:
       0: aload_0
       1: areturn
       2: astore_1
       3: aconst_null
       4: areturn
    Exception table:
       from    to  target type
           0     1     2   Class Java/lang/ClassCastException

  public static void main(Java.lang.String[]);
    Code:
       0: ldc2_w        #3                  // double 345435.34d
       3: invokestatic  #5                  // Method Java/lang/Double.valueOf:(D)Ljava/lang/Double;
       6: invokestatic  #6                  // Method convertInstanceOfObject:(Ljava/lang/Object;)Ljava/lang/Object;
       9: checkcast     #7                  // class Java/lang/String
      12: astore_1
      13: getstatic     #8                  // Field Java/lang/System.out:Ljava/io/PrintStream;
      16: aload_1
      17: invokevirtual #9                  // Method Java/io/PrintStream.println:(Ljava/lang/String;)V
      20: return

checkcastバイトコード命令は、convertInstanceOfObjectおよびconvertInstanceOfObjectメソッドにClassCastExceptionをスローできる命令がないのではなく、メインメソッドで発生することに注意してください。 mainメソッドはClassCastExceptionをキャッチしないため、mainメソッドを実行するとClassCastExceptionを取得しますが、nullの出力は期待できません。

次に、受け入れられた答えにコードを変更します。

public static <T> T convertInstanceOfObject(Object o, Class<T> clazz) {
        try {
            return clazz.cast(o);
        } catch (ClassCastException e) {
            return null;
        }
    }
    public static void main(String[] args) {
        String k = convertInstanceOfObject(345435.34, String.class);
        System.out.println(k);
    }

対応するバイトコードは次のとおりです。

public static <T> T convertInstanceOfObject(Java.lang.Object, Java.lang.Class<T>);
    Code:
       0: aload_1
       1: aload_0
       2: invokevirtual #2                  // Method Java/lang/Class.cast:(Ljava/lang/Object;)Ljava/lang/Object;
       5: areturn
       6: astore_2
       7: aconst_null
       8: areturn
    Exception table:
       from    to  target type
           0     5     6   Class Java/lang/ClassCastException

  public static void main(Java.lang.String[]);
    Code:
       0: ldc2_w        #4                  // double 345435.34d
       3: invokestatic  #6                  // Method Java/lang/Double.valueOf:(D)Ljava/lang/Double;
       6: ldc           #7                  // class Java/lang/String
       8: invokestatic  #8                  // Method convertInstanceOfObject:(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
      11: checkcast     #7                  // class Java/lang/String
      14: astore_1
      15: getstatic     #9                  // Field Java/lang/System.out:Ljava/io/PrintStream;
      18: aload_1
      19: invokevirtual #10                 // Method Java/io/PrintStream.println:(Ljava/lang/String;)V
      22: return

invokevirtualメソッドにconvertInstanceOfObject命令があり、Class.cast()メソッドを呼び出してClassCastExceptionをスローします。これはcatch(ClassCastException e)ブロックでキャッチされ、nullを返します。したがって、「null」は例外なくコンソールに出力されます。

14
Alvin

例外のスローに依存したくない場合(おそらくそうすべきではありません)、これを試すことができます:

public static <T> T cast(Object o, Class<T> clazz) {
    return clazz.isInstance(o) ? clazz.cast(o) : null;
}
5
intra