"Amigo, kan du lide hvaler?"
"Hvaler? Nej, aldrig hørt om dem."
"Den er ligesom en ko, kun større og den svømmer. I øvrigt kom hvaler fra køer. Øh, eller i det mindste deler de en fælles forfader. Det er lige meget."
"Lyt op. Jeg vil gerne fortælle dig om et andet meget kraftfuldt OOP-værktøj: polymorfisme . Det har fire funktioner."
1) Metode tilsidesættelse.
Forestil dig, at du har skrevet en "ko"-klasse til et spil. Den har masser af medlemsvariabler og -metoder. Objekter i denne klasse kan gøre forskellige ting: gå, spise, sove. Køer ringer også med en klokke, når de går. Lad os sige, at du har implementeret alt i klassen ned til mindste detalje.
Så pludselig siger kunden, at han vil frigive et nyt niveau af spillet, hvor alle handlinger foregår i havet, og hovedpersonen er en hval.
Du begyndte at designe Whale-klassen og indse, at den kun er lidt anderledes end Cow-klassen. Begge klasser bruger meget ens logik, og du beslutter dig for at bruge arv.
Ko-klassen er ideel til at være forældreklassen: den har allerede alle de nødvendige variabler og metoder. Alt du skal gøre er at tilføje hvalens evne til at svømme. Men der er et problem: din hval har ben, horn og en klokke. Når alt kommer til alt, implementerer Cow-klassen denne funktionalitet. Hvad kan du gøre?
Metodetilsidesættelse kommer til undsætning. Hvis vi arver en metode, der ikke gør præcis, hvad vi har brug for i vores nye klasse, kan vi erstatte metoden med en anden.
Hvordan gøres dette? I vores efterkommerklasse erklærer vi den metode, som vi ønsker at ændre (med samme metodesignatur som i den overordnede klasse) . Så skriver vi ny kode til metoden. Det er det. Det er som om forældreklassens gamle metode ikke eksisterer.
Sådan fungerer det:
Kode | Beskrivelse |
---|---|
|
Her definerer vi to klasser: Cow og Whale . Whale arver Cow .
Klassen |
|
Denne kode viser " Jeg er en ko " på skærmen. |
|
Denne kode viser " Jeg er en hval " på skærmen |
Efter at den har arvet Cow
og tilsidesat printName
, Whale
har klassen faktisk følgende data og metoder:
Kode | Beskrivelse |
---|---|
|
Vi ved intet om nogen gammel metode. |
"Helt ærligt, det var det, jeg havde forventet."
2) Men det er ikke alt.
"Antag at Cow
klassen har en printAll
, metode, der kalder de to andre metoder. Så ville koden fungere sådan her:"
Skærmen vil vise:
Jeg er hvid,
jeg er en hval
Kode | Beskrivelse |
---|---|
|
|
|
Skærmen vil vise: Jeg er hvid, jeg er en hval |
Bemærk, at når Cow-klassens printAll ()-metode kaldes på et Whale-objekt, vil Whale's printName()-metoden blive brugt, ikke Cow's.
Det vigtige er ikke klassen metoden er skrevet i, men snarere typen (klasse) af det objekt, som metoden kaldes på.
"Jeg ser."
"Du kan kun arve og tilsidesætte ikke-statiske metoder. Statiske metoder nedarves ikke og kan derfor ikke tilsidesættes."
Sådan ser Whale-klassen ud, efter at vi har anvendt arv og tilsidesat metoderne:
Kode | Beskrivelse |
---|---|
|
Sådan ser Whale-klassen ud, efter at vi har anvendt arv og tilsidesat metoden. Vi ved intet om nogen gammel printName metode. |
3) Type støbning.
Her er et endnu mere interessant punkt. Fordi en klasse arver alle metoderne og dataene fra dens overordnede klasse, kan et objekt i denne klasse refereres af variabler fra den overordnede klasse (og forælderen til forælderen osv., lige op til Object-klassen). Overvej dette eksempel:
Kode | Beskrivelse |
---|---|
|
Skærmen vil vise: Jeg er hvid. |
|
Skærmen vil vise: Jeg er hvid. |
|
Skærmen vil vise: Whale@da435a. Metoden toString() er nedarvet fra klassen Object. |
"Gode ting. Men hvorfor skulle du bruge det her?"
"Det er en værdifuld funktion. Du vil senere forstå, at den er meget, meget værdifuld."
4) Sen binding (dynamisk afsendelse).
Sådan ser det ud:
Kode | Beskrivelse |
---|---|
|
Skærmen vil vise: Jeg er en hval. |
|
Skærmen vil vise: Jeg er en hval. |
Bemærk, at det ikke er typen af variabel, der bestemmer, hvilken specifik printName- metode vi kalder (den af Cow- eller Whale-klassen), men derimod typen af objekt, der refereres til af variablen.
Cow - variablen gemmer en reference til et Whale- objekt, og printName- metoden defineret i Whale- klassen vil blive kaldt.
"Jamen, det tilføjede de ikke for overskuelighedens skyld."
"Ja, det er ikke så indlysende. Husk denne vigtige regel:"
Sættet af metoder, du kan kalde på en variabel, bestemmes af variablens type. Men hvilken specifik metode/implementering der bliver kaldt, bestemmes af typen/klassen af objektet, som variablen refererer til.
"Jeg vil gøre et forsøg."
"Du vil løbe ind i det her konstant, så du vil hurtigt forstå det og aldrig glemme."
5) Type støbning.
Støbning fungerer anderledes for referencetyper, altså klasser, end det gør for primitive typer. Udvidelse og indsnævring af konverteringer gælder dog også for referencetyper. Overvej dette eksempel:
Udvidelseskonvertering | Beskrivelse |
---|---|
|
En klassisk udvidelseskonvertering. Nu kan du kun kalde metoder defineret i Cow-klassen på Whale-objektet. Compileren vil kun lade dig bruge ko-variablen til at kalde de metoder, der er defineret af ko-typen. |
Indsnævring af konvertering | Beskrivelse |
---|---|
|
En klassisk indsnævringskonvertering med typetjek. Kovariablen af typen Cow gemmer en reference til et hvalobjekt. Vi kontrollerer, at dette er tilfældet , og udfører derefter (udvidelses-) typekonverteringen. Dette kaldes også typestøbning . |
|
Du kan også udføre en indsnævrende konvertering af en referencetype uden at typetjekke objektet. I dette tilfælde, hvis ko- variablen peger på noget andet end et Whale-objekt, vil en undtagelse (InvalidClassCastException) blive kastet. |
6) Og nu til noget velsmagende. Kalder den oprindelige metode.
Nogle gange, når du tilsidesætter en nedarvet metode, ønsker du ikke helt at erstatte den. Nogle gange vil man bare tilføje en lille smule til det.
I dette tilfælde ønsker du virkelig, at den nye metodes kode skal kalde den samme metode, men på basisklassen. Og Java lader dig gøre dette. Sådan gøres det: super.method()
.
Her er nogle eksempler:
Kode | Beskrivelse |
---|---|
|
|
|
Skærmen vil vise: Jeg er hvid Dette er falsk: Jeg er en ko, jeg er en hval |
"Hmm. Nå, det var en lektie. Mine robotører smeltede næsten."
"Ja, det er ikke simple ting. Det er noget af det sværeste materiale, du vil støde på. Professoren lovede at give links til materialer fra andre forfattere, så hvis du stadig ikke forstår noget, kan du udfylde huller."
GO TO FULL VERSION