Arv
I de foregående lektioner har du set arv nævnt flere gange. På Java-sproget kan klasser afledes fra andre klasser og derved arve felter og metoder fra disse klasser.
Med undtagelse af
Object
, som ikke har nogen superklasse, har hver klasse en og kun en direkte superklasse (enkelt arv). I mangel af nogen anden eksplicit superklasse er hver klasse implicit en underklasse af Object
. Klasser kan afledes fra klasser, der er afledt af klasser, der er afledt af klasser, og så videre og i sidste ende afledt af den øverste klasse
Object
. En sådan klasse siges at stamme fra alle klasser i arvekæden, der strækker sig tilbage til Object
. Ideen om arv er enkel, men kraftfuld: Når du vil oprette en ny klasse, og der allerede er en klasse, der indeholder noget af den kode, du ønsker, kan du udlede din nye klasse fra den eksisterende klasse . Ved at gøre dette kan du genbruge felterne og metoderne i den eksisterende klasse uden at skulle skrive (og fejle!) Dem selv.
En underklasse arver alle medlemmerne (felter, metoder og indlejrede klasser) fra dens superklasse. Konstruktører er ikke medlemmer, så de arves ikke af underklasser, men superklassens konstruktør kan påberåbes fra underklassen.
Java Platform Class Hierarchy
Object
klasse, defineret i java.lang
pakken, definerer og implementerer adfærd, der er fælles for alle klasser – inklusive dem, du skriver. I Java-platformen stammer mange klasser direkte fra Object
, andre klasser stammer fra nogle af disse klasser og så videre og danner et hierarki af klasser.
Alle klasser i Java-platformen er efterkommere af objekt
Øverst i hierarkiet er Object
den mest generelle af alle klasser. Klasser nær bunden af hierarkiet giver mere specialiseret adfærd.
Et eksempel på arv
Her er prøvekoden til en mulig implementering af en Bicycle
klasse, der blev præsenteret i lektionen Klasser og objekter:
En klassedeklaration for en MountainBike
klasse, der er en underklasse af Bicycle
kan se sådan ud:
public class MountainBike extends Bicycle { // the MountainBike subclass adds one field public int seatHeight; // the MountainBike subclass has one constructor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { super(startCadence, startSpeed, startGear); seatHeight = startHeight; } // the MountainBike subclass adds one method public void setHeight(int newValue) { seatHeight = newValue; } }
MountainBike
arver alle felter og metoder i Bicycle
og tilføjer feltet seatHeight
og en metode til at indstille det. Bortset fra konstruktøren er det som om du havde skrevet en ny MountainBike
klasse helt fra bunden med fire felter og fem metoder. Du behøvede imidlertid ikke at udføre alt arbejdet. Dette ville være særligt værdifuldt, hvis metoderne i klassen Bicycle
var komplekse og havde taget lang tid at debugge.
Hvad du kan gøre i en underklasse
En underklasse arver alle de offentlige og beskyttede medlemmer af dets overordnede, uanset hvilken pakke underklassen er i. Hvis underklassen er i samme pakke som dens forælder, det arver også pakkens private medlemmer af forældrene. Du kan bruge de arvede medlemmer som de er, erstatte dem, skjule dem eller supplere dem med nye medlemmer:
- De arvede felter kan bruges direkte, ligesom alle andre felter.
- Du kan erklære et felt i underklassen med samme navn som det i superklassen og dermed skjule det (anbefales ikke).
- Du kan erklære nye felter i underklassen, der ikke er i superklassen.
- De arvede metoder kan bruges direkte, som de er.
- Du kan skrive en ny instansmetode i underklasse det har den samme signatur som den i superklassen og tilsidesætter den.
- Du kan skrive en ny statisk metode i underklassen, der har den samme signatur som den i superklassen, og dermed skjule den.
- Du kan erklære nye metoder i underklassen, der ikke er i superklassen.
- Du kan skrive en underklassekonstruktør, der påberåber konstruktøren af superklassen, enten implicit eller ved hjælp af nøgleordet
super
.
De følgende afsnit i denne lektion udvides om disse emner.
Private medlemmer i en superklasse
En underklasse arver ikke private
medlemmerne af sin overordnede klasse. Men hvis superklassen har offentlige eller beskyttede metoder til at få adgang til dens private felter, kan disse også bruges af underklassen.
En indlejret klasse har adgang til alle de private medlemmer af sin omsluttende klasse – både felter og metoder. Derfor har en offentlig eller beskyttet indlejret klasse arvet af en underklasse indirekte adgang til alle de private medlemmer af superklassen.
Casting Objects
Vi har set, at et objekt er af datatype for den klasse, hvorfra den blev instantificeret. For eksempel, hvis vi skriver
public MountainBike myBike = new MountainBike();
så er myBike
af typen MountainBike
.
MountainBike
stammer fra Bicycle
og Object
. Derfor er en MountainBike
en Bicycle
og er også en Object
, og det kan være bruges hvor som helst Bicycle
eller Object
objekter kræves.
Det omvendte er ikke nødvendigvis sandt: a Bicycle
kan være en MountainBike
, men det er ikke nødvendigvis. Tilsvarende kan en Object
være en Bicycle
eller en MountainBike
, men det er ikke nødvendigvis.
Casting viser brugen af et objekt af en skriv i stedet for en anden type, blandt de objekter, der er tilladt ved arv og implementeringer. For eksempel, hvis vi skriver
Object obj = new MountainBike();
så er obj
begge en Object
og en MountainBike
(indtil obj
tildeles et andet objekt, der ikke er et MountainBike
). Dette kaldes implicit casting.
Hvis vi derimod skriver
MountainBike myBike = obj;
ville vi få en kompileringstidsfejl, fordi obj
ikke er kendt af compileren for at være en MountainBike
. Vi kan dog fortælle kompilatoren, at vi lover at tildele en MountainBike
til obj
ved eksplicit casting:
MountainBike myBike = (MountainBike)obj;
Denne rollebesætning indsætter en runtime-kontrol af, at obj
er tildelt en MountainBike
så compileren med sikkerhed kan antage, at obj
er en MountainBike
. Hvis obj
ikke er en MountainBike
under kørsel, kastes en undtagelse.
instanceof
operatoren. Dette kan redde dig fra en runtime-fejl på grund af en forkert rollebesætning. For eksempel:
if (obj instanceof MountainBike) { MountainBike myBike = (MountainBike)obj;}
Her verificerer instanceof
operatøren, at obj
henviser til en MountainBike
, så vi kan gøre rollebesætningen med viden om, at der ikke bliver nogen runtime-undtagelse kastet.