« Generic array creation » — l'erreur qui exaspère tout développeur Java
\n\nAvez-vous déjà écrit quelque chose comme new T[10] et obtenu une vague rouge de la part du compilateur ? Si oui, vous n'êtes pas seul. La question « How can I create a generic array in Java? » sur Stack Overflow a recueilli des centaines de milliers de vues. Et ce n'est pas un hasard : créer un tableau générique en Java est l'un de ces sujets où la théorie diffère de la pratique, et où l'IDE refuse de comprendre ce que vous voulez.
Dans cet article, nous allons voir pourquoi Java interdit les tableaux génériques, comment contourner cette limitation sans perdre la sécurité de typage, et quand un tableau est préférable à un ArrayList. C'est parti !
Pourquoi new T[10] ne fonctionne-t-il pas ? La racine du mal : l'effacement de type
\n\nPour comprendre comment créer un tableau générique en Java, il faut d'abord saisir pourquoi le compilateur crie. Le problème vient du type erasure (effacement de type). Les génériques Java n'existent qu'au moment de la compilation. Pendant l'exécution, l'information sur le type T est effacée et remplacée par Object (ou par la borne, si elle est définie).
Les tableaux en Java, quant à eux, sont des types réifiables. Ils connaissent leur type de composant au moment de l'exécution. Ainsi, la JVM peut vérifier que vous ne placez dans le tableau que des éléments du type correct. Si vous pouviez écrire new T[10], le tableau serait un Object[] au moment de l'exécution, et vous pourriez y mettre un String, un Integer et un Date en même temps — ce qui viole toute l'idée de sécurité de typage.
C'est pourquoi le compilateur génère une erreur :
\n// ❌ Erreur de compilation : generic array creation\npublic class Box<T> {\n private T[] array = new T[10]; // Cannot create a generic array of T\n}\n\nMéthode 1 : La plus simple — utilisez ArrayList
\n\nLa plupart du temps, vous n'avez même pas besoin d'un tableau. ArrayList fonctionne en interne avec Object[], mais fournit une interface sécurisée au niveau des types. C'est la solution idéale si vous n'êtes pas obsédé par les performances à la nanoseconde près.
import java.util.ArrayList;\nimport java.util.List;\n\npublic class GenericListExample<T> {\n private List<T> list = new ArrayList<>();\n\n public void add(T item) {\n list.add(item);\n }\n\n public T get(int index) {\n return list.get(index);\n }\n\n public int size() {\n return list.size();\n }\n}\n\nAvantages : sécurité de typage totale, aucun avertissement, support de l'extension dynamique.
\nInconvénients : un léger surcoût pour l'encapsulation/décapsulation des primitives (mais pour 99% des applications, cela reste imperceptible).
Méthode 2 : L'astuce classique avec (T[]) new Object[size]
\n\nSi vous avez vraiment besoin d'un tableau (par exemple, pour les performances ou la compatibilité avec une API legacy), vous pouvez utiliser un cast de type. C'est sûr si vous garantissez que le tableau ne quitte jamais les limites de votre classe.
\n\npublic class Stack<T> {\n private T[] elements;\n private int size = 0;\n private static final int DEFAULT_CAPACITY = 10;\n\n @SuppressWarnings("unchecked")\n public Stack() {\n elements = (T[]) new Object[DEFAULT_CAPACITY];\n }\n\n public void push(T item) {\n if (size == elements.length) {\n resize();\n }\n elements[size++] = item;\n }\n\n public T pop() {\n if (size == 0) {\n throw new EmptyStackException();\n }\n T result = elements[--size];\n elements[size] = null; // Aide le GC\n return result;\n }\n\n private void resize() {\n elements = Arrays.copyOf(elements, elements.length * 2);\n }\n}\n\nImportant : l'annotation @SuppressWarnings("unchecked") est nécessaire pour supprimer l'avertissement du compilateur. Utilisez-la avec précaution et uniquement lorsque vous êtes certain de la sécurité.