2010-05-06 12 views
3

// Code héritageConvertir le code hérité java en générique - comment remplacer l'objet avec le type?

void setCacheValue(String name, Object value){ 
    getServletContext().setAttribute(name, value); 
} 
Object getCacheValue(String name){ 
    return getServletContext().getAttribute(name); 
} 

// donc je veux utiliser générique pour "type sécurité"

// first, set method seems working perfectly 
<T> void setCacheObject(String name, T value){ 
    getServletContext().setAttribute(name, value); 
} 

// vient donc ici la peine

<T> T getCacheValue(String name){  
    // of course, I cannot change servlet class - it returns Object type 
    Object value = getServletContext().getAttribute(name); 
    // would this work:  
    return (T) value; 
    // this cast is meaningless... but how should I do it? 
} 

// C'est ce que je ce que pour atteindre dans mon propre code de l'appelant:

{ 
    double x = 1.2; 
    setCacheValue("x", x); 
    //... 
    // later 
    Double value = getCacheValue("x"); 
    // too bad cannot use primitive type - it cannot handle null 

}

Alors, quelle est la bonne façon de le faire?

Répondre

3

Ce n'est en effet pas possible. Vous devrez passer le "béton" T en quelque sorte comme argument de méthode afin que le type réel soit connu pendant l'exécution. Généralement approche utilisée passe comme Class<T>, de sorte que vous pouvez utiliser Class#cast():

<T> T getCacheValue(String name, Class<T> type) { 
    return type.cast(getServletContext().getAttribute(name)); 
} 

Vous pouvez l'utiliser comme suit:

Double value = getCacheValue("x", Double.class); 
+0

+ problème commun - approche standard – leonbloy

+0

très bien. J'ai trouvé que le cast de classe fait deux choses: il supprime l'avertissement de compilation, et il vérifie le type au moment de l'exécution - bien qu'il soit peut-être trop tard, mais il est préférable de ne pas vérifier du tout. (avec un prix d'avoir à passer un paramètre supplémentaire) – joejax

0

génériques de cartes prennent en charge un type sur toutes les valeurs de la carte , pas un type différent pour des valeurs spécifiques. Vous pouvez voir comment simuler here. Fondamentalement, l'idée est que vous devez avoir le type de sécurité sur la clé, où la clé a un type générique qui existe simplement à associer à la valeur. À la fin de la journée, vous ne serez pas en mesure de le faire sans un casting dangereux, mais vous pouvez le faire d'une manière qui rend extrêmement improbable qu'il y ait un problème avec un plâtre et d'une manière qui est typesafe aux utilisateurs de votre classe.

+0

Idée intéressante. Notez seulement que la table d'attributs du contexte de servlet n'accepte que les clés de type String. Vous devriez y mettre une autre carte et l'utiliser en conséquence. - – BalusC

0

En fait compilant aussi:

public class Test 
{ 
    <T> T getCacheValue(String name){  
     // of course, I cannot change servlet class - it returns Object type 
     Object value = getServletContext().getAttribute(name); 
     // would this work:  
     return (T) value; 
     // this cast is meaningless... but how should I do it? 
    } 

    public static void main(String... args) 
    { 
     Test t = new Test(); 
     Double double = t.<Double>getCacheValue("Double"); 
    } 
} 

Il est un peu vain (peut-être si vous ajoutez un typecheck) mais je l'ai trouvé intéressant de savoir.