1. Alle klasser arverObject

Alle klasser i Java arver implicit Objectklassen.

Vi vil analysere, hvad arv er, og hvordan det fungerer i Java i Java Core-questen. Indtil videre vil vi overveje en simpel kendsgerning, der følger af dette:

Et objekt af enhver klasse kan tildeles til en Objectvariabel. Eksempel:

Kode Bemærk
Object o = new Scanner(System.in);
Variablen ogemmer en reference til et Scannerobjekt
Object o = new String();
Variablen ogemmer en reference til et Stringobjekt
Object o = new Integer(15);
Variablen ogemmer en reference til et Integerobjekt
Object o = "Hello";
Variablen ogemmer en reference til et Stringobjekt

Det er her den gode nyhed slutter. Compileren holder ikke styr på den oprindelige type objekt, der er gemt i en Objectvariabel, så du vil ikke være i stand til at kalde metoder på det gemte objekt ud over klassens metoder Object.

Hvis du skal kalde de metoder, der er knyttet til objektets oprindelige type, skal du først gemme en reference til det i en variabel af den korrekte type, og derefter kalde metoderne på den variabel:

Kode Bemærk
Object o = new Scanner(System.in);
int x = o.nextInt();
Programmet vil ikke kompilere. Klassen Objecthar ingen nextInt()metode.
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

int x = console.nextInt();
Dette vil virke.

Her gemmer vi en reference til et Scannerobjekt i en Scannervariabel ved hjælp af en typecast-operator .

Du kan ikke bare gå og tildele en Objectvariabel til en Scanner-variabel, selvom Objectvariablen gemmer en reference til et Scannerobjekt. Men du kan gøre dette, hvis du bruger typecast-operatoren , som du allerede kender til. Dette er dens generelle udseende:

Type name1 = (Type) name2;

Hvor name1er navnet på en Typevariabel, og name2er navnet på en Objectvariabel, der gemmer en reference til et Typeobjekt.

Typecasting

Hvis variabelens type og objektets type ikke stemmer overens, ClassCastExceptionvil en blive kastet. Eksempel:

Kode Bemærk
Object o = new Integer(5);
String s = (String) o;
Der opstår en fejl under kørsel:
a ClassCastExceptionvil blive smidt her

Der er en måde at undgå denne fejl i Java: vi gør dette ved at kontrollere typen af ​​objektet, der er gemt i en variabel :

name instanceof Type

Operatøren instanceofkontrollerer, om namevariablen er et Typeobjekt.

Lad os som et eksempel finde en streng i en række forskellige objekter:

Kode Bemærk
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 vil konvertere disse værdier til henholdsvis en Integer, String, og Double.

Sløjfe over rækken af ​​objekter

Hvis objektet er en String

Gem det til en Stringvariabel
Vis variablen på skærmen.


2. Hvorfor generiske lægemidler dukkede op - samlinger

Lad os vende tilbage til samlinger.

Så snart Java-udviklere oprettede ArrayListklassen, ønskede de at gøre den universel, så den kunne gemme enhver type objekt. Så de brugte en række Objects til at gemme elementerne.

Styrken ved denne tilgang er, at du kan tilføje et objekt af enhver type til samlingen.

Selvfølgelig er der flere svagheder.

Ulempe 1.

Det var altid nødvendigt at skrive en typekonverteringsoperator, når man hentede elementer fra en samling:

Kode Bemærk
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);
}
Opret en samling for at gemme referencer til Objectobjekter

Fyld samlingen med tal 10, 20, ... 100;



Sum elementerne i samlingen


Typecasting er nødvendig

Ulempe 2.

Der var ingen garanti for, at en samling indeholder en bestemt type element

Kode Bemærk
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);
}
Opret en samling for at gemme referencer til Objectobjekter

Vi fylder samlingen med tal repræsenteret som Doubleobjekter:
0.0, 2.5, 5.0, ...


Sum elementerne i samlingen


Der vil være en fejl: a Doublekan ikke castes til enInteger

