Après la compilation, les types sont effacés.
Depuis T
n'est pas lié à un type spécifique, T
sera remplacé par Object
.
Donc, ce :
T[] arrItems = (T[]) currentItems.toArray((T[])...);
return arrItems;
ne créera pas et ne retournera pas un tableau du type spécifique utilisé par l'instance de la classe au moment de l'exécution, mais créera seulement un tableau de Object
.
Par ailleurs, en Collection.toArray()
vous ne pouvez passer ni un tableau ( new T[]
) car il n'est pas valable de créer un tableau générique .
Par conséquent, si vous voulez utiliser le toArray()
vous pouvez finalement seulement passer un tableau de Object
de cette façon :
Object[] arrayObject = values.toArray(new Object[currentItems.size()]);
Mais un tableau ne fonctionne pas comme un type de liste.
Un tableau d'un type spécifique ne peut pas être converti en un tableau d'un autre type, même si les éléments qu'il contient sont du type de la cible de la conversion.
Ainsi, vous ne pouvez pas lancer un tableau de Object
à un tableau d'un type spécifique, même si le tableau contient des éléments de ce type spécifique, par exemple.
Cela produira donc une ClassCastException :
clTag[] values = (clTag[]) arrayObject;
Pour résoudre votre problème :
Si vous pouvez utiliser Java 8, l'utilisation d'une interface fonctionnelle est vraiment une solution propre. Jorn Vernee a donné une très bonne réponse qui l'illustre.
Sinon, avant Java 8, la seule façon de créer un tableau du même type que le type paramétré utilisé dans une collection générique est :
1) Créer un nouveau tableau avec le type spécifié.
Le site java.lang.reflect.Array.newInstance(Class clazz, int length)
méthode permet de créer un tableau de la classe et de la longueur spécifiées.
2) Stocker la classe du type déclaré dans l'instance de la classe générique. Vous pouvez le faire en ajoutant un paramètre de classe dans le constructeur de celle-ci.
3) Le remplir à partir des éléments de la collection générique.
Un moyen simple est d'utiliser <Object, Object> Object[] java.util.Arrays.copyOf(Object[] original, int newLength, Class<? extends Object[]> newType)
mais elle n'est pas efficace car il faut d'abord convertir la collection en tableau avec la méthode toArray()
pour pouvoir le transmettre à la copyOf()
méthode.
Par exemple avec un générique List
vous pourriez écrire :
public class ZTagField<T> {
private class<T> clazz;
private List<T> list = new ArrayList<>();
public ZTagField (class<T> clazz){
this.clazz = clazz;
}
public T[] get() {
T[] array = (T[]) Array.newInstance(clazz, list.size());
Class<? extends Object[]> clazzArray = array.getClass();
array = (T[]) Arrays.copyOf(values.toArray(), values.size(), clazzArray);
return array;
}
}
Il fonctionne mais, comme on l'a dit, il n'est pas efficace.
Une solution plus efficace consisterait à itérer sur la liste et à ajouter des éléments dans le nouveau tableau au lieu d'utiliser l'option Arrays.copyOf()
:
public T[] get() {
T[] array = (T[]) Array.newInstance(clazz, list.size());
for (int i = 0; i < values.size(); i++) {
array[i] = values.get(i);
}
return array;
}