Génériques
Limitez les éléments d'une collection à un type spécifique.
le terme
Quelques notes:
Les types paramétrés et les types primitifs sont compatibles entre eux
ArrayList Collection1 = new ArrayList <Integer> (); // Pass, pas de précaution avertissement
Les types paramétrés ne considèrent pas les relations de succession des paramètres de type
ArrayList <string> collection3 = new ArrayList <Bject> (); // La compilation ne passe pas ArrayList <Bject> Collection4 = new ArrayList <string> (); // La compilation ne passe pas
mais
ArrayList Collection5 = New ArrayList <Integer> (); ArrayList <string> Collection6 = Collection5; // compilé par
"?" Magazine
"?" signifie tout type. Utilisez le "?" caractère générique pour désigner divers types paramétrés. Il peut appeler des méthodes qui ne sont pas liées au paramétrage (telles que la méthode Taille ()) et ne peuvent pas appeler des méthodes liées à la paramétrage (telles que la méthode Add ())
Extension générique
Qualifier la limite supérieure des caractères génériques
ArrayList <? étend le numéro> collection1 = new ArrayList <Integer> (); // compiler par ArrayList <? étend le numéro> collection2 = new ArrayList <string> (); // compiler par non
Qualifier la limite inférieure des personnages génériques
ArrayList <? super entier> collection3 = new ArrayList <Nombre> (); // compiler par ArrayList <? super entier> collection4 = new ArrayList <string> (); // compiler par non
Méthodes génériques personnalisées
Fonctions du modèle C ++
modèle <class t> t add (t x, t y) {return (t) (x + y);}Les génériques Java sont essentiellement implémentés entièrement dans le compilateur, utilisés par le compilateur pour effectuer des vérifications de type et des jugements de type, puis générer des bytecodes non génériques ordinaires. Cette technique de mise en œuvre est "Erasure".
Instance "effacer"
Des génériques sont fournis au compilateur Javac pour définir le type d'entrée de la collection. Lorsque le compilateur compile une collection avec description de type, les informations "type" seront supprimées.
classe publique GenerICTEST {public static void main (String [] args) {new GenericTest (). TestType (); } public void testType () {ArrayList <Integer> collection1 = new ArrayList <Integer> (); ArrayList <string> collection2 = new ArrayList <string> (); System.out.println (collection1.getClass () == collection2.getClass ()); // Les types de classe des deux sont les mêmes, c'est-à-dire que le bytecode est le même System.out.println (collection2.getClass (). GetName ()); // La classe est java.util.arraylist, et il n'y a pas d'informations de paramètre de type réel}}Sortir
vrai
java.util.arraylist
Utilisez la réflexion pour ignorer le compilateur et ajouter d'autres types de données à une collection générique.
Seuls les types de référence peuvent être utilisés comme paramètres réels pour les méthodes génériques:
classe publique GenerICTEST {public static void main (String [] args) {swap (new String [] {"111", "222"}, 0,1); // compiler par // swap (new int [] {1,2}, 0,1); // compiler en ne compilant pas car int n'est pas le type de type de référence (nouvel entier [] {1,2}, 0,1); // compiler par} / * échangez les éléments i-th et jth du tableau a * / public static <t> void swap (t [] a, int i, int j) {t temp = a [i]; a [i] = a [j]; a [j] = temp; }}Mais notez que les types de base peuvent parfois être utilisés comme paramètres réels, car il y a un emballage et un déballage automatique. Exemple (compilé et passé):
classe publique GenerICTEST {public static void main (String [] args) {new GenericTest (). TestType (); int a = plus grande (3,5); // int et double, obtenez l'échange comme nombre de nombres b = plus grande (3,5,5); // String et int obtiennent l'interchange comme objet objet c = plus grand ("1", 2); } // retourner y de x, y public static <T> t Biggerone (t x, t y) {return y; }}Dans le même temps, cet exemple montre également que lorsque les paramètres réels sont incohérents, T prend l'intersection, c'est-à-dire la première classe de parent commune. De plus, si vous utilisez le numéro B = plus grande (3,5,5); à la chaîne C = plus grande (3,5,5); alors l'erreur de compilation est signalée:
Erreur: (17, 29) Java: Types incompatibles: Les types déduits ne répondent pas à l'inférence de la limite supérieure: java.lang.number & java.lang.comparable <? étend java.lang.number & java.lang.comparable <? >>
Limite supérieure: java.lang.string, java.lang.object
Mais il y a une chose que je n'ai pas compris. Je suis en train de déboguer étape par étape dans l'idée et j'ai constaté que le résultat est le suivant: Capture d'écran de débogage générique-1 Je ne sais pas pourquoi B est de type double (mais il compile et rapportera une erreur lors de la réception de la valeur de retour sur Double B). Je ne sais pas si cela a quelque chose à voir avec l'IDE. L'IDE affiche-t-il le type le plus précis de cet objet lors du débogage?
Type d'inférence des paramètres de type
Le processus par lequel le compilateur juge les paramètres de type réel d'une méthode générique est appelée inférence de type.
Lorsqu'une certaine variable de type n'est appliquée qu'une seule de tous les paramètres et des valeurs de retour dans la liste des paramètres entière, il est déterminé sur la base du type d'application réel à ce moment-là lorsque la méthode est appelée. C'est-à-dire que le type de paramètres génériques est directement déterminé en fonction du type de paramètre ou de la valeur de retour réalisée lorsque la méthode est appelée. Par exemple:
swap (nouvelle chaîne [3], 1,2) -> statique <e> void swap (e [] a, int i, int j)
Lorsqu'une variable de type est appliquée à plusieurs endroits dans tous les paramètres et les valeurs de retour de l'ensemble de la liste des paramètres, si de nombreux types d'applications réels correspondent au même type lors de l'appel de la méthode, le type du paramètre générique est ce type. Par exemple:
Ajouter (3,5) -> statique <T> t Add (t a, t b)
Lorsqu'une certaine variable de type est appliquée à de nombreux endroits dans tous les paramètres et les valeurs de retour de la liste des paramètres entière, si les types d'applications réels dans de nombreux endroits correspondent à différents types lors de l'appel de la méthode et qu'il n'y a pas de valeur de retour, le type d'intersection maximal entre les multiples paramètres, c'est-à-dire la première classe parent commune. Par exemple:
remplissage (nouvel entier [3], 3,5) -> statique <T> vide rempli (t a [], t v)
Le type correspondant réel de cet exemple est un nombre, compilé et exécuter des problèmes.
Lorsqu'une variable de type est appliquée à plusieurs endroits dans tous les paramètres et les valeurs de retour de l'ensemble de la liste des paramètres, si les types d'applications réels à tant d'endroits correspondent à différents types lors de l'appel de la méthode, et qu'il existe une valeur de retour, le type de la valeur de retour est donné prioritaire, par exemple:
int x = ajouter (3,3,5) -> statique <T> t Add (t a, t b)
L'exemple ci-dessus a compilé une erreur, et le type X est modifié pour Float a également rapporté une erreur, et le changement de numéro est réussi.
Des exemples d'inférence de type des types de paramètres sont transitifs:
Copie (Nouveau entier [5], nouvelle chaîne [5]) -> Static <T> void copie (t [] a, t [] b)
Cet exemple infère que le type de paramètre réel est objet et compilé.
copy (new ArrayList <string>, nouvel entier [5]) -> Static <T> void copie (collection <T> a, t [] b)
Cet exemple détermine directement la variable de type en tant que type de chaîne en fonction de l'instance de classe ArrayList paramétrée et rapporte une erreur dans la compilation.
Cours génériques personnalisés
exemple
classe publique genericdao <t> {public void add (t x) {} public t findbyid (int id) {return null; } public void delete (t obj) {} public void delete (int id) {} public void update (t obj) {} public t findByUserName (name de chaîne) {return null; } public <T> set <T> findByConditions (String Where) {return null; }}Remarque: Lorsqu'une variable est déclarée générique, elle ne peut être appelée que par les variables et les méthodes d'instance (et les types intégrés), mais pas par des variables statiques et des méthodes statiques. Étant donné que les membres statiques sont partagés par des classes paramétrées, les membres statiques ne doivent pas avoir de paramètres de type de niveau de classe.
Comparaison des méthodes génériques et des classes génériques
exemple:
Classe publique A <T> () {// Méthode membre de la classe générique, le T est limité par T suivant un public t membrefunc () {return null; } // Méthode générique, ici t et t sont différentes de t de la classe A public statique <t> t génériquefunc (t a) {return null; } public static void main (string [] args) {// compilé sans compilation // entier i = a <string> (). findByUsername ("s"); // compilé par set <Integer> set = a <string> (). FindByConditions ("s"); }}Ici entier i = a <string> (). FindByUserName ("s"); compilera et signalera une erreur:
Erreur: (35, 61) Java: Type incompatible: java.lang.string ne peut pas être converti en java.lang.integer
À partir de cet exemple, on peut voir que le T de la méthode générique et le T de la classe A sont différents.
Génériques et réflexions
Obtenez les paramètres de type réel d'un générique par réflexion
Utilisez des variables génériques comme paramètres de la méthode et utilisez la méthode GetGenericParameterTypes de la classe de méthode pour obtenir l'exemple de paramètre de type réel du générique:
classe publique GenerICTEST {public static void main (String [] args) lève l'exception {getParamType (); } / * Utiliser la réflexion pour obtenir le type de paramètre réel des paramètres de la méthode * / public static void getParamType () lève NosuchMetHodexception {méthode méthode = genedictest.class.getMethod ("applatmap", map.class); // Obtenez le type de paramètres génériques du type de méthode [] types = méthode.getGenericParameterTypes (); System.out.println (types [0]); // Type paramétré ParamètreType Ptype = (Parametezedype) Types [0]; // Type primitif System.out.println (ptype.getRawtype ()); // Type de type réel System.out.println (ptype.getactualTypeArguments () [0]); System.out.println (ptype.getactualTypeArguments () [1]); } / * Méthode pour tester les types de paramètres * / public static void appliquemap (map <Integer, string> map) {}}Résultat de sortie:
java.util.map <java.lang.integer, java.lang.string> interface java.util.mapclass java.lang.integerclass java.lang.string