2009-05-13 10 views
4

Parfois, dans mon code, je voudrais me référer à (ce que je pense comme) le type implicite dans une hiérarchie générique (essentiellement le type impliqué par le premier? Dans ce qui suit).Puis-je simplifier cette Hiérarchie Java Generics

public class Foo<BAR extends Bar<?>> { 
    public void t(BAR x) { 
    List l = new ArrayList(); 
    Object baz = x.makeBaz(null); 
    l.add(baz); 
    x.setBazList(l); 
    } 
} 

public interface Bar<BAZ extends Number> { 
    public BAZ makeBaz(Object arg1); 
    public List<BAZ> getBazList(); 
    public void setBazList(List<BAZ> baz); 
} 

Par exemple, dans le code ci-dessus serait-il possible de remplacer les lignes

List l = new ArrayList(); 
    Object baz = x.makeBaz(null); 

avec quelque chose en utilisant les médicaments génériques?

Je préférerais ne pas avoir à écrire:

public class Foo<BAZ extends Number, BAR extends Bar<BAZ>> { 
    public void t(BAR x) { 
    List<BAZ> l = new ArrayList<BAZ>(); 
    BAZ baz = x.makeBaz(null); 
    l.add(baz); 
    } 
} 

car il se sent naturel de forcer ce sur la déclaration de toutes les classes dérivées.

Je sais que ce qui précède est un peu artificiel, mais c'est beaucoup plus simple que d'essayer d'afficher le code que je regarde.

Répondre

3

Je pense que le principal problème est que vous devez respecter une certaine façon que le type que vous obtenez de x.makeBaz() est le même que le paramètre de type de la liste que vous donnez à x.setBazList(l), et que si vous utilisez juste ? vous perdez que l'application capacité, vous avez donc besoin d'un paramètre de type générique. Mais dans un certain sens, le paramètre de type est seulement nécessaire "localement" dans ces quelques lignes et le reste de la classe ne devrait pas avoir besoin de savoir.

Vous pouvez utiliser le paramètre de type BAZ à la méthode juste paramétrez au lieu de la classe:

public <BAZ extends Number> void t2(Bar<BAZ> x) { 
    List<BAZ> l = new ArrayList<BAZ>(); 
    BAZ baz = x.makeBaz(null); 
    l.add(baz); 
    x.setBazList(l); 
} 

Cela permet de localiser la région du code où nous avons besoin de ce type variable temporaire BAZ. Notez que la signature de cette méthode est effectivement public void t2(Bar<?> x), c'est-à-dire que l'extérieur n'a pas besoin de savoir à ce sujet BAZ.

Maintenant, bien sûr, cette méthode accepte maintenant tous les Bar<anything> au lieu de seulement BAR. Si c'est un problème, vous pouvez simplement "envelopper" la méthode ci-dessus. Nous n'avons pas le même problème qu'avant parce que tous les trucs BAZ est déjà enfermé à l'intérieur t2(), qui prend Bar<anything>, afin que nous puissions en toute sécurité passer un BAR:

public void t(BAR x) { 
    t2(x); 
} 

Je suis d'accord que cela semble un peu rond-point. Peut-être que quelqu'un d'autre va trouver un meilleur moyen.

+0

par la façon dont on l'appelle "aide de capture": http://www.ibm.com/developerworks/java/library/j-jtp04298.html# 3.0 – newacct

0

Vous pouvez au moins se lient au nombre de BAZ étend Nombre

public class Foo<BAR extends Bar<?>> { 
    public void t(BAR x) {  
     List<Number> l = new ArrayList<Number>(); 
     Number baz = x.makeBaz(null); 
     l.add(baz); 
     // l.add(Integer.valueOf(1)); compiles but with this here the next line throws ClassCastException 
     x.setBazList(l); 
    } 
} 

public interface Bar<BAZ extends Number> { 
    public BAZ makeBaz(Object arg1); 
    public List<BAZ> getBazList(); 
    public void setBazList(List<BAZ> baz); 
} 

public class BarConcreate implements Bar<BigDecimal>{ 
    long counter = 1; 

    private List<BigDecimal> list = new ArrayList<BigDecimal>(); 
    public List<BigDecimal> getBazList() { 
     return list; 
    } 


    public BigDecimal makeBaz(Object arg1) { 
     return BigDecimal.valueOf(counter++); 
    } 

    public void setBazList(List<BigDecimal> baz) { 
     list = baz;   
     for(BigDecimal d : baz){ 
      logger.debug("value:" + d.toString()); 
     } 
    } 

} 


public void TestFooBar(){ 
    Foo<Bar<BigDecimal>> foo = new Foo<Bar<BigDecimal>>(); 
    Bar<BigDecimal> bar = new BarConcreate(); 
    foo.t(bar); 
} 

Cette java compile et fonctionne si la liste est seulement remplie de BigDecimal tout fonctionne si la liste a un nombre entier, il nous obtenons une classe cast exception sur la ligne x.setBazList (l);

Je trouve cela très intéressant.

+1

qui ne vérifie pas le type, comme x.setBazList() veut une liste pas une liste newacct

+0

Il compile et s'exécute, ce que je trouve un peu étrange, mais j'ai vérifié avant d'ajouter la réponse. –

0

Je pencherais pour cela si vous le souhaitez:

List<Number> l = new ArrayList<Number>(); 
Number baz = x.makeBaz(null); 

Hope this helps.

EDIT: Aussi ce sens:

public class Foo<BAR extends Bar<? extends Number>> 
+1

qui va rencontrer des problèmes quand vous arrivez à x.setBazList (l) – newacct