Generice Java

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare

1leftarrow blue.svg Intrare principală: Java 5 .

JDK 1.5 a introdus câteva extensii în limbajul Java . Una dintre acestea este introducerea de generice sau tipuri generice . Un generic este un instrument care permite definirea unui tip parametrizat, care este explicat ulterior în faza de compilare, după cum este necesar; genericele vă permit să definiți abstracții asupra tipurilor de date definite în limbă.

Caracteristici

Există mai multe avantaje în utilizarea genericelor:

  • Oferă o mai bună gestionare a verificării tipului în timpul compilării;
  • Evitați aruncarea din obiect. Adică ;
  • Evitați greșelile datorate turnării necorespunzătoare

În loc să utilizați (cod care ar putea genera o eroare de turnare):

 Titlul șirului = (( Șir ) cuvinte . Obțineți ( i )). toUppercase ();

sau mai corect pentru a evita greșelile

 Obiectul o = cuvinte . obține ( i );
String title = "" ;
if ( sau instanceof String )
     title = (( String ) o . get ( i )). toUppercase ();

va fi folosit:

 Titlul șirului = cuvinte . obține ( i ). toUppercase ();

Cu toate acestea, există și dezavantaje:

Se definește:

 Listă < String > cuvinte = new ArrayList < String > ();

in loc de:

 Lista cuvinte = new ArrayList ();

Cel mai frecvent exemplu de utilizare a acestora este în definirea / utilizarea așa-numitelor containere . Înainte de lansarea JDK 1.5, pentru a gestiona în mod transparent diferite tipuri de date, a fost necesar să recurgem la faptul că în Java fiecare clasă derivă implicit din clasa Object . De exemplu, dacă trebuia să implementați o listă legată , codul era următorul:

 Listează myIntList = new LinkedList ();
myIntList . add ( nou întreg ( 0 ));

și, în schimb, pentru a recupera elementul introdus, a trebuit să scrieți

 Integer x = ( Integer ) myIntList . iterator (). next ();

Rețineți distribuția la Integer necesară, deoarece myIntList funcționează de fapt pe obiecte Object . De la introducerea JDK 1.5 în schimb, este posibil să se utilizeze un cod ca următorul:

 Listă < Integer > myIntList = new LinkedList < Integer > ();
myIntList . add ( nou întreg ( 0 ));

unde se afirmă în mod explicit că myIntList va funcționa numai pe obiecte de tip Integer . Pentru a recupera elementul introdus, codul este după cum urmează:

 Integer x = myIntList . iterator (). next ();

Rețineți că distribuția nu mai este necesară, deoarece lista este de numere întregi.

Implementare

Java 5 nu a extins limbajul bytecode pentru a implementa generice. Aceasta înseamnă că genericele sunt într-adevăr doar constructe sintactice, emulate la nivelul bytecode-ului prin mecanismul obișnuit al clasei Object (descris mai sus). [1] Declarați

 Listă < Integer > myIntList = new LinkedList < Integer > ();

este echivalent programatic cu declararea

 Listează myIntList = new LinkedList (); // Lista obiectului

și să efectueze implicit conversii Object-> Integer și Integer-> Object pentru a citi și a scrie elemente.

Prin urmare, genericele au eliminat problemele legate de tastare; acum elementele listei trebuie să fie Număr întreg și nu (de exemplu) Șir și această verificare se efectuează la compilare.

Ştergere

Ștergerea este procesul care convertește programul codificat cu generice în forma fără acestea, care reflectă cel mai îndeaproape codul secundar produs. Acest termen nu este pe deplin corect deoarece genericele sunt eliminate, dar sunt adăugate și distribuții. Adăugarea acestor distribuții nu este explicită, iar limbajul proiectului oferă garanția din fontă : adică distribuția implicită adăugată la compilarea genericelor: nu poate da greș niciodată. Aceasta este o regulă care se aplică codului care nu are avertismente necontrolate . Avantajele implementării prin Erasure sunt:

  • păstrați lucrurile simple fără a adăuga detalii sau orice altceva;
  • păstrați lucrurile mici, de exemplu, cu o singură implementare a Listei;
  • pentru a simplifica evoluția, aceeași bibliotecă poate fi accesată din coduri generice și coduri vechi.

