Java >> Java tutorial >  >> Java

Hvad er generiske stoffer i Java

En generisk klasse er en speciel klasse, der genererer en eller flere ikke-specifikke java-typer ved instansiering. Dette hjælper med at fjerne runtime-undtagelsesrisikoen "ClassCastException", når vi skal caste mellem forskellige typer. Med disse generiske klasser har man mulighed for at oprette klasser, der fungerer med forskellige java-datatyper. Generiske stoffer hjælper med at forbedre kodens kvalitet og effektivitet.

Hvad mener jeg, når jeg siger "fjern risikoen for runtime-undtagelse (ClassCastException)"? okay, lad os få en bedre forståelse ved at bruge eksempler:

Typecasting skaber 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; 
}
    }
    
}

Output:

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)

I ovenstående kode skriver vi casted String s=(String) obj som fører til ClassCastException under kørsel. Denne runtime fejl skyldes, at det objekt, vi sender på listen, er en streng, hvor vi erklærede et af vores elementer som en heltalstype.

Ingen type casting fjerner 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){
}

}
    }
   

Output:

run:
BUILD SUCCESSFUL (total time: 0 seconds)

Hvis vi fjerner String s=(String) obj så fjerner vi ClassCastException under kørsel. Et punkt at bemærke, også hvis vi tilføjer list1.add(new Integer(5)) vi får igen en kompileringsfejl.

Fordele ved at bruge Generics

Lad os nu grave dybere ned ved at se på fordelene ved at bruge generiske lægemidler.

Kodegenanvendelighed

Generiske tillader genbrug af kode, det betyder, at vi kan skrive en grænseflade/klasse/metode og bruge den til enhver 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);
}
}

Output:

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

I ovenstående kode er der ingen steder, vi har erklæret heltal eller streng, men ved at bruge generisk kan vi genbruge koden til at udskrive enhver type, vi ønsker. Vi kan også udskrive float-type blot ved at tilføje generic.showData(1.212, 2.234);

Kompileringstypesikkerhed

Generics hjælper kodesikkerheden, da det giver dig mulighed for at kende en kodefejl på kompileringstidspunktet snarere end ved kørselstiden. Ved at bruge generiske artikler vil compileren vise en fejl på kompileringstidspunktet snarere end ved runtime. Hvordan hjælper dette? som programmør tror jeg, du ved, hvor svært det kan være at finde en fejl under kørslen, men det er ligetil at finde en fejl på kompileringstidspunktet, da redaktøren selv klager.

Fjerner individuel type støbning

Ved brug af generiske stoffer kræver vi ikke individuel støbning.
Lad os tage et kig på et eksempel:

I nedenstående kode kræver kode A typecasting, da vi ikke har brugt generika. Når vi først har introduceret generiske stoffer i koden, behøver vi ikke at skrive 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);  

}
}

Sidst men ikke listen er generiske stoffer, der hjælper med at implementere ikke-generiske algoritmer.

Generisk objektinitialisering

Et generisk objekt kan indeholde data af én type eller flere. For at initialisere objekt med én type.

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

For at initialisere objekt af to typer:

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

Dette fortæller klassen, at type 1-objektet er en streng, og type 2-objektet er et heltal. Fordelen ved dette i en generisk klasse er objekter af typen eksempel med forskellige typer givet for hver, så du kan initialisere et andet objekteksempel med

Generiske typer

Generisk klasse

En generisk klasse er en klasse, der kan henvise til enhver datatype. Derfor definerer du typen under instansieringen.
Generiske typer erklæres ved hjælp af vinkelparenteserne <> omkring en parameterholdertype f.eks. . Vi vil se på parametrene senere i denne tutorial
Lad os konvertere en normal java-klasse til en generisk klasse:

Normal klasse

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

I ovenstående eksempel har vi erklæret en klasse, så gik vi videre og erklærede en strengvariabel navn der indeholder strengdatatypen. Vi brugte derefter setter-metoden til at sætte navnet til et nyt navn og bruge getter-metoden til at returnere det. I driverklassen, hvis vi sender en streng i set-metoden og prøver at caste den som int, vil vi modtage en casting-fejl ved kørsel. Strengen kan ikke konverteres til int.

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

Antag, at vi ikke ønsker at beskæftige os med strengdatatype i dette tilfælde, bliver vi nødt til at ændre datatypen ved deklaration. Men dette kan opnås meget nemt ved hjælp af en generisk klasse, hvor vi kan bestemme den datatype, vi ønsker ved instansiering.

Generisk klasse

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

Generisk driverklasse

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();
}

Generiske metoder

