Java >> Tutoriel Java >  >> Java

Que sont les génériques en Java

Une classe générique est une classe spéciale qui génère un ou plusieurs types Java non spécifiques lors de l'instanciation. Cela permet de supprimer le risque d'exception d'exécution "ClassCastException" lorsque nous devons effectuer un cast entre différents types. Avec ces classes génériques, on a la possibilité de créer des classes qui fonctionnent avec différents types de données Java. Les génériques aident à améliorer la qualité et l'efficacité du code.

Qu'est-ce que je veux dire quand je dis "supprimer le risque d'exception d'exécution (ClassCastException)" ? d'accord, essayons de mieux comprendre en utilisant des exemples :

Typecasting créant ClassCastException

package generics;

import java.util.ArrayList;
import java.util.List;

public class Generics {
    public static void main(String[] args) 
    {
        List arraylist = new ArrayList();
        arraylist.add("xyz");
        arraylist.add(new Integer(5)); 

    for(Object obj : arraylist){
	
    String s=(String) obj; 
}
    }
    
}

Sortie :

run:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
	at generics.Generics.main(Generics.java:16)
C:\Users\Mozerian\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 1 second)

Dans le code ci-dessus, nous tapons casted String s=(String) obj qui conduisent à ClassCastException lors de l'exécution. Cette erreur d'exécution est due au fait que l'objet que nous transmettons dans la liste est une chaîne alors que nous avons déclaré l'un de nos éléments en tant que type Integer.

Pas de conversion de type supprimant ClassCastException

package generics;

import java.util.ArrayList;
import java.util.List;

public class Generics {
    public static void main(String[] args) 
    {
       List<String> arraylist = new ArrayList<String>(); 
        arraylist.add("xyz");
         //compiler error

        for(String s : arraylist){
}

}
    }
   

Sortie :

run:
BUILD SUCCESSFUL (total time: 0 seconds)

Si nous supprimons le String s=(String) obj puis nous supprimons l'exception ClassCastException au moment de l'exécution. Un point à noter également si nous ajoutons list1.add(new Integer(5)) nous obtenons à nouveau une erreur de compilation.

Avantages de l'utilisation des génériques

Allons maintenant plus loin en examinant les avantages de l'utilisation de génériques.

Réutilisabilité du code

Les génériques permettent la réutilisation du code, cela signifie que nous pouvons écrire une interface/classe/méthode et l'utiliser pour n'importe quel type

package generics;

import java.util.ArrayList;
import java.util.List;

public class Generics {
    public static void main(String[] args) 
    {
Generics generic = new Generics();
System.out.println("===printing the integer values==");
generic.showData(1,2 );
System.out.println("===printing the string values===");
generic.showData("Generics in", "Java is good");
}
public <T> void showData(T x, T y)
{
System.out.println(x);
System.out.println(y);
}
}

Sortie :

run:
===printing the integer values==
1
2
===printing the string values===
Generics in
Java is good
BUILD SUCCESSFUL (total time: 1 second)

Dans le code ci-dessus, nous n'avons déclaré nulle part un entier ou une chaîne, mais en utilisant générique, nous pouvons réutiliser le code pour imprimer n'importe quel type que nous voulons. Nous pouvons également imprimer le type flottant simplement en ajoutant generic.showData(1.212, 2.234);

Sécurité du type de compilation

Les génériques contribuent à la sécurité du code car ils permettent de connaître une erreur de code au moment de la compilation plutôt qu'au moment de l'exécution. En utilisant des génériques, le compilateur affichera une erreur au moment de la compilation plutôt qu'à l'exécution. Comment cela aide-t-il ? en tant que programmeur, je pense que vous savez à quel point il peut être difficile de trouver une erreur au moment de l'exécution, mais il est simple de trouver une erreur au moment de la compilation puisque l'éditeur lui-même se plaint.

Supprime le casting de type individuel

En utilisant des génériques, nous n'exigeons pas de coulée de type individuelle.
Prenons un exemple :

Dans le code ci-dessous, le code A nécessite un transtypage car nous n'avons pas utilisé de génériques. Une fois que nous avons introduit des génériques dans le code, nous n'avons plus besoin de taper cast.

package generics;

import java.util.ArrayList;
import java.util.List;

public class Generics {
    public static void main(String[] args) 
    {
   
List arraylist = new ArrayList();
arraylist.add("here we need type casting");
String typecast = (String) arraylist.get(0);


List<String> list = new ArrayList<String>();
list.add("here we do not need type casting");
String notypecast = list.get(0);  

}
}

Enfin, les génériques aident à implémenter des algorithmes non génériques.

Initialisation d'objet générique

Un objet générique peut contenir des données d'un type ou plus. Pour initialiser l'objet avec un type.

