J'ai de nouveau fait des recherches sur les génériques ces derniers jours, alors après avoir donné un bref aperçu des génériques, j'ai décidé de résumer les deux contenus suivants sous forme de mémo.
Quoi qu'il en soit, je voudrais réorganiser les avantages de l'utilisation des génériques. Il ** vous avertira au moment de la compilation si vous essayez d'insérer un objet du mauvais type ** (cité dans Effective Java 3rd Edition Chapter 5 Generics). En conséquence, un traitement similaire peut être réalisé avec différents types dans la plage dans laquelle la sécurité de type peut être garantie. Maintenant, je voudrais montrer un exemple concret dans le code. Ici, je voudrais comparer des séquences et des génériques et reconnaître la bonté d'écrire dans les génériques. Écrivez la définition de la liste, l'ajout à la liste et l'extraction de la liste sans utiliser de génériques comme suit.
ArrayList list = new ArrayList();
list.add("hoge");
String s = (String) list.get(0);
Puisqu'il est extrait en tant que type Object, il est nécessaire de le convertir explicitement, et s'il y a une erreur (telle que l'affectation avec int et l'extraction avec String), vous ne remarquerez pas l'erreur à moins que vous ne la déplaciez. ← C'est très douloureux. Écrivez la définition de la liste à l'aide des génériques, l'ajout à la liste et l'extraction comme suit.
ArrayList<String> list = new ArrayList<String>();
list.add("hoge");
String s = list.get(0);
J'obtiens une erreur lors de la compilation. (Vous pouvez remarquer l'erreur avant de l'exécuter ← C'est très agréable)
Generics a deux portées. Portée de la méthode et portée de l'instance. Un aperçu est donné pour chacun.
Tout d'abord, la syntaxe est indiquée ci-dessous.
SetInt.java
public class SetInt{
public <E> Set<E> union(Set<E> s1,Set<E> s2){
// (Exemple)Traitement pour ajouter s1 et s2
}
}
La première chose que vous remarquerez est le
Set<Integer> result = SetInt.union(Set<Integer>,Set<Integer>);
Set<Integer> result = SetInt.<Integer>union(Set<Integer>,Set<Integer>);
De plus, le type peut être spécifié explicitement et le traitement des exceptions peut être appelé comme suit.
Hoge.java
public class Hoge{
public <E extends Exception> void example() throws E {};
public void test() {
try {
this.<IOException>example();
} catch (IOException e) {
//Gestion des exceptions lors de la capture d'exception IOException
}
try {
this.<SQLException>example();
} catch (SQLException e) {
//Gestion des exceptions lors de la capture d'exception SQLException
}
}
}
Elle est plus souvent vue que la portée de la méthode, et j'estime qu'elle est généralement traitée dans les livres d'introduction. Un exemple est présenté ci-dessous.
Stack.java
public class Stack<E> {
private E elements;
public void push(E e) {
//Processus pour pousser vers les éléments
}
public E pop() {
//Traitement pour extraire E des éléments
}
}
Vous pouvez définir des associations dans lesquelles les arguments, les valeurs de retour et les types de champs d'instance de plusieurs méthodes d'instance déclarées (deux ci-dessus) sont identiques.
On suppose que vous avez connaissance de «covariant, antivariant, immuable» et du «principe de remplacement de Riskov». Cet article est facile à comprendre sur le premier (https://www.thekingsmuseum.info/entry/2016/02/07/235454) Dans le mémo suivant, à titre d'exemple, il existe des classes A, B et C, respectivement, et elles sont vérifiées comme ayant une relation d'héritage de C étend B et B étend A, respectivement.
Il peut être défini comme suit.
List<? extends B> extendsBList = new ArrayList<C>();
L'extensionAList ci-dessus a les propriétés suivantes.
Mis à part la propriété 1, la propriété 2 reste discutable. Le processus par lequel la propriété 2 est dérivée est résumé ci-dessous.
Par exemple, il peut être stocké dans extendBList et extendBList.add (new B ()); tient. Mais encore une fois, veuillez vous référer au code d'initialisation de extendBList. Initialisé avec le type ArrayList
Il peut être défini comme suit.
List<? super B> superBList = new ArrayList<A>();
Le superBList ci-dessus a les propriétés suivantes.
La question reste dans la propriété 2. Cependant, le fait que la propriété 1 soit vérifiée signifie que l'objet récupéré par get () peut être d'un type d'objet supérieur au type B. A partir de là, lorsque <? Super B> est défini, l'objet obtenu par get () ne peut être reçu que par le type Object situé en haut de tous les types. Au lieu d'accepter le stockage, il devient impossible de spécifier le type à renvoyer.
Le point 28 de la 2e édition effective de Java décrit les principes PECS. Cité ci-dessous.
Dans la fonction, si le rôle de l'argument de type générique est "Producer", utilisez extend, et s'il est "Consumer", utilisez super. Un producteur est un argument qui crée (fournit) une valeur dans une fonction. D'un autre côté, un consommateur est un argument qui consomme (utilise) une certaine valeur dans une fonction. Ce principe est également appelé "PECS" pour abréviation de Producer-Extends et Consumer-Super.
Sur la base de la discussion sur le co-changement et l'anti-changement, nous pouvons comprendre pourquoi nous le faisons. Prenons l'exemple de la classe Hoge.
Dans une méthode, l'utilisation de extend comme argument de la méthode et super comme valeur de retour de la méthode peut prendre une implémentation plus large de la méthode.
J'aimerais revoir le contenu de l'article de temps en temps. De plus, quand je peux écrire des génériques, je veux être capable de concevoir en utilisant des génériques.
(https://www.amazon.co.jp/exec/obidos/ASIN/B078H61SCH/xray2000-22/)
Recommended Posts