Maison  >  Article  >  Java  >  Java – Génériques

Java – Génériques

巴扎黑
巴扎黑original
2017-06-27 09:13:571823parcourir

Utilisez des crochets angulaires pour spécifier les paramètres de type formel. La relation entre les paramètres de type formel et les paramètres de type réels est similaire à la relation entre les paramètres de méthode formelle et les paramètres de méthode réels, sauf que les paramètres de type représentent des types plutôt que des valeurs.

Paramètres de type nommés

La convention de dénomination recommandée consiste à utiliser des noms majuscules à une seule lettre pour les paramètres de type. Cela diffère de la convention C++ (voir Annexe A : Comparaison avec les modèles C++) et reflète l'hypothèse selon laquelle la plupart des classes

génériques

auront un petit nombre de paramètres de type. Pour le modèle

générique commun, le nom recommandé est : K - clé, telle qu'une clé mappée. V - Valeur, telle que le contenu de List et Set, ou la valeur dans Map.

E ——Classe d'exception.

T ——

Générique

.


1. Pourquoi utiliser des génériques

方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。

1. Il n'y a aucune limite quant aux éléments pouvant être insérés. L'insertion de deux objets différents peut provoquer des exceptions.

2. Jetez l'objet dans la collection. La collection perd les informations d'état de l'objet. La collection sait seulement qu'elle contient l'objet, donc après l'avoir retiré. les éléments de collection, la conversion forcée est généralement également requise

2. Que sont les génériques

Les types paramétrés de Java sont appelés génériques, qui permettent au programme de spécifier le type d'éléments de collection lors de la création d'une collection

3. La syntaxe générique du diamant

doit seulement être suivie d'une paire de supports en diamant, pas besoin pour les génériques

4. Créez une classe personnalisée avec une déclaration générique lors de la définition d'un constructeur pour la classe, le nom du constructeur doit toujours être le nom de la classe d'origine. .

5. Dériver une sous-classe d'une classe générique Lors de l'héritage, vous devez transmettre les paramètres réels de la classe parent

la classe publique A étend Applef7e83be87db5cd2d9a8a0b8117b38cd4{}

Toutes les méthodes qui remplacent la classe parent deviennent le type correspondant

Vous pouvez également transmettre aucun paramètre réel

la classe publique A étend Apple{}

Traité comme type d'objet

6.

Peu importe les paramètres de type réels d'un générique, ils ont toujours la même classe au moment de l'exécution. Quel que soit le type de paramètre réel passé dans le paramètre de type générique, (

réside dans le but du concept de génériques en Java, ce qui l'amène à n'agir que dans la phase de compilation du code. Pendant le processus de compilation , Une fois le résultat générique correctement vérifié, les informations pertinentes du générique seront effacées, c'est-à-dire que le fichier de classe compilé avec succès ne contient aucune information générique et les informations génériques n'entreront pas dans l'étape d'exécution

<.>.) Pour Java, ils sont toujours traités comme la même classe et occupent un espace mémoire dans la mémoire. Par conséquent, les types ne peuvent pas être utilisés dans la déclaration et l'initialisation de méthodes statiques, de blocs d'initialisation statiques ou de variables formelles statiques. paramètres

                                                                                     

Les variables statiques sont partagées par toutes les instances d'une classe générique. Pour une classe déclarée comme MyClass8742468051c85b06f0a0af9e3e506b5c, la méthode permettant d'accéder aux variables statiques qu'elle contient est toujours MyClass.myStaticVar. Que les objets soient créés via le nouveau MyClassf7e83be87db5cd2d9a8a0b8117b38cd4 ou le nouveau MyClassc0f559cc8d56b43654fcbe4aa9df7b4a, ils partagent tous une variable statique. Supposons que les paramètres de type soient autorisés en tant que types de variables statiques. Considérons ensuite la situation suivante :

MaClassef7e83be87db5cd2d9a8a0b8117b38cd4 class1 = nouvelle MaClassef7e83be87db5cd2d9a8a0b8117b38cd4();

MaClassec0f559cc8d56b43654fcbe4aa9df7b4a ;Integer>();

class1.myStaticVar = "bonjour";

class2.myStaticVar = 5;

En raison de l'effacement du type du générique système Sauf (type effacement). myStaticVar est restauré au type Object, puis lorsque class1.myStaticVar= "hello"; est appelé, le compilateur effectue une conversion de type forcée, c'est-à-dire myStaticVar = (String)"hello"; appelé, le compilateur continue d'effectuer une conversion de type forcée. , myStaticVar = (Integer)Integer.valueOf(5); À ce stade, myStaticVar est de type String. Bien sûr, cette instruction lancera une exception ClassCastException au moment de l'exécution. tapez un problème de sécurité. Par conséquent, le système générique ne permet pas aux variables statiques d’une classe d’utiliser des paramètres de type comme types de variables.

Les classes génériques ne seront pas réellement générées dans le système, donc la classe générique ne peut pas être utilisée après l'opérateur instanceod car elle n'existe pas du tout !

7. Tapez des caractères génériques

