Découvrez les fonctionnalités et pratiques des génériques Java dans un seul article

Que sont les génériques ?

En Java, les génériques sont un mécanisme de paramétrage de type qui permet l'utilisation de paramètres de type lors de la définition de classes, d'interfaces ou de méthodes. L’objectif principal des génériques est d’augmenter la réutilisabilité du code, la sécurité des types et la flexibilité.

Les génériques vous permettent de spécifier un ou plusieurs paramètres de type lors de la définition d'une classe, d'une interface ou d'une méthode. Ces paramètres de type peuvent être utilisés comme espaces réservés dans une classe ou une méthode et seront remplacés par le type concret lorsqu'ils sont réellement utilisés. De cette façon, l'exactitude du type du code peut être vérifiée au moment de la compilation et les problèmes de conversion de type peuvent être évités.

Les génériques peuvent être appliqués à la définition de classes, d'interfaces, de méthodes et de classes de collection (telles que List, Set, Map, etc.).

public interface List<E> extends Collection<E> {
    
    
    int size();
    boolean isEmpty();
    ...
}

A quoi servent les génériques ?

​ Les génériques sont utilisés à de nombreuses fins en Java. Voici quelques-unes des principales utilisations :

  1. Sécurité du type : les génériques peuvent détecter les erreurs au moment de la compilation pour garantir que le code utilise le type correct . En utilisant des génériques, vous pouvez éviter les erreurs de conversion de type ou les problèmes d’incompatibilité de type au moment de l’exécution, améliorant ainsi la fiabilité et la sécurité de votre code.
  2. Réutilisation du code : l'utilisation de génériques vous permet d'écrire du code général pouvant être appliqué à plusieurs types de données. En définissant des classes ou des méthodes génériques, vous pouvez éviter d'écrire du code similaire à plusieurs reprises et améliorer la réutilisabilité et la maintenabilité du code.
  3. Classes de conteneurs et framework de collection : les classes de conteneurs (telles que List, Set, Map, etc.) dans le framework de collection de Java utilisent toutes des génériques. En utilisant des génériques, le type d'éléments stockés dans le conteneur peut être spécifié au moment de la compilation, fournissant ainsi des opérations de stockage et d'accès aux données sécurisées.
  4. Structure de données personnalisée : en utilisant des génériques, vous pouvez définir votre propre classe générique ou interface générique afin qu'elle puisse être appliquée à différents types de données. Cela vous permet d'écrire des structures de données courantes telles que des piles, des files d'attente, des arbres, etc., et de fournir des opérations de données de type sécurisé.
  5. Flexibilité des interfaces : en utilisant des génériques dans les interfaces, des interfaces paramétrées peuvent être définies afin qu'elles puissent être appliquées à différents types d'implémentations . Cela permet une conception d’interface plus flexible et améliore l’évolutivité et la réutilisabilité du code.
  6. Réflexion et génériques : le mécanisme de réflexion de Java peut être utilisé conjointement avec les génériques. En obtenant des informations sur les types génériques, les types génériques peuvent être manipulés dynamiquement au moment de l'exécution. Cela peut implémenter certaines opérations génériques avancées, telles que l'instanciation de types génériques, la vérification de types génériques, etc.

En général, les génériques fournissent un mécanisme flexible et sécurisé qui peut augmenter la réutilisabilité, la lisibilité et la fiabilité du code.

En utilisant des génériques, vous pouvez détecter les erreurs au moment de la compilation, réduire les conversions de types et fournir des structures de données et des algorithmes communs, améliorant ainsi la qualité et l'efficacité des programmes Java.

Quelle est la différence entre les génériques et les objets ?

Bien que les génériques et les objets puissent remplir des fonctions similaires à certains égards, il existe des différences importantes entre eux.

  1. Sécurité des types : les génériques fournissent une vérification de type au moment de la compilation et peuvent détecter les erreurs de type au moment de la compilation. Cela signifie que l'utilisation de génériques peut détecter les incompatibilités de types au moment de la compilation, plutôt que de les lancer au moment de l'exécution ClassCastException. En revanche, l'utilisation de ** Objectnécessite une conversion de type et une erreur d'exécution peut se produire lors de la conversion de type**.
  2. Lisibilité et maintenabilité : l'utilisation de génériques rend le code plus clair et plus facile à comprendre, puisque les paramètres de type fournissent des informations sur le type utilisé. En revanche, son utilisation Objectnécessite une conversion de type, ce qui augmente la complexité et la lisibilité du code, ainsi que le risque d'erreurs.
  3. Inférence de type automatique : lors de l'utilisation de génériques, le compilateur peut automatiquement déduire des paramètres de type en fonction du contexte, ce qui rend le code plus concis. Lorsqu'il est utilisé Object, une conversion de type explicite est requise, ce qui augmente la redondance et la complexité du code.
  4. Sécurité du type de collection : le framework de collection Java (tel que List, Set, Map, etc.) utilise des génériques pour spécifier le type d'éléments stockés dans le conteneur. En utilisant des génériques, vous pouvez détecter les erreurs de type au moment de la compilation et fournir des opérations de données sécurisées. S'il est utilisé Objectpour stocker des éléments de collection, une conversion de type est requise, ce qui est sujet aux erreurs de type et aux exceptions d'exécution.

