Comprendre les génériques en Java SE

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

Étiquettes: Java génériques types-paramétrés Wildcard bornes-de-type

Publié le 10 septembre à 17h04