Notez que, si Foo est un sous-type de Bar et G est une classe ou une interface avec une déclaration générique, G4ee996100bf04ab273e687539c860625 n'est pas un sous-type de Gad40e550a33cb99ea30eede96e03e60e.

En supposant que Lista87fdacec66f0909fc0757c19f2d2b1d peut être logiquement considérée comme la classe parent de Listf7e83be87db5cd2d9a8a0b8117b38cd4, alors a.test(list) n'aura pas d'erreur message , alors la question se pose : de quel type sont les données lorsqu'elles sont récupérées via la méthode getData() ? Entier ? Flotteur ? Ou Objet ? Et en raison de l'ordre incontrôlable du processus de programmation, un jugement de type et une conversion de type forcée doivent être effectués lorsque cela est nécessaire. Évidemment, cela contredit le concept de génériques. Par conséquent, ne peut logiquement pas être considéré comme la classe parent de Listf7e83be87db5cd2d9a8a0b8117b38cd4

Afin de représenter la classe parent de diverses collections génériques, vous pouvez utiliser des caractères génériques de type, qui sont un point d'interrogation, il peut correspondre à n'importe quel type :

Les caractères génériques de type sont généralement utilisés à la place des paramètres réels de type spécifique. Notez que voici les paramètres de type réels, pas les paramètres de type ! Et List6b3d0130bba23ae47fe2b8e8cddf0195 est logiquement la classe parent de Listc0f559cc8d56b43654fcbe4aa9df7b4a, Lista106241f68edc629be816c498f304ade... et de tous les Listccac514f3cd2fbbe834b6166404c038e. À partir de là, nous pouvons encore définir des méthodes génériques pour répondre à ces exigences.

Quel que soit le type réel de la liste, elle contient un objet

Remarque : avec des caractères génériques, cela signifie uniquement C'est la classe parent de diverses collections génériques et ne peut pas y ajouter d'éléments

ne connaît pas le type d'éléments de la collection c et ne peut pas y ajouter d'objets

7.1 Définir la limite supérieure des caractères génériques

Étant donné que Listc13078eef089064b7e80988f58350b9c n'est pas un sous-type de List5c58ee79afe736c10ab537fb5aaf549d, une erreur de compilation se produit

Ceci peut être recyclé. Utilisez des caractères génériques restreints

7.2 Définir la limite supérieure des paramètres de type

8. Méthodes génériques

Définir la classe, les paramètres de type ne sont pas utilisés dans l'interface lors de la définition des méthodes, je souhaite définir

méthodes statiques génériques indépendantes en même temps sans considérer plusieurs. -threading.point, il ne sera initialisé et appelé qu'une seule fois, il n'y aura pas d'initialisation superposée ni d'appels incorrects, et il n'y aura pas de situation comme la lecture de données sales dans la base de données, donc il n'y aura pas d'erreurs de code dans la conversion de type forcée.

Les paramètres formels définis dans la déclaration de la méthode ne peuvent être utilisés que dans cette méthode.

Contrairement aux classes et aux interfaces, les génériques dans les méthodes n'ont pas besoin d'afficher les paramètres de type réels transmis

Le compilateur ne doit pas être confus quant au type que vous transmettez

Pour exemple, test

Si vous transmettez un type String ou un type Object, le compilateur ne sait pas de quel type est votre T

Peut-il être modifié en 4572a4dc4b16be705a6ff1398c43c189 a, Collection8742468051c85b06f0a0af9e3e506b5c

Méthode générique

(dans le paramètre de type une section) Vous avez vu que vous pouvez rendre une classe générique en ajoutant une liste de paramètres de type formel à sa définition. Les méthodes peuvent également être génériques, que la classe dans laquelle elles sont définies soit générique ou non.

Les classes génériques appliquent des contraintes de type sur plusieurs signatures de méthodes. Dans Listd94943c0b4933ad8cac500132f64757f, le paramètre de type V apparaît dans les signatures de méthodes telles que get(), add(), contain(), etc. Lorsque vous créez une variable de type Mapb56561a2c0bc639cf0044c0859afb88f, vous déclarez une contrainte de type entre les méthodes. La valeur que vous transmettez à add() sera du même type que la valeur renvoyée par get().

De même, une méthode générique est généralement déclarée car vous souhaitez déclarer une contrainte de type sur plusieurs paramètres de la méthode. Par exemple, la méthode ifThenElse() dans le code suivant renverra soit le deuxième, soit le troisième paramètre en fonction de la valeur booléenne de son premier paramètre :

public 8742468051c85b06f0a0af9e3e506b5c T ifThenElse(booléen b, T premier, T seconde) {
retour b : seconde ;
}

Notez que vous pouvez appeler ifThenElse() sans indiquer explicitement au compilateur ce que vous voulez pour la valeur T. Le compilateur n'a pas besoin de savoir explicitement quelles valeurs T aura ; il sait simplement que les valeurs doivent toutes être les mêmes. Le compilateur vous permet d'appeler le code suivant car le compilateur peut utiliser l'inférence de type pour déduire que la chaîne substituée à T satisfait toutes les contraintes de type :

String s = ifThenElse(b, "a", "b");

De même, vous pouvez appeler :

