175 Stimmen

Objekt in einen generischen Typ umwandeln zur Rückgabe

Gibt es eine Möglichkeit, ein Objekt in den Rückgabewert einer Methode umzuwandeln? Ich habe es auf diese Weise versucht, aber es gab zur Kompilierzeit eine Ausnahme im "instanceof"-Teil:

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

Ich habe auch dies versucht, aber es gab zur Laufzeit eine Ausnahme, ClassCastException:

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

Gibt es eine Möglichkeit, dies einfach zu tun:

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

EDIT: Ich habe eine funktionierende Kopie der korrekten Antwort geschrieben:

public static  T convertInstanceOfObject(Object o, Class 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);
}

264voto

SpaceTrucker Punkte 12246

Sie müssen eine Class-Instanz verwenden, aufgrund der generischen Typenlöschung während der Kompilierung.

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

Die Deklaration dieser Methode ist:

public T cast(Object o)

Dies kann auch für Array-Typen verwendet werden. Es würde so aussehen:

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

Beachten Sie, dass wenn someObject an convertToInstanceOfObject übergeben wird, es den Compiler-Typ Object hat.

28voto

Alvin Punkte 9948

Ich stolpere über diese Frage und sie hat mein Interesse geweckt. Die akzeptierte Antwort ist völlig korrekt, aber ich dachte, ich gebe meine Erkenntnisse auf der JVM-Bytecode-Ebene weiter, um zu erklären, warum der OP die ClassCastException erlebt.

Ich habe den Code, der so ziemlich der gleiche ist wie der Code des OP:

public static  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);
}

und der entsprechende Bytecode lautet:

public static  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

Beachten Sie, dass die Bytecode-Anweisung checkcast im Hauptmethodenblock statt im convertInstanceOfObject Block erfolgt und die convertInstanceOfObject Methode keine Anweisung enthält, die eine ClassCastException auslösen kann. Da die Hauptmethode die ClassCastException nicht abfängt, erhalten Sie beim Ausführen der Hauptmethode eine ClassCastException und nicht die Erwartung, null auszudrucken.

Jetzt modificiere ich den Code zur akzeptierten Antwort:

public static  T convertInstanceOfObject(Object o, Class 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);
    }

Der entsprechende Bytecode lautet:

public static  T convertInstanceOfObject(java.lang.Object, java.lang.Class);
    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

Beachten Sie, dass es eine invokevirtual Anweisung in der convertInstanceOfObject Methode gibt, die die Class.cast() Methode aufruft, die eine ClassCastException auslöst, die vom catch(ClassCastException e) Block abgefangen und null zurückgegeben wird; daher wird "null" ohne Ausnahme auf der Konsole gedruckt.

25voto

intra Punkte 685

Wenn Sie nicht von der Ausnahmeabhängigkeit abhängen möchten (was Sie wahrscheinlich nicht sollten), können Sie Folgendes versuchen:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X