1. Toate clasele moștenescObject

Toate clasele din Java moștenesc implicit Objectclasa.

Vom analiza ce este moștenirea și cum funcționează ea în Java în misiunea Java Core. Pentru moment, vom lua în considerare un fapt simplu care decurge din aceasta:

Un obiect din orice clasă poate fi atribuit unei Objectvariabile. Exemplu:

Cod Notă
Object o = new Scanner(System.in);
Variabila ostochează o referință la un Scannerobiect
Object o = new String();
Variabila ostochează o referință la un Stringobiect
Object o = new Integer(15);
Variabila ostochează o referință la un Integerobiect
Object o = "Hello";
Variabila ostochează o referință la un Stringobiect

Aici se termină vestea bună. Compilatorul nu ține evidența tipului original de obiect salvat într-o Objectvariabilă, așa că nu veți putea apela metode pe obiectul salvat, altele decât metodele clasei Object.

Dacă trebuie să apelați metodele asociate cu tipul original al obiectului, atunci trebuie să salvați mai întâi o referință la acesta într-o variabilă de tipul corect, apoi să apelați metodele pe acea variabilă:

Cod Notă
Object o = new Scanner(System.in);
int x = o.nextInt();
Programul nu se va compila. Clasa Objectnu are nicio nextInt()metodă.
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

int x = console.nextInt();
Acest lucru va funcționa.

Aici salvăm o referință la un Scannerobiect într-o Scannervariabilă utilizând un operator typecast .

Nu puteți să atribuiți o Objectvariabilă unei variabile Scanner, chiar dacă Objectvariabila stochează o referință la un Scannerobiect. Dar puteți face acest lucru dacă utilizați operatorul typecast , despre care știți deja. Acesta este aspectul său general:

Type name1 = (Type) name2;

Unde name1este numele unei Typevariabile și name2este numele unei Objectvariabile care stochează o referință la un Typeobiect.

Tipare

Dacă tipul variabilei și tipul obiectului nu se potrivesc, atunci ClassCastExceptionva fi aruncat a. Exemplu:

Cod Notă
Object o = new Integer(5);
String s = (String) o;
Va apărea o eroare în timpul execuției: aici va fi aruncat
aClassCastException

Există o modalitate de a evita această eroare în Java: facem acest lucru verificând tipul obiectului stocat într-o variabilă :

name instanceof Type

Operatorul instanceofverifică dacă namevariabila este un Typeobiect.

De exemplu, să găsim un șir într-o matrice de diverse obiecte:

Cod Notă
Object[] objects = {10, "Hello", 3.14};

for (int i = 0; i < objects.length; i++)
{
   if (objects[i] instanceof String)
   {
      String s = (String) objects[i];
      System.out.println(s);
   }
}
Autoboxing va converti aceste valori într-un Integer, String, și Double, respectiv.

Buclă peste matricea de obiecte

Dacă obiectul este un String

Salvare într-o Stringvariabilă
Afișează variabila pe ecran.


2. De ce au apărut genericele — colecții

Să revenim la colecții.

De îndată ce dezvoltatorii Java au creat ArrayListclasa, au vrut să o facă universală, astfel încât să poată stoca orice tip de obiect. Deci au folosit o serie de Objects pentru a stoca elementele.

Punctul forte al acestei abordări este că puteți adăuga un obiect de orice tip la colecție.

Desigur, există mai multe puncte slabe.

Dezavantaj 1.

A fost întotdeauna necesar să scrieți un operator de conversie de tip atunci când recuperați elemente dintr-o colecție:

Cod Notă
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 10);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Creați o colecție pentru a stoca referințe la Objectobiecte

Umpleți colecția cu numere 10, 20, ... 100;



Însumați elementele colecției


Typecasting este necesar

Dezavantaj 2.

Nu exista nicio garanție că o colecție conține un anumit tip de element

Cod Notă
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 2.5);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Creați o colecție pentru a stoca referințe la Objectobiecte

Umplem colecția cu numere reprezentate ca Doubleobiecte:
0.0, 2.5, 5.0, ...


Însumăm elementele colecției


Va apărea o eroare: a Doublenu poate fi turnat într-unInteger

Datele pot fi introduse în colecție oriunde:

  • într-o altă metodă
  • într-un alt program
  • dintr-un dosar
  • prin rețea

Dezavantaj 3.

Datele din colecție pot fi modificate accidental.

Puteți trece o colecție plină cu datele dvs. către o anumită metodă. Această metodă, scrisă de un alt programator, adaugă datele sale la colecția ta.