Data kan lægges ind i samlingen hvor som helst:

  • i en anden metode
  • i et andet program
  • fra en fil
  • over netværket

Ulempe 3.

Dataene i samlingen kan ændres ved et uheld.

Du kan videregive en samling fyldt med dine data til en eller anden metode. Denne metode, skrevet af en anden programmør, føjer sine data til din samling.

Navnet på samlingen angiver ikke klart, hvilke typer data der kan gemmes i den. Og selvom du giver din variabel et klart navn, kan en reference til den overføres til et dusin metoder, og disse metoder vil bestemt ikke vide noget om det oprindelige navn på variablen.


3. Generiske lægemidler

Generisk i Java

I Java er alle disse problemer elimineret af denne seje ting kaldet generika.

I Java betyder generisk evnen til at tilføje typeparametre til typer. Resultatet er en kompleks sammensat type. Den generelle opfattelse af en sådan sammensat type er dette:

ClassName<TypeParameter>

Dette er en generisk klasse. Og det kan bruges overalt, hvor du normalt bruger klasser.

Kode Beskrivelse
ArrayList<Integer> list;
Oprettelse af variabler
list = new ArrayList<Integer> ();
Oprettelse af objekter
ArrayList<Integer>[] array;
Oprettelse af arrays

Kun Integervariabler kan gemmes i en sådan samling:

Kode Beskrivelse
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Hello");
ArrayListsamling med Integerelementer
Dette er tilladt
Og det vil også virke
Autoboksning

Men dette er ikke tilladt: kompileringsfejl

Du lærer, hvordan du opretter dine egne klasser med typeparametre i Java Collections-questen. Indtil videre vil vi se på, hvordan man bruger dem, og hvordan de virker.


4. Hvordan generika virker

Faktisk er generiske lægemidler frygtelig primitive.

Compileren erstatter simpelthen generiske typer med almindelige typer. Men når metoder af en generisk type bruges, tilføjer compileren en typecast-operator til at caste parametre til typeparametrene:

Kode Hvad compileren gør
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);

Antag, at vi har en metode, der summerer tallene i en samling af heltal:

Kode Hvad compileren gør
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;
}

Med andre ord er generika en slags syntaktisk sukker, ligesom autoboxing, men lidt mere. Med autoboxing tilføjer compileren metoder til at konvertere en inttil en Integerog omvendt, og for generiske stoffer tilføjer den typecast-operatorer.

Efter compileren har kompileret dine generiske klasser med typeparametre, konverteres de simpelthen til almindelige klasser og typecast-operatorer. Information om typeargumenterne, der sendes til variabler af generiske typer, går tabt. Denne effekt kaldes også type sletning .

Nogle gange har programmører, der skriver generiske klasser (klasser med typeparametre), virkelig brug for informationen om de typer, der sendes som argumenter. I Java Collections-questen lærer du, hvordan du håndterer dette, og hvad det indebærer.



5. Et par fakta om generiske lægemidler

Her er nogle flere interessante fakta om generiske lægemidler.

Klasser kan have flere typeparametre. Det ser sådan ud:

ClassName<TypeParameter1, TypeParameter2, TypeParameter3>

Faktisk er dette ikke rigtig overraskende. Hvor som helst compileren kan tilføje en operator til at caste til én type, kan den tilføje flere typecast-operatorer.

Eksempler:

Kode Bemærk
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Hello");
map.put(-15, "Hello");
Metodens putførste parameter er en Integer, og den anden er enString

Generiske typer kan også bruges som parametre . Det ser sådan ud:

ClassName<TypeParameter<TypeParameterParameter>>

Antag, at vi vil oprette en liste, der gemmer lister med strenge. I dette tilfælde får vi noget som dette:

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

Generiske typer (typer med typeparametre) kan også bruges som arraytyper. Det ser sådan ud:

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

Der sker ikke noget magisk her: vinkelparenteserne angiver blot typenavnet:

Kode Ikke-generisk modstykke
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];