Vodič za generičke Java - Što su generički lijekovi i kako ih koristiti?

Java Generics jedno je od najvažnijih obilježja Java jezika. Ideja koja stoji iza generičkih lijekova prilično je jednostavna, no ponekad se čini složenom zbog pomicanja s uobičajene sintakse povezane s njom.

Svrha ovog vodiča je upoznati vas s ovim korisnim konceptom generičkih lijekova na lako razumljiv način.

No, prije nego što zaronimo u same generike, shvatimo zašto su Java generici uopće bili potrebni.

Svrha Java Generics-a

Prije uvođenja generičkih lijekova u Javi 5, mogli ste napisati i sastaviti isječak koda poput ovog, ne donoseći pogrešku ili upozorenje:

List list = new ArrayList(); list.add('hey'); list.add(new Object());

Možete dodati vrijednosti bilo koje vrste na popis ili u drugu Javinu zbirku, a da ne morate deklarirati koju vrstu podataka pohranjuje. Ali kada dohvaćate vrijednosti s popisa, morate ga izričito prebaciti na određenu vrstu.

Razmislite o ponavljanju gornjeg popisa.



for (int i=0; i< list.size(); i++) {
String value = (String) list.get(i); //CastClassException when i=1 }

Dopuštanje stvaranja popisa bez prethodnog deklariranja pohranjene vrste podataka, kao što smo to učinili, moglo bi dovesti do toga da programeri čine pogreške kao gore što dovodi do ClassCastExceptions za vrijeme izvođenja.

Uvedeni su generički lijekovi kako bi se programeri spriječili u takvim pogreškama.

S generičkim lijekovima možete izričito deklarirati vrstu podataka koja će se pohraniti prilikom stvaranja Java kolekcije, kao što pokazuje sljedeći primjer.

Bilješka:I dalje možete stvoriti objekt kolekcije Java bez navođenja pohranjene vrste podataka, ali to se ne preporučuje. List stringList = new ArrayList();

Sada ne možete pogreškom pohraniti Integer na popisu vrsta niza bez izbacivanja pogreške u vremenu prevođenja. To osigurava da vaš program ne naleti na pogreške u izvođenju.

stringList.add(new Integer(4)); //Compile time Error

Glavna svrha uvođenja generičkih lijekova u Javu bila je izbjegavanje naleta na ClassCastExceptions za vrijeme izvođenja.

Stvaranje Java generičkih podataka

Generičke lijekove možete koristiti za stvaranje Java klasa i metoda. Pogledajmo primjere kako stvoriti generičke lijekove svake vrste.

Generička klasa

Prilikom stvaranja generičke klase, parametar tipa za klasu dodaje se na kraj naziva klase unutar kuta zagrade.

public class GenericClass {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return this.item;
} }

Evo, T je parametar tipa podataka. T, N i E neka su slova koja se koriste za parametre tipa podataka u skladu s Java konvencijama.

U gornjem primjeru možete mu proslijediti određenu vrstu podataka prilikom izrade objekta GenericClass.

public static void main(String[] args) {
GenericClass gc1 = new GenericClass();
gc1.setItem('hello');
String item1 = gc1.getItem(); // 'hello'
gc1.setItem(new Object()); //Error
GenericClass gc2 = new GenericClass();
gc2.setItem(new Integer(1));
Integer item2 = gc2.getItem(); // 1
gc2.setItem('hello'); //Error }

Ne možete proslijediti primitivni tip podataka parametru tipa podataka kada kreirate generički objekt klase. Kao tipski parametri mogu se proslijediti samo tipovi podataka koji proširuju Object type.

Na primjer:

GenericClass gc3 = new GenericClass(); //Error

Generičke metode

Stvaranje generičkih metoda slijedi sličan obrazac kao i stvaranje generičkih klasa. Generičku metodu možete implementirati unutar generičke klase, kao i generičke klase.

public class GenericMethodClass {
public static void printItems(T[] arr){
for (int i=0; i< arr.length; i++) {

System.out.println(arr[i]);
}
}
public static void main(String[] args) {
String[] arr1 = {'Cat', 'Dog', 'Mouse'};
Integer[] arr2 = {1, 2, 3};

GenericMethodClass.printItems(arr1); // 'Cat', 'Dog', 'Mouse'
GenericMethodClass.printItems(arr2); // 1, 2, 3
} }

Ovdje možete proslijediti niz određenog tipa za parameterizaciju metode. Generička metoda PrintItems() prelistava propušteni niz i ispisuje stavke pohranjene baš kao i uobičajena Java metoda.

Ograničeni parametri tipa

Do sada su se generičke klase i metode koje smo gore stvorili mogu parametrizirati za bilo koji tip podataka osim za primitivne tipove. Ali što ako bismo htjeli ograničiti tipove podataka koji se mogu proslijediti generičkim lijekovima? Tu ulaze parametri ograničenog tipa.

Tipove podataka možete prihvatiti generičkom klasom ili metodom tako što ćete navesti da to treba biti podrazred drugog tipa podataka.

Na primjer:

//accepts only subclasses of List public class UpperBoundedClass{
//accepts only subclasses of List
public void UpperBoundedMethod(T[] arr) {
} }

