Médiaforma

All posts tagged generics

Considérez le code suivant :

public class GenericsTypeAvant {

    private Object t;
     public Object get() {
        return t;
    }

    public void set(Object t) {
        this.t = t;
    }

    public static void main(String args[]){
        GenericsTypeAvant type = new GenericsTypeAvant();
        type.set(12);
        String str = (String) type.get();
    }
}
Ce code se compile correctement, mais il produit une erreur CassCastException à l’exécution. En effet, le nombre 12 ne peut pas être casté en un String :

 

 

Considérez maintenant le code suivant :

public class GenericsTypeMaintenant<T> {

    private T;

    public T get(){
        return this.t;
    }

    public void set(T t1){
        this.t=t1;
    }

    public static void main(String args[]){
        GenericsTypeMaintenant<String> type = new GenericsTypeMaintenant<>(); // Type String
        type.set("chaîne"); // OK

        GenericsTypeMaintenant<Integer> type1 = new GenericsTypeMaintenant<>(); //Type Integer
        type1.set(12); //OK
        //type1.set("abc"); //Invalide

        GenericsTypeMaintenant type2 = new GenericsTypeMaintenant(); //Type quelconque
        type2.set("texte"); //OK
        type2.set(10); //Valide

    }
}

Le type T est spécifié dans la classe :

public class GenericsTypeMaintenant<T>

Lors de l’instanciation d’un objet de classe GenericsTypeMaintenant, on définit le type de l’objet passé. Par exemple, un type String :

GenericsTypeMaintenant<String> type = new GenericsTypeMaintenant<>();

On passe alors un objet de type String au setter après l’instanciation de la classe :

type.set("chaîne");

Si on lui passe un autre type, une erreur sera déclenchée à la compilation.

Par exemple, cette instruction :

type.set(12);

Provoque une erreur à la compilation :

 

 

Lors de l’instanciation d’un objet GenericsTypeMaintenant, on peut aussi définir un type Integer :

GenericsTypeMaintenant<Integer> type1 = new GenericsTypeMaintenant<>();

 

Dans ce cas, les instructions suivantes ne produiront aucune erreur de compilation :

GenericsTypeMaintenant<Integer> type1 = new GenericsTypeMaintenant<>();
type1.set(12); //OK

 

Par contre, ces instructions provoqueront une erreur à la compilation :

GenericsTypeMaintenant<Integer> type1 = new GenericsTypeMaintenant<>();
type1.set("abc"); //Invalide

 

Si aucun type n’est spécifié :

GenericsTypeMaintenant type2 = new GenericsTypeMaintenant();

 

Une valeur de type quelconque peut être passée au setter. Ainsi, ces deux instructions sont correctes :

type2.set("texte");
type2.set(10);

Java – Generics

Categories: java
Comments: No

Les generics sont apparus avec la version 5 de Java. Ils ajoutent une vérification à la compilation pour éviter des erreurs de type ClassCastException à l’exécution.

Un premier exemple

Examinez ce code :

import java.util.ArrayList;
import java.util.List;

public class Generics {

    public static void main(String[] args) {
        List = new ArrayList();
        list.add("abc");
        list.add(new Integer(5));

        for(Object obj : list){
          //Ce casting conduit à une exception au runtime
          String str=(String) obj;
          //Traitement sur l’objet str
        }
    }
}

Voici l’erreur qui se produit à l’exécution :

 

 

 

Pour éviter ce type d’erreur, vous pouvez utiliser des generics. La définition de la collection se fait comme ceci :

import java.util.ArrayList;
import java.util.List;

public class Generics {

    public static void main(String[] args) {
      List<String> list1 = new ArrayList<String>();
      list1.add("abc");
      //Cette instruction produit une erreur à la compilation
      list1.add(new Integer(5));

      // Aucun casting n’est nécessaire
      // L’erreur ClassCastException est ainsi évitée
      for(String str : list1){
        //Traitement sur l’objet str
      }
    }
}

Il est également possible d’utiliser des generics dans des méthodes. Voici un exemple :

public class GenericsClass<T> {

    private T;

    public void ajouter(T t) {
        this.t = t;
    }

    public <U> void inspecter(U){
        System.out.println("T est de classe " + t.getClass().getName());
        System.out.println("U est de classe " + u.getClass().getName());
    }

    public static void main(String[] args) {
        GenericsClass<Integer> classeGenerique = new GenericsClass<Integer>();
        classeGenerique.ajouter(new Integer(100));
        classeGenerique.inspecter("un texte");
    }
}

Ici, on définit la classe GenericsClass de type générique <T>.

La méthode main() instancie l’objet GenericsClass classeGenerique de type Integer.

La méthode ajouter(T t) stocke la valeur 100 dans la variable privée t de type Integer.

La méthode inspecter() reçoit un objet u de type générique <U>. Elle affiche le type de la classe T et le type de la classe U.