"Jeg vil fortælle dig om " adgangsmodifikatorer ". Jeg fortalte om dem en gang før, men gentagelse er en søjle for læring."
Du kan kontrollere den adgang (synlighed), som andre klasser har til din klasses metoder og variable. En adgangsmodifikator besvarer spørgsmålet «Hvem kan få adgang til denne metode/variabel?». Du kan kun angive én modifikator for hver metode eller variabel.
1) " offentlig " modifikator.
En variabel, metode eller klasse markeret med den offentlige modifikator kan tilgås fra hvor som helst i programmet. Dette er den højeste grad af åbenhed: Der er ingen begrænsninger.
2) « privat » modifikator.
En variabel, metode eller klasse markeret med den private modifikator kan kun tilgås i den klasse, hvor den er erklæret. Den markerede metode eller variabel er skjult fra alle andre klasser. Dette er den højeste grad af privatliv: kun tilgængelig for din klasse. Sådanne metoder nedarves ikke og kan ikke tilsidesættes. Derudover kan de ikke tilgås i en efterkommerklasse.
3) « Standardmodifikator ».
Hvis en variabel eller metode ikke er markeret med nogen modifikator, anses den for at være markeret med "standard" modifikatoren. Variabler og metoder med denne modifikator er synlige for alle klasser i pakken, hvor de er erklæret, og kun for disse klasser. Denne modifikator kaldes også " pakke " eller " pakke privat " adgang, hvilket antyder, at adgang til variabler og metoder er åben for hele pakken, der indeholder klassen.
4) « beskyttet » modifikator.
Dette adgangsniveau er lidt bredere end pakken . En variabel, metode eller klasse markeret med den beskyttede modifikator kan tilgås fra dens pakke (som "pakke") og fra alle nedarvede klasser.
Denne tabel forklarer det hele:
Type synlighed | Søgeord | Adgang | |||
---|---|---|---|---|---|
Din klasse | Din pakke | Descendent | Alle klasser | ||
Privat | privat | Ja | Ingen | Ingen | Ingen |
Pakke | (ingen modifikator) | Ja | Ja | Ingen | Ingen |
Beskyttet | beskyttet | Ja | Ja | Ja | Ingen |
Offentlig | offentlig | Ja | Ja | Ja | Ja |
Der er en måde, hvorpå du nemt kan huske denne tabel. Forestil dig, at du skriver et testamente. Du deler alle dine ting op i fire kategorier. Hvem skal bruge dine ting?
Hvem har adgang | Modifikator | Eksempel |
---|---|---|
Bare mig | privat | Personlig dagbog |
Familie | (ingen modifikator) | Familiebilleder |
Familie og arvinger | beskyttet | Familiegods |
Alle | offentlig | Erindringer |
"Det er meget som at forestille sig, at klasser i samme pakke er en del af en familie."
"Jeg vil også fortælle dig nogle interessante nuancer om overordnede metoder."
1) Implicit implementering af en abstrakt metode.
Lad os sige, at du har følgende kode:
class Cat
{
public String getName()
{
return "Oscar";
}
}
Og du besluttede at oprette en Tiger-klasse, der arver denne klasse, og tilføje en grænseflade til den nye klasse
class Cat
{
public String getName()
{
return "Oscar";
}
}
interface HasName
{
String getName();
int getWeight();
}
class Tiger extends Cat implements HasName
{
public int getWeight()
{
return 115;
}
}
Hvis du bare implementerer alle de manglende metoder, som IntelliJ IDEA fortæller dig at implementere, kan du senere ende med at bruge lang tid på at søge efter en fejl.
Det viser sig, at Tiger-klassen har en getName-metode, der er arvet fra Cat, som vil blive taget som implementering af getName-metoden til HasName-grænsefladen.
"Jeg kan ikke se noget forfærdeligt ved det."
"Det er ikke så slemt, det er et sandsynligt sted for fejl at snige sig ind."
Men det kan være endnu værre:
interface HasWeight
{
int getValue();
}
interface HasSize
{
int getValue();
}
class Tiger extends Cat implements HasWeight, HasSize
{
public int getValue()
{
return 115;
}
}
Det viser sig, at du ikke altid kan arve fra flere grænseflader. Mere præcist kan du arve dem, men du kan ikke implementere dem korrekt. Se på eksemplet. Begge grænseflader kræver, at du implementerer getValue()-metoden, men det er ikke klart, hvad det skal returnere: vægten eller størrelsen? Dette er ret ubehageligt at have med at gøre.
"Jeg er enig. Du vil implementere en metode, men du kan ikke. Du har allerede arvet en metode med samme navn fra basisklassen. Den er ødelagt."
"Men der er gode nyheder."
2) Udvidelse af synlighed. Når du arver en type, kan du udvide synligheden af en metode. Sådan ser det ud:
Java kode | Beskrivelse |
---|---|
|
|
|
Vi har udvidet metodens synlighed fra protected til public . |
Kode | Hvorfor dette er "lovligt" |
---|---|
|
Alt er fantastisk. Her ved vi ikke engang, at sigtbarheden er blevet udvidet i en efterkommerklasse. |
|
Her kalder vi metoden, hvis synlighed er blevet udvidet.
Hvis dette ikke var muligt, kunne vi altid erklære en metode i Tiger: Med andre ord, vi taler ikke om nogen sikkerhedsbrud. |
|
Hvis alle de nødvendige betingelser for at kalde en metode i en basisklasse ( Cat ) er opfyldt , så er de helt sikkert opfyldt for at kalde metoden på den descendente type ( Tiger ) . Fordi begrænsningerne på metodekaldet var svage, ikke stærke. |
"Jeg er ikke sikker på, at jeg helt har forstået det, men jeg vil huske, at det er muligt."
3) Indsnævring af returtypen.
I en tilsidesat metode kan vi ændre returtypen til en indsnævret referencetype.
Java kode | Beskrivelse |
---|---|
|
|
|
Vi tilsidesatte metoden getMyParent , og nu returnerer den et Tiger objekt. |
Kode | Hvorfor dette er "lovligt" |
---|---|
|
Alt er fantastisk. Her ved vi ikke engang, at getMyParent-metodens returtype er blevet udvidet i descendant-klassen.
Hvordan den «gamle kode» fungerede og virker. |
|
Her kalder vi metoden, hvis returtype er blevet indsnævret.
Hvis dette ikke var muligt, kunne vi altid erklære en metode i Tiger: Der er med andre ord ingen sikkerhedsbrud og/eller type casting brud. |
|
Og alt fungerer fint her, selvom vi udvidede variablenes type til basisklassen (Cat).
På grund af tilsidesættelse kaldes den korrekte setMyParent-metode. Og der er intet at bekymre sig om, når man kalder getMyParent-metoden , fordi returværdien, selvom Tiger-klassen er, stadig kan tildeles myParent-variablen i basisklassen (Cat) uden problemer. Tiger-objekter kan sikkert opbevares både i Tiger-variabler og Cat-variabler. |
"Jep. Okay. Når du tilsidesætter metoder, skal du være opmærksom på, hvordan alt dette fungerer, hvis vi sender vores objekter til kode, der kun kan håndtere basisklassen og ikke ved noget om vores klasse. "
"Nøjagtigt! Så er det store spørgsmål, hvorfor kan vi ikke indsnævre returværdiens type, når vi tilsidesætter en metode?"
"Det er indlysende, at i dette tilfælde ville koden i basisklassen holde op med at virke:"
Java kode | Forklaring af problemet |
---|---|
|
|
|
Vi overbelastede getMyParent-metoden og indsnævrede typen af dens returværdi.
Alt er fint her. |
|
Så holder denne kode op med at virke.
GetMyParent-metoden kan returnere enhver forekomst af et objekt, fordi den faktisk kaldes på et Tiger-objekt. Og vi har ikke et tjek før opgaven. Det er således fuldt ud muligt, at Cat-type myParent-variablen gemmer en String-reference. |
"Fantastisk eksempel, Amigo!"
I Java, før en metode kaldes, er der ingen kontrol af, om objektet har en sådan metode. Alle kontroller finder sted under kørsel. Og et [hypotetisk] kald til en manglende metode vil højst sandsynligt få programmet til at forsøge at udføre ikke-eksisterende bytekode. Dette ville i sidste ende føre til en fatal fejl, og operativsystemet ville tvangslukke programmet.
"Hvaa. Nu ved jeg det."
GO TO FULL VERSION