Numele colecției nu indică clar ce tipuri de date pot fi stocate în ea. Și chiar dacă dați variabilei dvs. un nume clar, o referință la aceasta poate fi transmisă la o duzină de metode, iar acele metode cu siguranță nu vor ști nimic despre numele original al variabilei.


3. Generice

Generic în Java

În Java, toate aceste probleme sunt eliminate de acest lucru grozav numit generice.

În Java, genericele înseamnă capacitatea de a adăuga parametri de tip la tipuri. Rezultatul este un tip compozit complex. Vederea generală a unui astfel de tip compozit este următoarea:

ClassName<TypeParameter>

Aceasta este o clasă generică. Și poate fi folosit oriunde folosiți în mod normal cursurile.

Cod Descriere
ArrayList<Integer> list;
Crearea variabilelor
list = new ArrayList<Integer> ();
Crearea obiectelor
ArrayList<Integer>[] array;
Crearea de tablouri

IntegerÎntr-o astfel de colecție pot fi stocate doar variabile:

Cod Descriere
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Hello");
ArrayListcolectare cu Integerelemente
Acest lucru este permis
Și va funcționa și asta
Autoboxing

Dar acest lucru nu este permis: eroare de compilare

Veți învăța cum să vă creați propriile clase cu parametri de tip în misiunea Java Collections. Deocamdată, ne vom uita la cum să le folosim și cum funcționează.


4. Cum funcționează genericele

De fapt, genericele sunt teribil de primitive.

Compilatorul înlocuiește pur și simplu tipurile generice cu tipuri obișnuite. Dar atunci când sunt utilizate metode de tip generic, compilatorul adaugă un operator de tipar pentru a arunca parametrii la parametrii de tip:

Cod Ce face compilatorul
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList list = new ArrayList();
list.add(1);
list.add( (Integer) 1 );
int x = list.get(0);
int x = (Integer) list.get(0);
list.set(0, 10);
list.set(0, (Integer) 10);

Să presupunem că avem o metodă care însumează numerele dintr-o colecție de numere întregi:

Cod Ce face compilatorul
public int sum(ArrayList<Integer> numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + numbers.get(i);

   return result;
}
public int sum(ArrayList numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + (Integer) numbers.get(i);

   return result;
}

Cu alte cuvinte, genericele sunt un fel de zahăr sintactic, la fel ca autoboxing-ul, dar puțin mai mult. Cu autoboxing, compilatorul adaugă metode pentru conversia an intîn an Integerși invers, iar pentru generice adaugă operatori typecast.

După ce compilatorul compilează clasele dvs. generice cu parametrii de tip, acestea sunt pur și simplu convertite în clase obișnuite și operatori typecast. Informațiile despre argumentele tip transmise variabilelor de tipuri generice se pierd. Acest efect se mai numește și ștergere de tip .

Uneori, programatorii care scriu clase generice (clase cu parametri de tip) chiar au nevoie de informații despre tipurile transmise ca argumente. În misiunea Java Collections, veți învăța cum să faceți față acestui lucru și ce implică.



5. Câteva fapte despre generice

Iată câteva fapte mai interesante despre medicamente generice.

Clasele pot avea mai mulți parametri de tip. Arata cam asa:

ClassName<TypeParameter1, TypeParameter2, TypeParameter3>

De fapt, acest lucru nu este chiar surprinzător. Oriunde compilatorul poate adăuga un operator pentru a turna la un singur tip, poate adăuga mai mulți operatori de tipare.

Exemple:

Cod Notă
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Hello");
map.put(-15, "Hello");
Primul putparametru al metodei este an Integer, iar al doilea este aString

Tipurile generice pot fi folosite și ca parametri . Arata cam asa:

ClassName<TypeParameter<TypeParameterParameter>>

Să presupunem că vrem să creăm o listă care să stocheze liste de șiruri. În acest caz, vom obține ceva de genul acesta:

// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");

// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");

// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);

Tipurile generice (tipuri cu parametri de tip) pot fi, de asemenea, utilizate ca tipuri de matrice. Arata cam asa:

ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];

Nu se întâmplă nimic magic aici: parantezele unghiulare indică doar numele tipului:

Cod Omologul negeneric
ArrayList<String>[] list = new ArrayList<String>[10];
StringArrayList[] list = new StringArrayList[10];
ArrayList<Integer>[] list = new ArrayList<Integer>[10];
IntegerArrayList[] list = new IntegerArrayList[10];
ArrayList<Scanner>[] list = new ArrayList<Scanner>[10];
ScannerArrayList[] list = new ScannerArrayList[10];