Les génériques permettent de paramétrer des classes, interfaces ou méthodes avec des types abstraits, résolus dynamiquement lors de l'instanciation ou de l'appel. Introduits à partir de Java 5, ils renforcent la sécurité typée et réduisent les erreurs d'exécution.
Déclaration et utilisation
Avant Java 7, la syntaxe exigeait de répéter le type générique à la création d’objet. Depuis, l’opérateur diamant <> simplifie cette écriture :
List<String> mots = new ArrayList<>();
Classes et interfaces génériques personnalisées
Il est possible de définir ses propres structures génériques. Le constructeur n’a pas besoin de spécifier le paramètre de type :
private static class Boite<T> {
private Boite() {}
}
private static interface Stockable<E> {
void afficher();
}
Utilisation :
Boite<Integer> numerique = new Boite<>();
Héritage avec types génériques
Une classe enfant peut implémenter une interface générique soit en conservant le paramètre, soit en le fixant :
private static class Element implements Stockable {
public void afficher() {}
}
private static class Texte implements Stockable<String> {
public void afficher() {}
}
Wildcard (type inconnu)
Le symbole ? représente un type indéterminé, utile pour manipuler des collections sans connaître leur type exact :
List<?> elements = obtenirListe();
Princiep fondamental : si le code compile sans avertissement, aucune ClassCastException ne surviendra à l’exécution.
Bornes supérieures
On peut restreindre les types acceptés via extends. Cela s’appliqeu aussi bien aux wildcards qu’aux paramètres de type :
private static class Lecteur {
public void lire(List<? extends Element> items) {}
}
private static class Conteneur<T extends CharSequence> {}
private static class Archive<T extends String & Serializable> {}
Méthodes génériques
Les méthodes peuvent elles-mêmes déclarer des paramètres de type, placés entre le modificateur et le type de retour :
private static class Util {
private <T extends Number> void traiter(T valeur) {}
}
Borne inférieure avec super
Permet d’accepter un type ou ses superclasses :
private static class Injecteur {
private <T> void injecter(List<? super T> cible) {}
}
Réflexion et génériques
Depuis Java 5, la classe Class supporte les génériques (Class<T>), évitant ainsi les casts explicites lors de l’utilisation de la réflexion.
Avantages principaux
- Vérification des types à la compilation
- Élimination des
ClassCastExceptionà l’exécution - Code plus lisible et maintenable