Generic <String> gen = new Generic <String>();

Pour initialiser un objet de deux types :

Generic <String,Interger> gen = new Generic <String,Integer>();

Cela indique à la classe que l'objet de type 1 est une chaîne et que l'objet de type 2 est un entier. L'avantage de ceci dans une classe générique est des objets d'exemple de type avec différents types donnés pour chacun afin que vous puissiez initialiser un autre exemple d'objet avec

Types de génériques

Classe générique

Une classe générique est une classe qui peut faire référence à n'importe quel type de données. Par conséquent, vous définissez le type lors de l'instanciation.
Les types génériques sont déclarés à l'aide des chevrons <> autour d'un type de support de paramètre, par exemple. . Nous verrons les paramètres plus tard dans ce tutoriel
Convertissons une classe Java normale en une classe générique :

Classe normale

public class Generics {
    private String name;
    public void set (String setname)
    {
        name = setname;
    }
    public String get()
    {
        return name;
    }

Dans l'exemple ci-dessus, nous avons déclaré une classe, puis nous sommes allés de l'avant et avons déclaré une variable de chaîne name qui contient le type de données de chaîne. Nous avons ensuite utilisé la méthode setter pour définir le nom sur un nouveau nom et utiliser la méthode getter pour le renvoyer. Dans la classe du pilote, si nous passons une chaîne dans la méthode set et essayons de la convertir en int, nous recevrons une erreur de conversion lors de l'exécution. La chaîne ne peut pas être convertie en int.

public static void main(String[] args) 
    {
   Generics cars = new Generics();
   cars.set(T)
   Int number = (int)cars.get();
System.out.println(number);
    }
    }

En supposant que nous ne voulions pas traiter le type de données de chaîne dans ce cas, nous devrons changer le type de données lors de la déclaration. Mais cela peut être réalisé très facilement en utilisant une classe générique où nous pouvons déterminer le type de données que nous voulons à l'instanciation.

Classe générique

public class Generics<T> {
    private T t;
    public void set (T setname)
    {
        t = setname;
    }
    public T get()
    {
        return t;
    }
    

Classe de pilote générique

public static void main(String[] args) 
    {
    Generics <Integer> IntValue = new Generics <Integer> ();
    Generics <String> StringValue = new Generics <String>();
    IntValue.set(T);
    StringValue.set("Test");
    int nunmber = IntValue.get();
    String st = StringValue.get();
}

Méthodes génériques

Jusqu'à présent, nous avons créé des classes génériques, mais nous pouvons également créer des méthodes génériques en dehors d'une classe générique. Tout comme la déclaration de type, la déclaration de méthode est générique. Un ou plusieurs types de paramètres paramétrent cela. Les méthodes génériques sont des méthodes qui peuvent accepter n'importe quel type d'argument. Il autorise les méthodes statiques et non statiques uniquement si la portée des arguments est limitée à la méthode dans laquelle il est déclaré.

Nous allons utiliser un losange d'interface de type pour créer des méthodes génériques.

Le diamant de l'interface

Un losange d'interface de type vous permet de créer une méthode générique comme vous le feriez pour une méthode ordinaire, sans spécifier de type entre crochets.
Mais pourquoi un diamant ?
Les chevrons sont souvent appelés losanges <>
Typiquement, s'il n'y a qu'un seul type à l'intérieur du diamant, nous utilisons où T signifie typePour deux types, nous aurions Vous pouvez utiliser le seul mot non inversé comme support de type au lieu d'utiliser . Nous aurions pu utiliser . Par convection, les noms des paramètres de type sont des lettres majuscules simples.

package generics;

import java.util.ArrayList;
import java.util.List;

public class Generics<T> 
{
    public static <K> void printArray(K [] arrayElements){
        
        for(K elements :arrayElements){
            
            System.out.println(elements );  
                      
        }
        
        System.out.println();  
    }
   
