1. Alle klasser arverObject
Alle klasser i Java arver implisitt Object
klassen.
Vi vil analysere hva arv er og hvordan det fungerer i Java i Java Core-oppdraget. For nå skal vi vurdere ett enkelt faktum som følger av dette:
Et objekt av en hvilken som helst klasse kan tilordnes til en Object
variabel. Eksempel:
Kode | Merk |
---|---|
|
Variabelen o lagrer en referanse til et Scanner objekt |
|
Variabelen o lagrer en referanse til et String objekt |
|
Variabelen o lagrer en referanse til et Integer objekt |
|
Variabelen o lagrer en referanse til et String objekt |
Det er her de gode nyhetene slutter. Kompilatoren holder ikke styr på den opprinnelige typen objekt som er lagret i en Object
variabel, så du vil ikke kunne kalle andre metoder på det lagrede objektet enn metodene til Object
klassen.
Hvis du trenger å kalle metodene knyttet til objektets opprinnelige type, må du først lagre en referanse til den i en variabel av riktig type, og deretter kalle metodene på den variabelen:
Kode | Merk |
---|---|
|
Programmet vil ikke kompilere. Klassen Object har ingen nextInt() metode. |
|
Dette vil fungere. Her lagrer vi en referanse til et Scanner objekt i en Scanner variabel ved hjelp av en typecast-operator . |
Du kan ikke bare gå og tilordne en Object
variabel til en Scanner-variabel, selv om Object
variabelen lagrer en referanse til et Scanner
objekt. Men du kan gjøre dette hvis du bruker typecast-operatoren , som du allerede vet om. Dette er dens generelle utseende:
Type name1 = (Type) name2;
Hvor name1
er navnet på en Type
variabel, og name2
er navnet på en Object
variabel som lagrer en referanse til et Type
objekt.
Typecasting
Hvis variabelens type og objektets type ikke samsvarer, vil a ClassCastException
bli kastet. Eksempel:
Kode | Merk |
---|---|
|
En feil vil oppstå under kjøring: a ClassCastException vil bli kastet her |
Det er en måte å unngå denne feilen i Java: vi gjør dette ved å sjekke typen objekt som er lagret i en variabel :
name instanceof Type
Operatøren instanceof
sjekker om name
variabelen er et Type
objekt.
Som et eksempel, la oss finne en streng i en rekke forskjellige objekter:
Kode | Merk |
---|---|
|
Autoboksing vil konvertere disse verdiene til henholdsvis Integer , String , og Double . Sløyfe over utvalget av objekter Hvis objektet er en String Lagre det i en String variabel Vis variabelen på skjermen. |
2. Hvorfor generika dukket opp - samlinger
La oss gå tilbake til samlingene.
Så snart Java-utviklere opprettet ArrayList
klassen, ønsket de å gjøre den universell, slik at den kunne lagre alle typer objekter. Så de brukte en rekke Object
s for å lagre elementene.
Styrken med denne tilnærmingen er at du kan legge til et objekt av enhver type i samlingen.
Selvfølgelig er det flere svakheter.
Ulempe 1.
Det var alltid nødvendig å skrive en typekonverteringsoperator når du henter elementer fra en samling:
Kode | Merk |
---|---|
|
Opprett en samling for å lagre referanser til Object objekter Fyll samlingen med tall 10 , 20 , ... 100 ; Sum elementene i samlingen Typecasting er nødvendig |
Ulempe 2.
Det var ingen garanti for at en samling inneholder en bestemt type element
Kode | Merk |
---|---|
|
Opprett en samling for å lagre referanser til Object objekter Vi fyller samlingen med tall representert som Double objekter: 0.0 , 2.5 , 5.0 , ... Sum elementene i samlingen Det vil oppstå en feil: a Double kan ikke kastes til enInteger |
Data kan legges inn i samlingen hvor som helst:
- i en annen metode
- i et annet program
- fra en fil
- over nettverket
Ulempe 3.
Dataene i samlingen kan endres ved et uhell.
Du kan overføre en samling fylt med dataene dine til en eller annen metode. Denne metoden, skrevet av en annen programmerer, legger dataene til samlingen din.
Navnet på samlingen indikerer ikke tydelig hvilke typer data som kan lagres i den. Og selv om du gir variabelen din et klart navn, kan en referanse til den overføres til et dusin metoder, og disse metodene vil definitivt ikke vite noe om det opprinnelige navnet på variabelen.
3. Generiske legemidler
I Java elimineres alle disse problemene av denne kule tingen som kalles generika.
I Java betyr generikk muligheten til å legge til typeparametere til typer. Resultatet er en kompleks kompositttype. Det generelle synet på en slik sammensatt type er dette:
ClassName<TypeParameter>
Dette er en generisk klasse. Og den kan brukes uansett hvor du vanligvis bruker klasser.
Kode | Beskrivelse |
---|---|
|
Opprette variabler |
|
Opprette objekter |
|
Opprette arrays |
Bare Integer
variabler kan lagres i en slik samling:
Kode | Beskrivelse |
---|---|
|
ArrayList samling med Integer elementer Dette er tillatt Og dette vil også fungere
Autoboksing
Men dette er ikke tillatt: kompileringsfeil |
Du vil lære hvordan du lager dine egne klasser med typeparametere i Java Collections-oppdraget. Foreløpig skal vi se på hvordan du bruker dem og hvordan de fungerer.
4. Hvordan generika fungerer
Egentlig er generika fryktelig primitive.
Kompilatoren erstatter ganske enkelt generiske typer med vanlige typer. Men når metoder av en generisk type brukes, legger kompilatoren til en typecast-operatør for å kaste parametere til typeparameterne:
Kode | Hva kompilatoren gjør |
---|---|
|
|
|
|
|
|
|
|
Anta at vi har en metode som summerer tallene i en samling av heltall:
Kode | Hva kompilatoren gjør |
---|---|
|
|
Generika er med andre ord en slags syntaktisk sukker, akkurat som autoboksing, men litt mer. Med autoboksing legger kompilatoren til metoder for å konvertere en int
til en Integer
og omvendt, og for generiske stoffer legger den til typecast-operatører.
Etter at kompilatoren har kompilert de generiske klassene dine med typeparametere, blir de ganske enkelt konvertert til vanlige klasser og typecast-operatører. Informasjon om typeargumentene som sendes til variabler av generiske typer går tapt. Denne effekten kalles også type sletting .
Noen ganger trenger programmerere som skriver generiske klasser (klasser med typeparametere) virkelig informasjonen om typene som sendes som argumenter. I Java Collections-oppdraget lærer du hvordan du håndterer dette og hva det innebærer.
5. Noen få fakta om generiske legemidler
Her er noen flere interessante fakta om generika.
Klasser kan ha flere typeparametere. Det ser omtrent slik ut:
ClassName<TypeParameter1, TypeParameter2, TypeParameter3>
Egentlig er dette egentlig ikke overraskende. Hvor som helst hvor kompilatoren kan legge til en operatør for å kaste til én type, kan den legge til flere typecast-operatører.
Eksempler:
Kode | Merk |
---|---|
|
Metodens put første parameter er en Integer , og den andre er enString |
Generiske typer kan også brukes som parametere . Det ser omtrent slik ut:
ClassName<TypeParameter<TypeParameterParameter>>
Anta at vi ønsker å lage en liste som vil lagre lister med strenger. I dette tilfellet får vi noe slikt:
// 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 typeparametere) kan også brukes som matrisetyper. Det ser omtrent slik ut:
ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];
Det er ikke noe magisk som skjer her: vinkelparentesene indikerer bare typenavnet:
Kode | Ikke-generisk motstykke |
---|---|
|
|
|
|
|
|