En résumé, les génériques présentent plus d'avantages en termes de sécurité des types, de lisibilité et de maintenabilité du code et de sécurité des types de collection Object. Il fournit une vérification de type au moment de la compilation et une inférence de type automatique, rendant le code plus sûr et plus concis.

Par conséquent, lorsque des génériques peuvent être utilisés, il est recommandé d'utiliser plutôt des génériques Objectpour implémenter le paramétrage de type et les opérations de type sécurisé .

​ Ce qui suit montre les différences d'utilisation entre les deux au niveau du code :

  1. Type de sécurité :

    // 使用泛型
    List<String> stringList = new ArrayList<>();
    stringList.add("Hello");
    stringList.add("World");
    stringList.add(123); // 编译错误,类型不匹配
    
    // 使用Object
    List objectList = new ArrayList();
    objectList.add("Hello");
    objectList.add("World");
    objectList.add(123); // 编译通过,但在运行时可能抛出ClassCastException
    

    En utilisant des génériques, le compilateur peut détecter les erreurs de type au moment de la compilation et éviter les erreurs de conversion de type au moment de l'exécution.

  2. Lisibilité et maintenabilité du code :

    // 使用泛型
    public <T> T getLastElement(List<T> list) {
          
          
        return list.get(list.size() - 1);
    }
    
    // 使用Object
    public Object getLastElement(List list) {
          
          
        return list.get(list.size() - 1);
    }
    

    L'utilisation de génériques rend votre code plus clair et plus facile à comprendre car les paramètres de type fournissent des informations sur le type utilisé. Lorsqu'il est utilisé Object, une conversion de type est requise, ce qui augmente la complexité et la lisibilité du code.

  3. Sécurité du type de collecte :

    // 使用泛型
    List<String> stringList = new ArrayList<>();
    stringList.add("Hello");
    stringList.add("World");
    String firstElement = stringList.get(0); // 不需要进行类型转换
    
    // 使用Object
    List objectList = new ArrayList();
    objectList.add("Hello");
    objectList.add("World");
    String firstElement = (String) objectList.get(0); // 需要进行类型转换
    

    En utilisant des génériques, vous pouvez détecter les erreurs de type au moment de la compilation et fournir des opérations de données sécurisées.

​ Ces exemples illustrent les avantages des génériques en termes de sécurité des types, de lisibilité et de maintenabilité du code et de sécurité des types de collection.

Les génériques peuvent détecter les erreurs au moment de la compilation, rendre le code plus clair et plus facile à comprendre et fournir des opérations de données sécurisées.

Comment définir les génériques et les usages de base ?

  1. Définir une classe générique :

    public class Box<T> {
          
          
        private T content;
    
        public T getContent() {
          
          
            return content;
        }
    
        public void setContent(T content) {
          
          
            this.content = content;
        }
    }
    

    Dans l'exemple ci-dessus, Box<T>est une classe générique et Tconstitue le paramètre de type. TPeut être utilisé comme espace réservé dans une définition de classe , indiquant qu'il sera remplacé par un type spécifique lorsqu'il sera réellement utilisé.

    ​Créez un objet générique :

    Box<String> stringBox = new Box<>();
    
    stringBox.setContent("Hello");
    
    String content = stringBox.getContent();
    

    <>​Spécifiez des paramètres de type spécifiques lors de la création d'un objet générique à l'aide de crochets angulaires . Dans l'exemple ci-dessus, un Box<String>objet est créé et le type chaîne est attribué au contenu de l'objet générique.

  2. Définir des méthodes génériques :

    public <T> T getLastElement(List<T> list) {
          
          
        return list.get(list.size() - 1);
    }
    

    Dans l'exemple ci-dessus, <T>cela signifie que la méthode a un paramètre de type générique. Les paramètres de type générique peuvent être utilisés dans le type de retour et la liste de paramètres d'une méthode T.

  3. Utilisez des caractères génériques :

    public void processList(List<?> list) {
          
          
        // 处理列表的逻辑
    }
    

    Dans l'exemple ci-dessus, des caractères génériques sont utilisés ?pour indiquer que la méthode accepte une liste de n'importe quel type. Cela vous permet de gérer des listes de types non spécifiés dans la méthode, augmentant ainsi la flexibilité de la méthode.

  4. Limites de type générique :

    public <T extends Number> void printNumber(T number) {
          
          
        System.out.println(number);
    }
    

    Dans l'exemple ci-dessus, en utilisant les limites de type extends Number, le type générique est limité Tà Numberou à ses sous-classes. Cela garantit que les paramètres transmis sont conformes à certaines contraintes de type.

    ​ Il convient de noter que les génériques sont effacés au moment de la compilation, c'est-à-dire que les informations spécifiques des paramètres de type ne sont pas conservées au moment de l'exécution. Par conséquent, soyez conscient de certaines limitations et comportements pouvant résulter de l’effacement de type lors de l’utilisation de génériques.