Indtil videre har vi lavet generiske klasser, men vi kan også lave generiske metoder uden for en generisk klasse. Ligesom typedeklaration er metodedeklaration generisk. En eller flere typer parametre parametrerer det. Generiske metoder er metoder, der kan acceptere enhver form for argument. Det tillader kun både statiske og ikke-statiske metoder, at rækkevidden af ​​argumenterne er begrænset til den metode, hvor den er erklæret.

Vi vil bruge en type interface diamant til at skabe generiske metoder.

Grænsefladediamanten

En type interface-diamant giver dig mulighed for at oprette en generisk metode, som du ville gøre med en almindelig metode, uden at angive en type mellem vinkelparenteser.
Men hvorfor en diamant?
Vinkelbeslagene omtales ofte som diamant <>
Typisk, hvis der kun er én type inde i diamanten, bruger vi hvor T står for typeFor to typer ville vi have Du kan bruge det eneste ikke-omvendte ord som typeholder i stedet for at bruge . Vi kunne have brugt . Ved konvektion er typeparameternavne enkeltstående store bogstaver.

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  );   
}
}
  

Output:

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)

I ovenstående kode definerede vi en generisk metode printArray for at returnere indholdet af arrayet. Driver-calss i hovedmetoden tillader flere array-typer.

Generisk grænseflade

En grænseflade er en java-konstruktion, der hjælper med at definere de roller, som et objekt kan påtage sig. Vi kan også oprette en generisk grænseflade.

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

Public interface School <T1,T2>{

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

En grænseflade er implementeret af en klasse og udvidet med en anden grænseflade. Lad os implementere grænsefladen ovenfor.

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

Generisk konstruktør

En konstruktør er en speciel type metode, der bruges til at initialisere et objekt eller kan påberåbes, når et objekt af den pågældende klasse oprettes. Lad os tage et kig på et eksempel på en generisk konstruktør

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;
}

I dette eksempel har bilklassens konstruktør typeoplysningerne. Derfor kan du kun have en forekomst af biler med alle attributter af en enkelt type.

Skriv parameternavn

For at skelne de generiske typeparameternavne fra java-variabler, laves navnene enkelt, store bogstaver. Dette danner deres egen navnekonvention. Disse parametre omfatter.
T-type
E-element (bruges i vid udstrækning af java-samlingsrammerne)
N-nummer
K-tast (bruges i kort)
V-værdi (bruges på kort)
S,U,V osv- 2 nd ,3 rd ,4 th typer.

Generiske WildCards.

I java præsenterer vi jokertegn ved hjælp af et spørgsmålstegn (?). De henviser til en ukendt type. Jokertegn med generisk giver os mulighed for at skabe kontrol over den type, vi bruger. Vi kan ikke bruge et jokertegn, mens vi instansierer en generisk klasse eller påberåber os en generisk metode.
De falder i to kategorier

Afgrænset

De bundne typer bruges, når vi ønsker at begrænse variabeltyperne i en metode. De er af to typer.

.

For at erklære denne type grænse starter du med at angive typeparameternavnet, efterfulgt af udvide nøgleordet og til sidst øvre grænse.

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

.

Lad os tage et eksempel, vi ønsker at tilføje tegn/heltal til en liste over tegn/heltal i en metode, super Søgeord bruges sammen med en nedre grænse.

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

Ubegrænset

betegner et ubegrænset jokertegn
Vi bruger ubundet type, når vi ønsker, at den generiske metode skal fungere med alle datatyper,
Eksempel:arrayList (rep. arrayList af ukendt type)

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

Punkter at bemærke, når du arbejder med generiske typer

Mens du arbejder med generiske typer, husk følgende:

  • Typerne skal identificeres ved instansieringen af ​​klassen
  • Din klasse skal indeholde metoder, der indstiller typerne inde i klassen til den type, der sendes ind i klassen ved oprettelse af et objekt i klassen
  • En måde at se på den generiske klasse er ved at forstå, hvad der sker bag koden.

Don'ts i Java Generics

Opret ikke statiske felter af typen, dette vil generere en kompileringstidsfejl.

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

Opret ikke forekomster af T. Dette vil føre til en fejl.

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

Opret ikke en generisk undtagelsesklasse. Dette forårsager kompileringsfejl.

public class Generic<T> extends Exception {}

Opret ikke generiske stoffer med primitiver-deklaration.

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

Konklusion

I denne tutorial har vi diskuteret generiske stoffer i java; vi har dækket generisk klasse, grænseflade, konstruktør og metoder. Vi gik videre og kiggede på de generiske wildcards og parametre og til sidst på don'ts i generiske. Med det diskuteret, er det tydeligt, at generisk er blevet en god funktion, som alle programmører bør sætte pris på, da programmørernes liv med brugen af ​​generiske lægemidler er gjort lettere.


Java tag