Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Définition de méthodes génériques

Apprendre à coder une classe générique Introduction à la réflexion Java



Accès rapide :
La vidéo
Définition de méthodes génériques sur classes normales
Valeur de retour basée sur un type générique

La vidéo

Cette vidéo vous apprend à coder des méthodes génériques sur des classes non génériques. Elle vous montre aussi comment restreindre les types autorisés par la généricité.


Définition de méthodes génériques

Définition de méthodes génériques sur classes normales

Pour rappel, depuis la version 5.0 du Java SE, il est possible de faire de la programmation générique en Java. Dans le chapitre précédent, nous avons vu comment définir des classes génériques, ces classes contenant des méthodes génériques. Mais, il est aussi possible de coder des méthodes génériques sur des classes qui ne le sont pas.

L'exemple de code suivant permet de remplir une collection générique à partir des éléments contenus dans un tableau. La cohérence des types des données du tableau et de la collection est garantie par l'utilisation de la généricité. Si vous utilisez des types différents, une erreur de compilation sera produite. Deux scénarios de tests sont lancés sur notre méthode générique : l'un avec des chaînes de caractères et l'autre avec des données flottantes.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class DemoGenerics {
          
    // La méthode générique : elle rapatrie les éléments d'un tableau dans une collection.
    public static <T> void fromArrayToCollection( T[] array, Collection<T> collection ) {
        for ( T element : array ) {
            collection.add(element); 
        }
    }
    
    // On teste notre méthode générique avec des chaînes de caractères.
    public static void tryWithStrings() {
        String [] messages = {
                "Hello", "World", "End"
        };
        
        List<String> messageList = new ArrayList<>();
        fromArrayToCollection( messages, messageList );
        
        for( String message : messageList ) {
            System.out.println( message );
        }
    }

    // On teste notre méthode générique avec des nombres flottants.
    public static void tryWithDoubles() {
        Double [] values = {
                20.5, 78.2, 13.8, 47.4, 63.1
        };
        
        List<Double> valueList = new ArrayList<>();
        fromArrayToCollection( values, valueList );
        
        for( double message : valueList ) {
            System.out.println( message );
        }
    }

    // On lance nos tests.
    public static void main( String [] args ) {
        tryWithStrings();
        System.out.println( "----------------" );
        tryWithDoubles();
    }
        
}
Exemple de définition d'une méthode générique sur une classe non générique

Et voici les résultats produits par cet exemple :

Hello
World
End
----------------
20.5
78.2
13.8
47.4
63.1

Valeur de retour basée sur un type générique

Dans ce premier exemple, nous allons coder une méthode dont le type de retour dépend du type de l'un de ses paramètres pour produire des objets de natures diverses. En voici un petit exemple.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
import java.lang.reflect.Constructor;
import java.util.Date;

import javax.swing.JButton;

public class DemoGenerics {
    
    // La méthode générique : elle produit une instance en fonction
    // de la méta-classe passée en paramètre.
    public static <T> T createInstance( Class<T> metadata ) throws Exception {
        Constructor<T> constructor = metadata.getDeclaredConstructor();
        constructor.setAccessible( true );
        return constructor.newInstance();        
    }
    
    // Quelques tests.
    public static void main( String[] args ) throws Exception {
        Date date = Demo.createInstance( Date.class );
        System.out.println( date );

        JButton button = Demo.createInstance( JButton.class );
        System.out.println( button );
    }
    
}
Exemple de définition d'une méthode avec une valeur de retour basée sur un type générique
dans le main, aucun cast n'est nécessaire étant donné que le type de retour de la méthode est dépendant du type du paramètre de la méthode.

Il est aussi possible d'utiliser l'inférence de type (la déduction de type) opérée par le compilateur. Le compilateur peut déduire la nature du type générique en fonction du type de la variable à qui la valeur de retour de votre méthode générique est affectée. En voici un exemple.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
import java.awt.Component;
import java.util.Hashtable;

import javax.swing.JButton;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class DemoGenerics {
    
    private Hashtable<String, Component> components = new Hashtable<>();
    
    public DemoGenerics() {
        components.put( "txtLogin", new JTextField() );
        components.put( "txtPassword", new JPasswordField() );
        components.put( "btnConnect", new JButton() );
    }
    
    // La méthode générique (la généricité porte sur son type de retour).
    @SuppressWarnings( "unchecked" )            // Utile pour supprimer un warning.
    public <T extends Component> T findComponentByName( String name ) throws Exception {
        return (T) components.get( name );        
    }
    
    // Quelques tests de notre méthode générique
    public static void main( String[] args ) throws Exception {
        
        DemoGenerics container = new DemoGenerics();

        JTextField txtLogin = container.findComponentByName( "txtLogin" );
        System.out.println( txtLogin );

        JPasswordField txtPassword = container.findComponentByName( "txtPassword" );
        System.out.println( txtPassword );

        JButton btnConnect = container.findComponentByName( "btnConnect" );
        System.out.println( btnConnect );
        
        // Produit une exception de type ClassCastException
        JButton testErreur = container.findComponentByName( "txtLogin" );
    }
    
}
Inférence de type sur une valeur de retour générique
il faut néanmoins noter qu'une telle méthode ne permet pas de récupérer des méta-données sur le type générique (T.class) et ne permet pas d'instancier un élément basé sur le type générique (new T()).


Apprendre à coder une classe générique Introduction à la réflexion Java