Les soi-disant génériques : ils vous permettent de spécifier des paramètres de type lors de la définition des classes et des interfaces. Ce paramètre de type sera déterminé lors de la déclaration des variables et de la création d'objets (c'est-à-dire en transmettant des paramètres de type réels, qui peuvent également être appelés arguments de type).
Classe ou interface générique
Le code de copie de la syntaxe « diamant » est le suivant :
//définition
interface publique List<E> étend Collection<E>
classe publique HashMap<K,V> étend AbstractMap<K,V> implémente Map<K,V>, clonable, sérialisable
//utiliser
List<String> list = new ArrayList();
//Après Java 7, vous pouvez omettre le paramètre de type des crochets angulaires derrière lui.
List<String> list = new ArrayList<>();
Dériver une sous-classe d'une classe générique
Copiez le code comme suit :
//Méthode 1
L'application de classe publique étend GenericType<String>
//Méthode 2
la classe publique App<T> étend GenericType<T>
//Méthode 3
L'application de classe publique étend GenericType
Pseudo génériques
Il n'existe pas de véritable classe générique. Les classes génériques sont transparentes pour la machine virtuelle Java. En d'autres termes, la JVM traite les classes génériques de la même manière que les classes ordinaires. dans les méthodes statiques, les blocs d'initialisation statiques et les variables statiques.
- Les méthodes suivantes sont toutes fausses. Le code de copie est le suivant :
données T statiques privées ;
statique{
Tf;
}
public static void func(){
T nom = 1 ;
}
L'exemple suivant peut vérifier de côté qu'il n'y a pas de classe générique. Copiez le code. Le code est le suivant :
public static void main (String[] args){
List<String> a1 = new ArrayList<>();
List<Integer> a2 = new ArrayList<>();
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass());
System.out.println(a2.getClass());
}
Le code de copie de sortie est le suivant :
vrai
classe java.util.ArrayList
classe java.util.ArrayList
Tapez un caractère générique
Tout d'abord, il doit être clair que si Foo est la classe parent de Bar, mais que List<Foo> n'est pas la classe parent de List<Bar> Afin de représenter diverses classes parent génériques, Java utilise "?" caractères génériques. Autrement dit, List<?> représente la classe parent de diverses listes génériques. Avec ce type de caractère générique, les génériques de liste ne peuvent pas définir (définir) des éléments, mais peuvent uniquement obtenir (obtenir) des éléments. Le programme ne pouvant pas déterminer les types dans la liste, il ne peut pas ajouter d'objets. Mais l’objet obtenu doit être de type Objet.
Les méthodes suivantes compileront avec des erreurs :
Copiez le code comme suit :
Liste<?> list = new ArrayList<>();
list.add(nouvel objet());
Quelques idées :
1. Les objets List<String> ne peuvent pas être utilisés comme objets List<Object>, c'est-à-dire : la classe List<String> n'est pas une sous-classe de la classe List<Object>.
2. Les tableaux sont différents des génériques : en supposant que Foo est un sous-type (sous-classe ou sous-interface) de Bar, alors Foo[] est toujours un sous-type de Bar[] mais G<Foo> n'est pas un sous-type G<Bar> ;
3. Afin de représenter la classe parent de diverses listes génériques, nous devons utiliser des caractères génériques de type. Le caractère générique de type est un point d'interrogation (?). Passez un point d'interrogation comme argument de type à la collection List, écrit : List<?. > (ce qui signifie liste inconnue d'éléments de type). Ce point d'interrogation (?) est appelé caractère générique et son type d'élément peut correspondre à n'importe quel type.
Limite supérieure générique
List<? extends SuperType> représente la classe parent ou elle-même de toutes les listes génériques SuperType. Les génériques avec des limites supérieures génériques ne peuvent pas avoir de méthodes définies, ils obtiennent uniquement des méthodes.
Définir la limite supérieure des caractères génériques peut résoudre les problèmes suivants : Dog est une sous-classe d'Animal et il existe une méthode getSize pour obtenir le nombre de listes entrantes. Le code est le suivant. Copiez le code comme suit :
classe abstraite Animal {
public abstrait void run();
}
la classe Chien étend Animal {
public void run() {
System.out.println("Piste de chiens");
}
}
Application de classe publique {
public static void getSize(Liste<Animal> liste) {
System.out.println(list.size());
}
public static void main (String[] arguments) {
List<Dog> list = new ArrayList<>();
getSize(list); // Erreur de compilation ici
}
}
La raison de l'erreur de programmation ici est que List<Animal> n'est pas la classe parent de List<Dog>. La première solution consiste à modifier le paramètre formel List<Animal> dans la méthode getSize en List<?>, mais dans ce cas, une conversion de type forcée est requise à chaque fois que l'objet est obtenu, ce qui est plus gênant. L'utilisation de la limite supérieure générique résout très bien ce problème. Vous pouvez remplacer List<Animal> par List<?, et il n'y aura aucune erreur lors de la compilation et aucune conversion de type n'est requise.
Limite inférieure pour les caractères génériques
List<? super SubType> représente la limite inférieure de la liste générique SubType. Les génériques avec des limites supérieures génériques ne peuvent pas avoir de méthodes get, mais uniquement des méthodes set.
Méthodes génériques
Si vous définissez des classes et des interfaces sans utiliser de paramètres de type, mais que vous souhaitez définir vous-même des paramètres de type lors de la définition de méthodes, cela est également possible. JDK1.5 prend également en charge les méthodes génériques. La signature de méthode d'une méthode générique contient plus de déclarations de paramètres de type que la signature de méthode d'une méthode ordinaire. Les déclarations de paramètres de type sont placées entre crochets. Plusieurs paramètres de type sont séparés par des virgules (,). modificateurs et types de valeurs de retour de méthode Le format de syntaxe est le suivant :
Copiez le code comme suit :
Nom de la méthode de type de valeur de retour du modificateur (liste de types) {
//corps de la méthode
}
Les méthodes génériques permettent d'utiliser des paramètres de type pour exprimer des dépendances de type entre un ou plusieurs paramètres d'une méthode, ou entre les valeurs de retour et les paramètres de la méthode. S’il n’existe pas de dépendance de type, les méthodes génériques ne doivent pas être utilisées. La méthode de copie des Collections utilise des méthodes génériques :
Copiez le code comme suit :
public static <T> void copy(List<? super T> dest, List<? extends T> src){ ...}
Cette méthode nécessite que le type src soit une sous-classe du type dest ou lui-même.
Effacer et convertir
Dans le code générique strict, les classes avec des déclarations génériques doivent toujours avoir des paramètres de type. Cependant, afin d'être cohérent avec l'ancien code Java, il est également autorisé d'utiliser des classes avec des déclarations génériques sans spécifier de paramètres de type. Si aucun paramètre de type n'est spécifié pour cette classe générique, le paramètre de type est appelé type brut et prend par défaut le premier type de limite supérieure spécifié lors de la déclaration du paramètre.
Lorsqu'un objet avec des informations génériques est affecté à une autre variable sans informations génériques, toutes les informations de type entre les crochets angulaires sont supprimées. Par exemple, si un type List<String> est converti en List, la vérification de type des éléments de collection de List devient la limite supérieure de la variable de type (c'est-à-dire Object). Cette situation est appelée effacement.
L'exemple de code de copie est le suivant :
classe Apple<T étend le numéro>
{
Taille T ;
publicApple()
{
}
Apple publique (taille T)
{
this.size = taille ;
}
public void setSize (taille T)
{
this.size = taille ;
}
public T getSize()
{
renvoie this.size;
}
}
Classe publique ErasureTest
{
public static void main (String[] arguments)
{
Apple<Integer> a = new Apple<>(6); // ①
// La méthode getSize d'un renvoie un objet Integer
Entier as = a.getSize();
// Attribue l'objet a à la variable Apple, perdant les informations de type entre crochets
Pomme b = a ; // ②
// b sait seulement que le type de taille est Number
Nombre size1 = b.getSize();
//Le code suivant provoque une erreur de compilation
Taille entière2 = b.getSize(); // ③
}
}