Integer i = ifThenElse(b, new Integer(1), new Integer(2));

Cependant, compilation Le code suivant n'est pas autorisé par le compilateur car aucun type ne satisferait les contraintes de type requises :

String s = ifThenElse(b, "pi", new Float ( 3.14));

Pourquoi avez-vous choisi d'utiliser une méthode générique au lieu d'ajouter le type T à la définition de la classe ? Il y a (au moins) deux cas où cela doit être fait :

Lorsqu'une méthode générique est statique, les paramètres de type classe ne peuvent pas être utilisés dans ce cas.

Lorsqu'une contrainte de type sur T est vraiment locale à une méthode, cela signifie qu'il n'y a pas d'utilisation du même type T dans une autre signature de méthode du même contrainte de classe. La signature d'un type fermé peut être simplifiée en rendant les paramètres de type d'une méthode générique locaux à la méthode.


Type restreint

Méthode générique dans l'écran précédent Dans l'exemple , le paramètre de type V est un type sans contrainte ou sans restriction. Il est parfois nécessaire de spécifier des contraintes supplémentaires sur les paramètres de type lorsque ceux-ci n'ont pas été entièrement spécifiés.

Considérez l'exemple de classe Matrix, qui utilise un paramètre de type V, qui est délimité par la classe Number :

classe publique Matrixae0232c3244c2cc6df973fad5b129c33 { ... }

Le compilateur vous permet de créer Matrixc0f559cc8d56b43654fcbe4aa9df7b4a ;Float>, mais si vous essayez de définir une variable de type Matrixf7e83be87db5cd2d9a8a0b8117b38cd4, une erreur se produira. Le paramètre de type V est évalué comme étant limité par Number . En l'absence de restrictions de type, les paramètres de type sont supposés être restreints par Object. C'est pourquoi l'exemple de l'écran précédent, Méthodes génériques, permet à List.get() de renvoyer Object lorsqu'il est appelé sur une List6b3d0130bba23ae47fe2b8e8cddf0195, même si le compilateur ne connaît pas le type du paramètre de type V.

9. La différence entre les méthodes génériques et les caractères génériques de type

Si une méthode Si le type de paramètre formel (a) ou le type de la valeur de retour dépend du type d'un autre paramètre formel (b), alors la déclaration de type du paramètre formel (b) ne doit pas utiliser de caractères génériques. Seuls les paramètres de type peuvent être déclarés dans la signature de la méthode. , c'est-à-dire une méthode générique.

Ce que je comprends, c'est que le caractère générique de type n'a pas besoin d'ajouter ou de modifier les éléments de la collection, et il est attaché aux autres plutôt qu'aux autres qui lui sont attachés. Utilisez .

Les caractères génériques de type peuvent être utilisés pour définir le type de paramètres formels dans les signatures de méthodes ou pour définir les types de variables dans les méthodes génériques doivent être explicitement déclarées dans la méthode correspondante.

10. Effacement et conversion

Lors de l'attribution d'un objet avec des informations génériques à un autre Lors de l'ajout d'un variable sans informations génériques, toutes les informations de type entre crochets angulaires sont supprimées.

Lors de l'attribution de li à List, le compilateur effacera le Les informations génériques du premier, c'est-à-dire perdre les informations de type des éléments de la collection de listes.

Java permet également à l'objet liste d'être directement affecté à une variable List30690cee1a11d5dfbdced93b89f678ee, de sorte que le programme peut être compilé et passé, mais émet uniquement une "conversion non vérifiée" (en modifiant la logique classe parent directement affectée à la sous-classe), mais la variable list fait en fait référence à la collection list, donc lorsque vous essayez de supprimer les éléments de la collection en tant qu'objet de type String, cela déclenchera un exécuter l'exception

11. Génériques et tableaux

Les génériques Java ont un principe de conception très important : si un morceau de code ne génère pas d'avertissement « exception non convertie » lors de la compilation, le programme ne provoquera pas d'exception ClassCastException. Pour cette raison, Le type de tous les éléments du tableau ne peut pas contenir de variables de type ou de paramètres de type, à moins qu'il ne s'agisse d'un caractère générique de type illimité, mais le type d'élément peut être déclaré comme contenant un tableau de variables de type ou de paramètres de type

En supposant que cela puisse passer, cela ne provoquera aucun avertissement, mais provoquera une exception

Changez au format suivant :

La première ligne aura un avertissement "conversion non vérifiée", et la dernière ligne lancera également une exception

Créer des caractères génériques illimités Le tableau générique

n'émettra aucun avertissement lors de la compilation, mais une exception sera levée au moment de l'exécution car le programme doit forcer le premier élément de collection du premier élément de tableau de type lsa Convert to String, le programme doit donc utiliser l'opérateur instanceof pour garantir son type de données

De même, créer un objet tableau dont le type d'élément est un type variable provoquera également une erreur de compilation

8742468051c85b06f0a0af9e3e506b5c T[] makeArray(Collection8742468051c85b06f0a0af9e3e506b5c coll)

{ return new T[cool.size()]

>

La variable de type n'existe pas au moment de l'exécution et le compilateur ne peut pas déterminer quel est le type réel

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn