Hei! I dag skal vi se på en viktig mekanisme: arv i nestede klasser. Har du noen gang tenkt på hva du ville gjort hvis du trengte å få en nestet klasse til å arve en annen klasse. Hvis ikke, tro meg: denne situasjonen kan være forvirrende, fordi det er mange nyanser.
- Får vi en nestet klasse til å arve en eller annen klasse? Eller får vi en klasse til å arve en nestet klasse?
- Er barne-/foreldreklassen en vanlig offentlig klasse, eller er det også en nestet klasse?
- Til slutt, hvilken type nestede klasser bruker vi i alle disse situasjonene?
Statiske nestede klasser
Deres arveregler er de enkleste. Her kan du gjøre nesten alt du måtte ønske. En statisk nestet klasse kan arve:- en vanlig klasse
- en statisk nestet klasse som er deklarert i en ytre klasse eller dens forfedre
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
La oss prøve å endre koden og lage en Drawing
statisk nestet klasse og dens etterkommer - Boeing737Drawing
.
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Som du kan se, ikke noe problem. Vi kan til og med trekke ut Drawing
klassen og gjøre den til en vanlig offentlig klasse i stedet for en statisk nestet klasse - ingenting vil endre seg.
public class Drawing {
}
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Vi forstår dette. Men hvilke klasser kan arve en statisk nestet klasse? Praktisk talt alle! Nestet/ikke-nestet, statisk/ikke-statisk — det spiller ingen rolle. Her får vi den Boeing737Drawing
indre klassen til å arve den Drawing
statiske nestede klassen:
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public class Boeing737Drawing extends Drawing {
public int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Du kan lage en forekomst av Boeing737Drawing
slik:
public class Main {
public static void main(String[] args) {
Boeing737 boeing737 = new Boeing737(1990);
Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
System.out.println(drawing.getMaxPassengersCount());
}
}
Selv om klassen vår Boeing737Drawing
arver en statisk klasse, er den ikke statisk i seg selv! Som et resultat vil den alltid trenge en forekomst av den ytre klassen. Vi kan fjerne Boeing737Drawing
klassen fra Boeing737
klassen og gjøre den til en enkel offentlig klasse. Ingenting endrer seg. Den kan fortsatt arve den Drawing
statiske nestede klassen.
public class Boeing737 {
private int manufactureYear;
public static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
}
public class Boeing737Drawing extends Boeing737.Drawing {
public int getMaxPassengersCount() {
return Boeing737.maxPassengersCount;
}
Det eneste viktige poenget er at i dette tilfellet må vi gjøre den statiske maxPassengersCount
variabelen offentlig. Hvis det forblir privat, vil ikke en vanlig offentlig klasse ha tilgang til det. Vi har funnet ut statiske klasser! :) La oss nå gå videre til indre klasser. De kommer i 3 typer: enkle indre klasser, lokale klasser og anonyme indre klasser. Igjen, la oss gå fra enkelt til komplekst :)
Anonyme indre klasser
En anonym indre klasse kan ikke arve en annen klasse. Ingen annen klasse kan arve en anonym klasse. Det kunne ikke vært enklere! :)Lokale klasser
Lokale klasser (i tilfelle du har glemt det) er deklarert i en kodeblokk av en annen klasse. Oftest skjer dette innenfor en eller annen metode i den ytre klassen. Logisk sett kan bare andre lokale klasser innenfor samme metode (eller kodeblokk) arve en lokal klasse. Her er et eksempel:
public class PhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
class CellPhoneNumber extends PhoneNumber {
}
class LandlinePhoneNumber extends PhoneNumber {
}
// ...number validation code
}
}
Dette er koden fra leksjonen vår om lokale klasser. Vår nummervalideringsklasse har en PhoneNumber
lokal klasse. Hvis vi trenger det for å representere to forskjellige enheter, for eksempel et mobiltelefonnummer og et fasttelefonnummer, kan vi bare gjøre dette innenfor samme metode. Årsaken er enkel: en lokal klasses omfang er begrenset til metoden (kodeblokken) der den er deklarert. Som et resultat vil vi ikke kunne bruke den eksternt (inkludert for klassearv). Mulighetene for arv innenfor selve lokalklassen er imidlertid mye bredere! En lokal klasse kan arve:
- En vanlig klasse.
- En indre klasse som er erklært i samme klasse som den lokale klassen eller i en av dens forfedre.
- En annen lokal klasse erklært i samme metode (kodeblokk).
public class PhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
Her fjernet vi PhoneNumber
klassen fra validatePhoneNumber()
metoden og gjorde den til en indre klasse i stedet for en lokal klasse. Dette hindrer oss ikke i å få våre 2 lokale klasser til å arve den. Eksempel 2 - "... eller i forfedrene til denne klassen." Nå er dette allerede mer interessant. Vi kan rykke PhoneNumber
enda høyere i arvekjeden. La oss erklære en abstrakt AbstractPhoneNumberValidator
klasse, som vil bli stamfaren til PhoneNumberValidator
klassen vår:
public abstract class AbstractPhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
}
Som du kan se, erklærte vi det ikke bare – vi flyttet også den PhoneNumber
indre klassen inn i det. Men i sin etterkommer PhoneNumberValidator
kan lokale klasser deklarert i metoder arve PhoneNumber
uten problemer!
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
På grunn av arveforholdet "ser" de lokale klassene i en etterkommerklasse de indre klassene inne i en stamfar. Og til slutt, la oss gå videre til den siste gruppen :)
Indre klasser
En indre klasse erklært i samme ytre klasse (eller i dens etterkommer) kan arve en annen indre klasse. La oss utforske dette ved å bruke vårt eksempel med sykler fra leksjonen om indre klasser.
public class Bicycle {
private String model;
private int maxWeight;
public Bicycle(String model, int maxWeight) {
this.model = model;
this.maxWeight = maxWeight;
}
public void start() {
System.out.println("Let's go!");
}
class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
class SportSeat extends Seat {
// ...methods
}
}
Her erklærte vi den Seat
indre klassen inne i Bicycle
klassen. En spesiell type racersete, SportSeat
, arver det. Men vi kan lage en egen "racersykkel"-type og sette den i en egen klasse:
public class SportBicycle extends Bicycle {
public SportBicycle(String model, int maxWeight) {
super(model, maxWeight);
}
class SportSeat extends Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
Dette er også et alternativ. Den indre klassen til etterkommeren ( SportBicycle.SportSeat
) "ser" de indre klassene til forfaren og kan arve dem. Å arve indre klasser har en veldig viktig egenskap! I de to foregående eksemplene SportSeat
var klassen vår en indre klasse. Men hva om vi bestemmer oss for å lage SportSeat
en vanlig offentlig klasse som samtidig arver den Seat
indre klassen?
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {
public SportSeat() {
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
Vi fikk en feil! Kan du gjette hvorfor? :) Det hele er enkelt. Da vi snakket om den Bicycle.Seat
indre klassen, nevnte vi at en referanse til en forekomst av den ytre klassen implisitt overføres til konstruktøren av den indre klassen. Dette betyr at du ikke kan lage et Seat
objekt uten å lage et Bicycle
objekt. Men hva med opprettelsen av en SportSeat
? I motsetning til Seat
, har den ikke denne innebygde mekanismen for implisitt å sende konstruktøren en referanse til en forekomst av den ytre klassen. S till, uten et Bicycle
objekt, kan vi ikke lage et SportSeat
objekt, akkurat som i tilfellet med Seat
. Derfor er det bare én ting igjen for oss å gjøre - eksplisitt gi konstruktøren SportSeat
en referanse til et Bicycle
objekt. Slik gjør du det:
class SportSeat extends Bicycle.Seat {
public SportSeat(Bicycle bicycle) {
bicycle.super();
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
Vi kaller superklassekonstruktøren ved å bruke super();
Now, hvis vi ønsker å lage et SportSeat
objekt, vil ingenting stoppe oss fra å gjøre dette:
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle("Peugeot", 120);
SportSeat peugeotSportSeat = new SportSeat(bicycle);
}
}
Puh! Denne leksjonen var ganske lang :) Men du lærte mye! Nå er det på tide å løse noen oppgaver! :)
GO TO FULL VERSION