179 votes

Transformation d'un objet en un type générique pour le retour

Existe-t-il un moyen de transformer un objet en valeur de retour d'une méthode ? J'ai essayé de cette façon mais cela a donné une exception de compilation dans la partie "instanceof" :

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

J'ai également essayé celui-ci mais il a donné une exception d'exécution, ClassCastException :

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

Existe-t-il un moyen de le faire facilement ?

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"

EDIT : J'ai écrit une copie de travail de la réponse correcte :

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

269voto

SpaceTrucker Points 2897

Vous devez utiliser un Class en raison de l'effacement des types génériques lors de la compilation.

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

La déclaration de cette méthode est :

public T cast(Object o)

Cela peut également être utilisé pour les types de tableaux. Cela ressemblerait à ceci :

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

Notez que lorsque someObject est transmis à convertToInstanceOfObject il a le type de temps de compilation Object .

28voto

Alvin Points 3991

Je suis tombé sur cette question et elle a suscité mon intérêt. La réponse acceptée est tout à fait correcte, mais j'ai pensé que je devais fournir mes conclusions au niveau du code d'octet de la JVM pour expliquer pourquoi le PO a rencontré le problème suivant ClassCastException .

J'ai le code qui est à peu près le même que celui de l'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);
}

et le code d'octet correspondant est :

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

Remarquez que checkcast l'instruction de code d'octet se produit dans la méthode principale et non dans la méthode convertInstanceOfObject y convertInstanceOfObject n'a pas d'instruction qui puisse lancer ClassCastException . Parce que la méthode principale n'attrape pas le ClassCastException Ainsi, lorsque vous exécutez la méthode principale, vous obtiendrez un message de type ClassCastException et non l'attente de l'impression null .

Maintenant je modifie le code pour la réponse acceptée :

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

Le code d'octet correspondant est :

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

Remarquez qu'il y a un invokevirtual l'instruction dans le convertInstanceOfObject qui appelle Class.cast() qui lance la méthode ClassCastException qui sera attrapé par le catch(ClassCastException e) bock et retour null ; par conséquent, "null" est imprimé sur la console sans aucune exception.

25voto

intra Points 375

Si vous ne voulez pas dépendre de la levée d'exception (ce que vous ne devriez probablement pas faire), vous pouvez essayer ceci :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X