Quelle est la différence entre les caractères génériques et les objets dans les génériques ?

​ Les caractères génériques sont une syntaxe spéciale dans les génériques qui sont utilisés pour augmenter la flexibilité des génériques. L'utilisation de caractères génériques dans les génériques peut résoudre certains problèmes liés au type et fournir une prise en charge plus large des types. Par rapport à using Object, les caractères génériques présentent les différences et utilisations suivantes :

  1. Convient aux types inconnus : les caractères génériques ?représentent des types inconnus et peuvent accepter des paramètres de n'importe quel type dans certains cas. Cela permet à une méthode ou une classe générique d’être plus générale et applicable à des types non spécifiés.
  2. Utilisé avec l'inférence de type : les caractères génériques peuvent être utilisés avec l'inférence de type pour déduire automatiquement le type approprié en fonction du contexte. Cela rend le code plus propre et élimine le besoin de spécifier explicitement des paramètres de type spécifiques.
  3. Caractère générique de limite supérieure : le caractère générique ? extends Tindique que le type T et ses sous-types sont acceptés. L'utilisation de caractères génériques de limite supérieure peut permettre un traitement universel de plusieurs types sans être limité à des paramètres de type spécifiques.
  4. Caractère générique de limite inférieure : le caractère générique ? super Tindique que le type T et son type parent sont acceptés. L'utilisation de caractères génériques de limite inférieure permet une gestion générique de plusieurs types et permet de transmettre des types plus génériques comme arguments.
  5. Flexibilité et extensibilité : l'utilisation de caractères génériques permet une conception de code plus flexible et extensible. Il peut gérer davantage de types de données tout en maintenant la sécurité des types et en évitant les conversions de types et les exceptions inutiles.

Comment bien utiliser les génériques en pratique ?

  1. Noms de paramètres de type significatifs : lors de la définition d’une classe, d’une interface ou d’une méthode générique, choisissez des noms de paramètres de type descriptifs. Par exemple, utilisez Tpour représenter les paramètres de type générique, utilisez Epour représenter les types d'éléments de collection et utilisez Ket Vpour représenter l'équivalence clé-valeur. Cela augmente la lisibilité et la compréhensibilité du code.

  2. Évitez les types primitifs : essayez d’éviter d’utiliser des types primitifs et utilisez plutôt des types génériques. Un type primitif fait référence à un type générique pour lequel aucun paramètre de type concret n'est spécifié, par exemple au lieu Listde List<String>. L'utilisation de types primitifs perdra la sécurité des types et la vérification au moment de la compilation des génériques , alors essayez d'éviter de les utiliser.

  3. Utilisation flexible des caractères génériques : vous pouvez utiliser des caractères génériques pour augmenter la flexibilité lors de la définition de méthodes génériques ou de l'utilisation de types génériques. Par exemple, use ? extends Tsignifie que le type T et ses sous-types sont acceptés, et use ? super Tsignifie que le type T et son surtype sont acceptés. Cela rend le code plus général et applicable à davantage de types.

  4. Écrire des structures de données et des algorithmes généraux : en utilisant des génériques, vous pouvez écrire des structures de données générales (telles que des piles, des files d'attente, des arbres, etc.) et des algorithmes (tels que le tri, la recherche, etc.) pour vous adapter à différents types de données. Cela améliore la réutilisabilité et la maintenabilité du code.

  5. Évitez les conversions : essayez d'éviter les conversions lorsque vous utilisez des génériques . Si une conversion de type est requise, envisagez de reconcevoir le code pour tirer pleinement parti de l'inférence de type générique et des caractères génériques afin de réduire le besoin de conversion de type.

  6. Faites bon usage des contraintes génériques : vous pouvez utiliser la limite supérieure et la limite inférieure des génériques pour limiter la plage de types des génériques . Cela permet d'effectuer une vérification de type au moment de la compilation et augmente la fiabilité et la sécurité du code.

  7. Apprenez et apprenez de l'utilisation des génériques dans la bibliothèque standard : Le cadre de collection et d'autres classes couramment utilisées dans la bibliothèque standard Java utilisent une multitude de génériques, et vous pouvez apprendre et apprendre de leur conception et de leur utilisation. En lisant et en comprenant le code générique de la bibliothèque standard, vous pourrez mieux maîtriser les compétences d'utilisation des génériques.

Pour utiliser pleinement les génériques dans le codage pratique, vous devez comprendre le concept et la syntaxe des génériques, choisir des noms de paramètres de type significatifs, éviter d'utiliser des types primitifs, faire bon usage des caractères génériques et des qualifications, écrire des structures de données et des algorithmes communs et apprendre à s'appuyer sur des standards.Utilisation générique de la bibliothèque. En appliquant correctement les génériques, vous pouvez améliorer la lisibilité, la maintenabilité et la réutilisabilité du code, tout en augmentant la sécurité des types et la vérification au moment de la compilation.

Je suppose que tu aimes

Origine blog.csdn.net/weixin_40709965/article/details/131795130
conseillé
Classement