Problème de casting avec les ArrayList
Résolu
Pumbaa
-
ouechTonton Messages postés 13 Statut Membre -
ouechTonton Messages postés 13 Statut Membre -
Bonjour, j'ai un gros problème, j'essaye de faire une méthode générique qui clone en profondeur une ArrayList (donc qui clone chaque objet, pas seulement la liste elle-même) mais je n'arrive pas à le faire "proprement".
Voici une partie de mon programme :
/* L'interface */
public interface MyClonable
{
public MyClonable myClone();
}
/* La classe qui implémente l'interface */
public class Process implements MyClonable
{
public Process(Process source)
{
/* bla bla */
}
public Process myClone()
{
return new Process(this);
}
}
/* La méthode de clonage proprement dite */
public class Tools
{
public static ArrayList<MyClonable> deepClone(ArrayList<MyClonable> source)
{
ArrayList<MyClonable> clone = new ArrayList<MyClonable>(source.size());
for(MyClonable o:source)
clone.add(o.myClone());
return clone;
}
}
/* L'utilisation */
ArrayList<MyClonable> listSource = {...}; // Elle est déjà pleine
ArrayList<Process> listProcess = Tools.deepClone(listSource);
/* Problème : le compilateur me retourne : "The method deepClone(ArrayList<MyClonable>) in the type Tools is not applicable for the
arguments (ArrayList<Process>)"*/
Et je ne comprends pas du tout pourquoi. Avec un pote nous avons essayé de nombreuses idées, mais rien ne marche.
De tête nous avons testé :
- un casting : ArrayList<Process> listProcess = Tools.deepClone((ArrayList<MyClonable>)listProcess); --> Erreur, impossible de caster
- définir autrement le prototype de la méthode de clonage : public static ArrayList<? extends MyClonable> deepClone(ArrayList<? extends MyClonable> source) --> Erreur, Type mismatch: cannot convert from ArrayList<capture#1-of ? extends MyClonable> to
ArrayList<Process>
- plein d'autres trucs.
Le seul qui marche, c'est de ne mettre nul part le type de la collection : public static ArrayList deepClone(ArrayList source)
mais ça me met des warning partout (dans le prototype de la fonction, et dans son appel.
Auriez-vous une solution plus belle svp ?
D'avance merci
Pumbaa
Voici une partie de mon programme :
/* L'interface */
public interface MyClonable
{
public MyClonable myClone();
}
/* La classe qui implémente l'interface */
public class Process implements MyClonable
{
public Process(Process source)
{
/* bla bla */
}
public Process myClone()
{
return new Process(this);
}
}
/* La méthode de clonage proprement dite */
public class Tools
{
public static ArrayList<MyClonable> deepClone(ArrayList<MyClonable> source)
{
ArrayList<MyClonable> clone = new ArrayList<MyClonable>(source.size());
for(MyClonable o:source)
clone.add(o.myClone());
return clone;
}
}
/* L'utilisation */
ArrayList<MyClonable> listSource = {...}; // Elle est déjà pleine
ArrayList<Process> listProcess = Tools.deepClone(listSource);
/* Problème : le compilateur me retourne : "The method deepClone(ArrayList<MyClonable>) in the type Tools is not applicable for the
arguments (ArrayList<Process>)"*/
Et je ne comprends pas du tout pourquoi. Avec un pote nous avons essayé de nombreuses idées, mais rien ne marche.
De tête nous avons testé :
- un casting : ArrayList<Process> listProcess = Tools.deepClone((ArrayList<MyClonable>)listProcess); --> Erreur, impossible de caster
- définir autrement le prototype de la méthode de clonage : public static ArrayList<? extends MyClonable> deepClone(ArrayList<? extends MyClonable> source) --> Erreur, Type mismatch: cannot convert from ArrayList<capture#1-of ? extends MyClonable> to
ArrayList<Process>
- plein d'autres trucs.
Le seul qui marche, c'est de ne mettre nul part le type de la collection : public static ArrayList deepClone(ArrayList source)
mais ça me met des warning partout (dans le prototype de la fonction, et dans son appel.
Auriez-vous une solution plus belle svp ?
D'avance merci
Pumbaa
7 réponses
-
-
J'ai trouvé ceci comme explication et solution : http://tutorials.jenkov.com/java-generics/wildcards.html
En résumé, il faut écrire ce genre de code, avec des wildcards "?" :
public void test( ArrayList<? extends ClasseMere> argument) {
//Ton code
}
pour appeler cette méthode :
ArrayList<ClasseFille> liste;
test(liste);
Je ne connaissais pas ces wildcards. Je ne sais pas ce que les puristes en pense... mais j'achète ! -
-
C'est pour moi une abberation dans Java qui vient de me gêner également. Le problème est le suivant: Il est impossible de caster directement ArrayList<B> vers ArrayList<A> même si A est une super-classe ou une interface de B.
Pour pouvoir faire la conversion, il faut le faire en 2 étapes en passant par une ArrayList générique.
Tu n'est pas obligé d'utiliser une ArrayList générique partout, mais tu ne sauras pas éviter d'avoir un warning lors de la double conversion... -
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question -
Mouarf, au moins je ne suis pas le seul ^^
J'espère que ce "bug" sera fixé un jour, car comme tu le dis c'est un peu aberrant (à moins qu'on ne soit passé à côté de quelque chose...) -
C'est un peu tard pour répondre mais comme je suis tombé sur ce topic en cherchant à caster une liste ça peut servir à quelqu'un d'autre.
Si on a accès au code source de la fonction qui prend une liste générique en paramètre on peut faire comme ça :
public <T extends ClasseMere> T test(List<T> l) {
return l.get(0);
}
pour appeler cette méthode :
List<ClasseFille> l = ...;
ClasseFille x = test(l); // ça marche, pas besoin de caster ni la liste ni le résultat -
Il n'est jamais trop tard pour répondre ^^
Concernant ta solution, je ne comprends pas très bien. Aurais-tu l'amabilité de développer un petit peu stp ?
Par exemple, il manque le type à retourner dans ta fonction test, si j'ai bien compris.