Ovdje je UpperBoundedClass i UpperBoundedMethod može se parametrizirati samo pomoću podtipova List vrsta podataka.

List tip podataka djeluje kao gornja granica parametra tipa. Ako pokušate upotrijebiti vrstu podataka koja nije podvrsta List, izbacit će pogrešku u vremenu prevođenja.

Granice nisu ograničene samo na klase. Možete proslijediti i sučelja. Proširenje sučelja u ovom slučaju znači implementaciju sučelja.

Parametar također može imati više granica kao što pokazuje ovaj primjer.

//accepts only subclasses of both Mammal and Animal public class MultipleBoundedClass{
//accepts only subclasses of both Mammal and Animal
public void MultipleBoundedMethod(T[] arr){
} }

Prihvaćajući tip podataka mora biti podrazred klasa Životinje i Sisavci. Ako je jedna od ovih granica klasa, ona mora biti prva u vezanoj deklaraciji.

U gornjem primjeru, ako je sisavac klasa, a životinja sučelje, sisari moraju biti na prvom mjestu kao što je gore prikazano. Inače, kôd baca pogrešku vremena kompajliranja.

Zamjenski Java znakovi

Zamjenski znakovi koriste se za prijenos parametara generičkih tipova na metode. Za razliku od generičke metode, ovdje se generički parametar prenosi na parametre koje metoda prihvaća, a koji se razlikuje od parametra tipa podataka o kojem smo gore govorili. Zamjenski znak predstavlja znak? simbol.

public void printItems(List list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
} }

Gore navedeno printItems() metoda prihvaća popise bilo koje vrste podataka kao parametar. To sprječava programera da ponavljaju kodove za popise različitih vrsta podataka, što bi bio slučaj bez generičkih lijekova.

Gornje ograničeni zamjenski znakovi

Ako želimo ograničiti tipove podataka pohranjene na popisu koji metoda prihvaća, možemo koristiti ograničene zamjenske znakove.

Primjer:

public void printSubTypes(List list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
} }

printSubTypes() metoda prihvaća samo popise koji pohranjuju podtipove boje. Prihvaća popis predmeta RedColor ili BlueColor, ali ne prihvaća popis predmeta Animal. To je zato što Životinja nije podvrsta Boje. Ovo je primjer gornjeg ograničenog zamjenskog znaka.

Donji ograničeni zamjenski znakovi

Slično tome, da imamo:

public void printSuperTypes(List list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
} }

zatim, printSuperTypes() metoda prihvaća samo popise koji pohranjuju super tipove klase Dog. Prihvatio bi popis predmeta sisavaca ili životinja, ali ne i popis objekata LabDog, jer LabDog nije superrazred pasa, već podrazred. Ovo je primjer donjeg ograničenog zamjenskog znaka.

Zaključak

Java Generics postala je značajka bez koje programeri ne mogu živjeti od njenog uvođenja.

Ova popularnost posljedica je utjecaja na olakšavanje života programera. Osim što ih sprječava u pogreškama u kodiranju, upotreba generičkih kodova čini kod manje ponavljanim. Jeste li primijetili kako generalizira klase i metode kako bi se izbjeglo ponavljanje koda za različite tipove podataka?

Dobro poznavanje generičkih lijekova važno je da biste postali stručnjak za jezik. Dakle, primjena onoga što ste naučili iz ovog vodiča u praktičnom kodu je način da se sada ide naprijed.