Dacă un element Y derivă dintr-un element X, nu se poate spune că o colecție de elemente din Y derivă din colecția elementelor X, deoarece, în general, aceasta este o operație imposibilă; numai unele dintre acestea ar putea fi chiar sigure, mai ales în ceea ce privește matricele și citirea, dar acest lucru nu este adevărat în general.

Să luăm în considerare clasa generică LinkedList <T> : să luăm două dintre instanțele sale: LinkedList <Number> și LinkedList <Integer> . Sunt două tipuri diferite, incompatibile între ele, chiar dacă Numărul întreg extinde Numărul ; situație spre deosebire de cea care apare în matrice, unde Numărul întreg [] este un subtip de Număr [] . Pentru a verifica acest lucru, să creăm două liste:

 LinkedList < Number > l1 = new LinkedList < Number > ();
 LinkedList < Integer > l2 = new LinkedList < Integer > ();

Și considerăm cele două atribuții posibile l1 = l2 și l2 = l1; în orice caz primiți o eroare deoarece LinkedList <Integer> nu extinde LinkedList <Number> .

Anterior, atribuțiile sunt imposibile, deoarece principiul substituției este încălcat: unei variabile de un anumit tip i se poate atribui o valoare de orice subtip; o metodă cu un argument de un anumit tip poate fi apelată cu un argument de orice subtip.

 Listă < Număr > numere = new ArrayList < Număr > ();
numere . adăugați ( 2 );
numere . adăugați ( 3.14d );
afirma numere . toString (). egal ( "[2, 3.14]" );

Aici principiul se aplică între List și ArrayList și, respectiv, între Number și Integer Double . Lista <Integer>, pe de altă parte, nu este un subtip al Listei <Number>, deoarece principiul de înlocuire este încălcat din nou, de exemplu:

 Listă < Număr întreg > întregi = Matrice . asList ( 1 , 2 );
Listă < Număr > numere = numere întregi ; // nu compilați
numere . adăugați ( 3.14d );
afirmă numere întregi . toString (). egal ( "[1, 2,3.14]" );

Tipuri parametrice variabile (wildcard)

Nu poate exista o compatibilitate generală între tipurile parametrice. Dacă sunteți în căutarea compatibilității, trebuie să luați în considerare cazuri specifice și tipuri de parametri ai metodelor individuale. Astfel, notația normală de tip List <T> generică, utilizată pentru a crea obiecte, este însoțită de o nouă notație, concepută pentru a exprima tipuri acceptabile ca parametri în metode unice.

Prin urmare, vorbim despre tipuri parametrice variabile, în Java numite metacaracter .

Deoarece notația List <T> denotă tipul generic normal, se introduc următoarele notații cu metacaracter :

  • tip covariant List <? extinde T> : captează proprietățile Listei <X> unde X extinde T ; este folosit pentru a specifica tipuri care pot fi citite numai.
  • tip contravariant List <? super T> : captează proprietățile Listei <X> unde X este extins cu T ; este folosit pentru a specifica tipuri care pot fi scrise numai.
  • tip bivariant List <?> : captează toate List <T> fără distincție; este folosit pentru a specifica tipuri care nu permit citiri sau scrieri.

Definiția unei clase generice

Iată un exemplu de clasă generică

 public class Gen < X , Y > {

  privat final X var1 ;
  privat Y var2 final ;

  publice Gen (X x Y y) {  
    var1 = x ;
    var2 = y ;   
  }

  public X getVar1 () {
    retur var1 ;
  }

  public Y getVar2 () {
    retur var2 ;
  }
 
  public String toString () { 
    returnează "(" + var1 + "," + var2 + ")" ;  
  }
}

Această clasă nu este utilă de la sine, deci trebuie folosită o altă structură, ca în exemplul următor:

 Gen < String , String > example1 = new Gen < String , String > ( "exemplu" , "unul" );
Gen < String , Integer > example2 = new Gen < String , Integer > ( "exemplu" , 2 );

Sistem . afară . println ( "primul exemplu:" + exemplu1 );
Sistem . afară . println ( "al doilea exemplu:" + exemplu2 );

Notă

Informatică Portal IT : accesați intrările Wikipedia care se ocupă cu IT