Java Generics: Description et méthodes
Depuis l'apparition même de la langue Java a subibeaucoup de changements qui, sans aucun doute, ont apporté des moments positifs à sa fonctionnalité. Un tel changement significatif est l'introduction de Java Generic ou la généralisation. Cette fonctionnalité a rendu le langage non seulement plus flexible et polyvalent, mais aussi beaucoup plus sûr en termes de réduction des types de données.
Le fait est que, avant l'introduction de génériques génériquesle code en Java n'a pu être créé que par référence au type d'objet. De tels liens peuvent être assignés à n'importe quel objet. Après tout, les classes Java sont les héritiers implicites de classe d'objets. Cependant, cette approche est une source potentielle de nombreuses erreurs liées aux types de sécurité dans la conversion apparente d'un objet à partir de l'objet du type de cible. Lors de l'utilisation des généralisations toutes les moulages sont effectuées implicitement et automatiquement, éliminant même le risque d'erreurs.
Java Generics: description et exemple
Prenons un exemple simple d'application de la généralisation à la classe habituelle dans la figure ci-dessous. Et seulement alors nous allons procéder à un examen détaillé de toutes les subtilités et les nuances de Java Generic.
Remarquez comment lePair annonce de classe. Juste après le nom de classe, les crochets sont ouverts, dans lesquels est indiquée la lettre T. C'est une sorte d'espace réservé qui sera remplacé par un type spécifique lors de la création d'une instance de cette classe. Cela ressemble à ceci: Pair <Entier> obj = new Pair <Entier> (). Il convient de noter qu'au lieu de T, vous pouvez spécifier n'importe quelle lettre, mais, en règle générale, utiliser T, V ou E.
Note: en commençant par la huitième version de Java, en spécifiant le type de cible lorsque le lien est déclaré, vous pouvez laisser les chevrons du constructeur vides. Donc, l'exemple ci-dessus peut être réécrit comme suit: Pair <Integer> obj = new Pair <> ().
Quand une classe est déclarée de cette façon, alors dans sonVous pouvez utiliser cette lettre à la place des types de champs spécifiques, des références et des méthodes renvoyés par les méthodes. Comme T est remplacé par un type spécifique lors de la création d'un objet de classe, les premier et deuxième champs dans ce cas seront de type Entier.
Suivant la logique, les arguments firstItem et secondItem,transmis au constructeur correspondant, doit également être de type Integer ou sa sous-classe. Si vous essayez de transmettre un type de données différent de ce qui a été spécifié lors de la création de l'objet, le compilateur n'ignore pas cette erreur. Ainsi, le constructeur avec des arguments lors de la création de l'objet aura la forme suivante: Pair <Entier> obj = new Pair <> (nouveau Entier (1), nouveau Entier (2)). La même chose s'applique aux arguments des méthodes setFirst et setSecond. Et comme vous l'avez probablement déjà deviné, les méthodes getFirst et getSecond renverront des valeurs de type Integer.
Une classe générique avec plusieurs paramètres de type
Dans les classes génériques, vous pouvez également déclarer plusieurs paramètres de type spécifiés entre crochets séparés par des virgules. La classe Pair pour ce cas est présentée dans la figure ci-dessous.
Comme vous pouvez le voir, lors de la création d'une instance d'une telle classeDans les chevrons, vous devez spécifier le même nombre de types que les paramètres. Si vous connaissez un tel type de structure de données que Map, vous remarquerez peut-être que le même principe est utilisé ici. Là, le premier argument détermine le type de la clé, et le second - le type de la valeur. Il convient de noter que les types d'arguments passés à la création d'objet peuvent être les mêmes. Ainsi, la déclaration suivante d'une instance de la classe Pair est absolument correcte: Pair <String, String> obj.
Quelques caractéristiques des généralisations
Avant d'aller plus loin, il convient de noter queLe compilateur Java ne crée pas de versions différentes de la classe Pair. En fait, pendant le processus de compilation, toutes les informations sur le type générique sont supprimées. Au lieu de cela, les types correspondants sont castés, créant une version spéciale de la classe Pair. Cependant, le programme lui-même a toujours une seule version généralisée de cette classe. Ce processus est appelé dans le nettoyage de type Java Generic.
Notons un point important. Les références à différentes versions de la même classe générique java ne peuvent pas pointer vers le même objet. Autrement dit, disons que nous avons deux liens: Pair <Integer> obj1 et Pair <Double> obj2. Par conséquent, une erreur se produit dans la ligne obj1 = obj2. Bien que les deux variables soient de type Pair <T>, les objets auxquels elles se réfèrent sont différents. Ceci est un exemple frappant de la sécurité des types dans Java Generic.
Restrictions imposées aux classes généralisées
Il est important de savoir que les généralisations peuvent être appliquéesuniquement pour référencer les types, c'est-à-dire que l'argument passé à l'argument de classe générique java doit être un type de classe. Des types simples tels que, par exemple, double ou long, ne peuvent pas être transmis. En d'autres termes, la ligne de déclaration de classe Pair suivante n'est pas valide: Pair <int> obj. Cependant, cette limitation n'est pas un problème sérieux, puisque Java a une classe wrapper correspondante pour chaque type primitif. Strictement parlant, si vous voulez encapsuler un entier et une valeur logique dans la classe Pair, l'auto-pack fera tout pour vous: Pair <Entier, Booléen> obj = new Pair <> (25, true).
Une autre limitation sérieuse est laimpossibilité de créer une instance d'un paramètre de type. Ainsi, la ligne suivante provoquera une erreur de compilation: T first = new T (). Ceci est évident, puisque vous ne savez pas à l'avance si une classe complète ou une interface abstraite sera passée en argument. La même chose vaut pour la création de tableaux.
Types limités
Assez souvent, il y a des situations oùIl est nécessaire de limiter la liste des types pouvant être passés en argument à la classe générique java. Supposons que dans notre classe Pair, nous voulons encapsuler exclusivement des valeurs numériques pour d'autres opérations mathématiques sur eux. Pour ce faire, nous devons définir la limite supérieure du paramètre type. Ceci est implémenté en utilisant une déclaration de superclasse héritée par tous les arguments passés entre les chevrons. Cela ressemblera à ceci: class Pair <T extends Number>. De cette façon, le compilateur apprend qu'à la place du paramètre T, vous pouvez substituer la classe Number ou l'une de ses sous-classes.
C'est une technique courante. Ces restrictions sont souvent utilisées pour assurer la compatibilité des paramètres de type dans la même classe. Prenons un exemple sur notre classe Pair: classe Pair <T, V extend T>. Ici, nous disons au compilateur que le type T peut être arbitraire et que le type V doit être de type T ou une de ses sous-classes.
La restriction "d'en bas" se produit exactement de la même manièreimage, mais au lieu du mot étend, le mot super est écrit. En d'autres termes, la déclaration de la classe Pair <T super ArrayList> indique qu'au lieu de T, une ArrayList ou toute classe ou interface héritée peut être substituée.
Méthodes Java génériques et constructeurs
En Java, des généralisations peuvent être appliquées non seulement aux classes, mais aussi aux méthodes. Ainsi, la méthode généralisée peut être déclarée dans la classe ordinaire.
Comme vous pouvez le voir sur la figure ci-dessus, la déclaration de la méthode généralisée n'a rien de compliqué. Il suffit de placer les crochets avant la méthode de type de retour et de spécifier les paramètres de type.
Dans le cas du constructeur, tout se fait de la même manière:
Les crochets angulaires dans ce cas sont placés avant le nom du constructeur, car il ne renvoie aucune valeur. Le résultat du travail des deux programmes sera:
Entier
Ficelle