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
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é.
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(); } } |
Et voici les résultats produits par cet exemple :
Hello World End ---------------- 20.5 78.2 13.8 47.4 63.1
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 ); } } |
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" ); } } |
T.class
) et ne permet pas
d'instancier un élément basé sur le type générique (new T()
).
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 :