    public static void main(String[] args) 
    {
   
    Integer [] arrayInt = {1,2,3,4,5};
    String [] arrayString = {"moses","njorge"};
    Character[] arrayChar = { 'A', 'V', 'C', 'D'};
    
    System.out.println( "Printing Integer Array" );
    printArray( arrayInt  );   


    System.out.println( "Printing String Array" );
    printArray( arrayString  );   
    
    System.out.println( "Printing Char Array" );
    printArray( arrayChar  );   
}
}
  

Sortie :

run:
===Printing Integer Array===
1
2
3
4
5

==Printing String Array===
Generics
in java is Sweet

===Printing Char Array==
A
B
B
A
BUILD SUCCESSFUL (total time: 1 second)

Dans le code ci-dessus, nous avons défini une méthode générique printArray pour renvoyer le contenu du tableau. Le pilote calss dans la méthode main permet plusieurs types de tableaux.

Interface générique

Une interface est une construction Java qui aide à définir les rôles qu'un objet peut assumer. Nous pouvons également créer une interface générique.

package java.lang;
import java.util.*;

Public interface School <T1,T2>{

  public int School(T1 t);
  public String School(T2 p);
}

Une interface est implémentée par une classe et étendue par une autre interface. Implémentons l'interface ci-dessus.

Public class Faculty implements School<Integer,String>{
Public Integer School (Integer t)
{
  //execution code
}
Public String School (String p)
{
  //execution code
}
}

Constructeur générique

Un constructeur est un type spécial de méthode qui est utilisé pour initialiser un objet ou qui peut être invoqué lorsqu'un objet de cette classe est créé. Examinons un exemple de constructeur générique

public class Cars<T> 
{
    private T toyota;
    private T isuzu;
    private T mercedes;
    
    
    public Cars(T toyota, T isuzu, T mercedes)
    {
        super();
        this.toyota = toyota;
        this.isuzu = isuzu;
        this.mercedes = mercedes;
}

Dans cet exemple, le constructeur de la classe cars possède les informations de type. Par conséquent, vous pouvez avoir une instance de voitures avec tous les attributs d'un seul type.

Saisir le nom du paramètre

Afin de distinguer les noms de paramètres de type générique des variables Java, les noms sont constitués de lettres majuscules uniques. Cela forme leur propre convention de nom. Ces paramètres comprennent.
Type T
E- element (largement utilisé par le framework de collection java)
N-nombre
Touche K (utilisée dans la carte)
Valeur V (utilisée dans la carte)
S,U,V, etc- 2 ème ,3 ème ,4 ème type.

Cartes génériques génériques.

En Java, nous présentons les caractères génériques à l'aide d'un point d'interrogation (?). Ils font référence à un type inconnu. Les caractères génériques avec générique nous permettent de créer un contrôle du type que nous utilisons. Nous ne pouvons pas utiliser de caractère générique lors de l'instanciation d'une classe générique ou de l'appel d'une méthode générique.
Ils se divisent en deux catégories

Limite

Les types liés sont utilisés lorsque nous voulons restreindre les types de variables dans une méthode. Ils sont de deux types.

. < ? étend le type>

Pour déclarer ce type de limite, vous commencez par lister le nom du paramètre de type, suivi du mot-clé extend et enfin de la limite supérieure.

public static <T extends Comp<T>> int compa(T t1, T t2){
		return t1.compareTo(t2);
	}

.

Prenons un exemple où nous voulons ajouter des Caractères/Entiers à une liste de Caractères/Entiers dans une méthode, Le super Le mot-clé est utilisé avec une limite inférieure.

public static void IntegersAdd(List<? super Integer> list){
		list.add(new Integer(50));
	}

Illimité

indique un caractère générique illimité
Nous utilisons le type non lié lorsque nous voulons que la méthode générique fonctionne avec tous les types de données,
Exemple :arrayList (rep. arrayList de type inconnu)

public static void print(List<?> list){
		for(Object data : list){
			System.out.print(data + "::");
		}
	}

Points à noter lorsque vous travaillez avec des types génériques

Lorsque vous travaillez avec des types génériques, rappelez-vous ce qui suit :

  • Les types doivent être identifiés lors de l'instanciation de la classe
  • Votre classe doit contenir des méthodes qui définissent les types à l'intérieur de la classe sur le type passé dans la classe lors de la création d'un objet de la classe
  • Une façon d'examiner la classe générique consiste à comprendre ce qui se passe derrière le code.

À ne pas faire dans les génériques Java

Ne créez pas de champs statiques de type cela générera une erreur de compilation.

public class Generics<T>
{
   private static T name; 
}

Ne créez pas d'instances de T. Cela conduira à une erreur.

public class Generics<T>
{
   public Generics(){
      new T();
   }
}

Ne créez pas de classe d'exception générique. Cela provoque une erreur de compilation.

public class Generic<T> extends Exception {}

Ne créez pas de génériques avec une déclaration de primitives.

final List<int> AddList = new ArrayList<>();

Conclusion

Dans ce tutoriel, nous avons discuté des génériques en Java ; nous avons couvert la classe générique, l'interface, le constructeur et les méthodes. Nous sommes allés plus loin et avons examiné les jokers et les paramètres génériques et enfin les choses à ne pas faire dans les génériques. Avec cela discuté, il est évident que le générique est devenu une bonne fonctionnalité que tous les programmeurs devraient apprécier puisque la vie des programmeurs avec l'utilisation des génériques est facilitée.


Balise Java