2009-03-11 10 views
6

Je voudrais implémenter une méthode qui prend un Object comme argument, le convertit en un type arbitraire, et si cela échoue, retourne null. Voici ce que j'ai jusqu'à présent:Génériques Java

public static void main(String[] args) { 
    MyClass a, b; 
    a = Main.<MyClass>staticCast(new String("B")); 
} 

public static class MyClass { 
} 

public static <T> T staticCast(Object arg) { 
    try { 
     if (arg == null) return null; 
     T result = (T) arg; 
     return result; 
    } catch (Throwable e) { 
     return null; 
    } 
} 

Malheureusement, l'exception de fonte de classe est jamais jeté/pris dans le corps de la fonction staticCast(). Il semble que le compilateur Java génère la fonction String staticCast(Object arg) dans laquelle vous avez une ligne String result = (String) arg; même si je dis explicitement que le type de modèle doit être MyClass. De l'aide? Merci.

+0

Par ailleurs, vous devriez être catchin g uniquement ClassCastException, non Throwable. Catching Throwable peut causer de sérieux problèmes. –

Répondre

10

Parce que l'information de type générique est effacé lors de l'exécution, la manière standard de caster un type générique est un objet Class:

public static <T> T staticCast(Object arg, Class<T> clazz) { 
    if (arg == null) return null; 
    if (!clazz.isInstance(arg)) 
     return null; 
    T result = clazz.cast(arg); 
    return result; 
} 

Ensuite, appelez comme ceci:

a = Main.staticCast("B", MyClass.class); 
+0

en utilisant Class.isInstance serait plus direct. –

+0

hmm, clazz? est-ce comme un klass? –

+0

isInstance ne fonctionne que si l'objet est une instance de clazz, et non s'il s'agit d'une sous-classe de clazz. isAssignableFrom fonctionnera sur tout ce qui peut être converti en clazz, même en sous-classes. –

6

Vous ne pouvez pas faire ce que vous voulez ... du moins pas de cette façon. Le compilateur a supprimé toutes les informations afin que vous finissiez avec (T) étant Object dans la distribution - et cela fonctionne.

Le problème est que plus tard vous faites l'objet MyClass = (String); et ce n'est pas autorisé.

Vous avez contourné la vérification des compilateurs et l'avez fait échouer lors de l'exécution.

Alors, qu'est-ce que vous essayez de faire exactement? Si vous nous dites pourquoi vous voulez faire cela, nous pouvons probablement vous dire la façon Java de le faire.

Compte tenu de votre commentaire, vous pouvez essayer quelque chose comme:

public class Main 
{ 
    public static void main(String[] args) 
    { 
     String a; 
     MyClass b; 
     a = staticCast(new String("B"), String.class); 
     b = staticCast(new String("B"), MyClass.class); 
     System.out.println(a); 
    } 

    public static class MyClass 
    { 
    } 

    public static <T> T staticCast(Object arg, final Class clazz) 
    { 
     // edit - oops forgot to deal with null... 
     if(arg == null) 
     { 
      return (null); 
     } 

     // the call to Class.cast, as mmeyer did, might be better... probably is better... 
     if(arg.getClass() != clazz) 
     { 
      // Given your answer to Ben S... 
      return (null); 

      // throw new ClassCastException("cannot cast a " + arg.getClass() + " to a " + clazz); 
     } 

     return ((T)arg); 
    } 
} 
+0

Je vois, donc T est un objet dans la distribution. Je veux une méthode distincte pour chaque T qui va lancer l'argument à (T), et si cela échoue, une exception est attrapée et non levée.Selon Paul Tomblin (ci-dessous), cela n'arrivera pas. – Budric

+0

le code que j'ai fourni dans l'édition devrait faire ce que vous voulez – TofuBeer

1

Ne confondez pas Java génériques pour les modèles C++. Il va seulement être une méthode staticCast qui est appelée avec différents effacement de type, pas un pour chaque T.

Ne pas utiliser Génériques du tout, je l'écrire de cette façon:

public static void main(String[] args) { 
    MyClass a, b; 
    a = (MyClass)Main.staticCast(new String("B"), MyClass.class); 
} 

public static class MyClass { 
} 

public static staticCast(Object arg, Class class) { 
     if (arg != null && class.isAssignableFrom(arg)) 
      return arg; 
     return null; 
} 

ou le vol d'un autre répondre, en utilisant des génériques:

public static <T> T staticCast(Object arg, Class<T> class) { 
     if (arg != null && class.isAssignableFrom(arg)) 
     { 
      T result = class.cast(arg); 
      return result; 
     } 
     return null; 
} 
+0

J'ai oublié que CCE était une exception RuntimeException et ne nécessitait pas de bloc catch, ou je l'aurais fait comme votre seconde méthode à l'origine. –

+0

Pouvez-vous expliquer pourquoi le compilateur Java ne génère pas la fonction MyClass staticCast (Object arg); quand je spécifie explicitement le type T dans la ligne: a = Main. StaticCast (new String ("B")) ; Je l'ai explicitement dit à ... Je pensais Un lien vers une lecture serait génial. – Budric

+0

@Budric: Essayez http://java.sun.com/docs/books/tutorial/java/generics/erasure.html. Recherchez également les questions marquées [java] [génériques]. Il y en a d'assez intéressants. –

4

Vous voulez dire Class<T>.cast(Object obj)?

Quelque chose comme:

Class.forName("YourClass").cast(obj); 

devrait faire à peu près ce que vous voulez. Sachez que c'est assez malodorant cependant et est probablement un signe de mauvaise conception.

+0

Merci. Le problème est que ceci jettera une exception de cast de classe si elle échoue. Il est identique à l'objet code: (YourClass) et vous obtenez une exception d'erreur que vous devez vérifier chaque fois que vous utilisez cette ligne de code. J'aimerais attraper et masquer cette exception dans la méthode cast(). – Budric

+0

Voulez-vous asSubclass ou getConstructor(). NewInstance(). Cast? –

1

Je suis d'accord avec Ben, cependant, je préfère la notation suivante:

MyClass.class.cast(obj); 
Questions connexes