"Jeg skal fortelle deg om « adgangsmodifikatorer ». Jeg fortalte om dem en gang før, men repetisjon er en pilar for læring."

Du kan kontrollere tilgangen (synligheten) som andre klasser har til metodene og variablene til klassen din. En tilgangsmodifikator svarer på spørsmålet «Hvem kan få tilgang til denne metoden/variabelen?». Du kan spesifisere bare én modifikator for hver metode eller variabel.

1) « offentlig » modifikator.

En variabel, metode eller klasse merket med den offentlige modifikatoren kan nås fra hvor som helst i programmet. Dette er den høyeste graden av åpenhet: det er ingen begrensninger.

2) « privat » modifikator.

En variabel, metode eller klasse merket med den private modifikatoren kan bare nås i klassen der den er deklarert. Den merkede metoden eller variabelen er skjult fra alle andre klasser. Dette er den høyeste grad av personvern: kun tilgjengelig for klassen din. Slike metoder er ikke arvet og kan ikke overstyres. I tillegg kan de ikke nås i en etterkommerklasse.

3)  « Standard modifikator».

Hvis en variabel eller metode ikke er merket med noen modifikator, anses den for å være merket med "standard" modifikator. Variabler og metoder med denne modifikatoren er synlige for alle klasser i pakken der de er deklarert, og bare for disse klassene. Denne modifikatoren kalles også " pakke " eller " pakke privat " tilgang, og antyder at tilgang til variabler og metoder er åpen for hele pakken som inneholder klassen.

4) « beskyttet » modifikator.

Dette tilgangsnivået er litt bredere enn pakken . En variabel, metode eller klasse merket med den beskyttede modifikatoren kan nås fra pakken (som "pakke") og fra alle arvede klasser.

Denne tabellen forklarer det hele:

Type synlighet Nøkkelord Adgang
Din klasse Pakken din Descendent Alle klasser
Privat privat Ja Nei Nei Nei
Pakke (ingen modifikator) Ja Ja Nei Nei
Beskyttet beskyttet Ja Ja Ja Nei
Offentlig offentlig Ja Ja Ja Ja

Det er en måte å enkelt huske denne tabellen. Tenk deg at du skriver et testamente. Du deler alle tingene dine inn i fire kategorier. Hvem får bruke tingene dine?

Hvem har tilgang Modifikator Eksempel
Bare  meg privat Personlig dagbok
Familie (ingen modifikator) Familiebilder
Familie og arvinger beskyttet Familie eiendom
Alle offentlig Memoarer

"Det er mye som å forestille seg at klasser i samme pakke er en del av en familie."

"Jeg vil også fortelle deg noen interessante nyanser om overordnede metoder."

1) Implisitt implementering av en abstrakt metode.

La oss si at du har følgende kode:

Kode
class Cat
{
 public String getName()
 {
  return "Oscar";
 }
}

Og du bestemte deg for å lage en Tiger-klasse som arver denne klassen, og legge til et grensesnitt til den nye klassen

Kode
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 metodene som IntelliJ IDEA ber deg implementere, kan du senere ende opp med å bruke lang tid på å søke etter en feil.

Det viser seg at Tiger-klassen har en getName-metode arvet fra Cat, som vil bli tatt som implementering av getName-metoden for HasName-grensesnittet.

— Jeg ser ikke noe forferdelig ved det.

"Det er ikke så ille, det er et sannsynlig sted for feil å snike seg inn."

Men det kan bli enda verre:

Kode
interface HasWeight
{
 int getValue();
}
interface HasSize
{
 int getValue();
}
class Tiger extends Cat implements HasWeight, HasSize
{
 public int getValue()
 {
  return 115;
 }
}

Det viser seg at du ikke alltid kan arve fra flere grensesnitt. Mer presist kan du arve dem, men du kan ikke implementere dem riktig. Se på eksempelet. Begge grensesnittene krever at du implementerer getValue()-metoden, men det er ikke klart hva den skal returnere: vekten eller størrelsen? Dette er ganske ubehagelig å måtte forholde seg til.

"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 det er gode nyheter."

2) Utvide synlighet. Når du arver en type, kan du utvide synligheten til en metode. Slik ser det ut:

Java-kode Beskrivelse
class Cat
{
 protected String getName()
 {
  return "Oscar";
 }
}
class Tiger extends Cat
{
 public String getName()
 {
  return "Oscar Tiggerman";
 }
}
Vi har utvidet metodens synlighet fra protectedtil public.
Kode Hvorfor er dette «lovlig»
public static void main(String[] args)
{
 Cat cat = new Cat();
 cat.getName();
}
Alt er flott. Her vet vi ikke engang at sikten er utvidet i en etterkommerklasse.
public static void main(String[] args)
{
 Tiger tiger = new Tiger();
 tiger.getName();
}
Her kaller vi metoden hvis synlighet er utvidet.

Hvis dette ikke var mulig, kunne vi alltid erklære en metode i Tiger:
public String getPublicName()
{
super.getName(); //kall den beskyttede metoden
}

Med andre ord, vi snakker ikke om noen sikkerhetsbrudd.

public static void main(String[] args)
{
 Cat catTiger = new Tiger();
 catTiger.getName();
}
Hvis alle betingelsene som er nødvendige for å kalle en metode i en basisklasse ( Cat ) er oppfylt , er de absolutt tilfredsstilt for å kalle metoden på den etterkommere typen ( Tiger ) . Fordi restriksjonene på metodekallet var svake, ikke sterke.

— Jeg er ikke sikker på at jeg forsto det helt, men jeg skal huske at dette er mulig.

3) Innsnevring av returtypen.

I en overstyrt metode kan vi endre returtypen til en innsnevret referansetype.

Java-kode Beskrivelse
class Cat
{
 public Cat parent;
 public Cat getMyParent()
 {
  return this.parent;
 }
 public void setMyParent(Cat cat)
 {
  this.parent = cat;
 }
}
class Tiger extends Cat
{
 public Tiger getMyParent()
 {
  return (Tiger) this.parent;
 }
}
Vi overstyrte metoden getMyParent, og nå returnerer den et Tigerobjekt.
Kode Hvorfor er dette «lovlig»
public static void main(String[] args)
{
 Cat parent = new Cat();

 Cat me = new Cat();
 me.setMyParent(parent);
 Cat myParent = me.getMyParent();
}
Alt er flott. Her vet vi ikke engang at getMyParent-metodens returtype har blitt utvidet i etterkommerklassen.

Hvordan den «gamle koden» fungerte og fungerer.

public static void main(String[] args)
{
 Tiger parent = new Tiger();

 Tiger me = new Tiger();
 me.setMyParent(parent);
 Tiger myParent = me.getMyParent();
}
Her kaller vi metoden hvis returtype er blitt innsnevret.

Hvis dette ikke var mulig, kunne vi alltid erklære en metode i Tiger:
public Tiger getMyTigerParent()
{
return (Tiger) this.parent;
}

Det er med andre ord ingen sikkerhetsbrudd og/eller type casting brudd.

public static void main(String[] args)
{
 Tiger parent = new Tiger();

 Cat me = new Tiger();
 me.setMyParent(parent);
 Cat myParent = me.getMyParent();
}
Og alt fungerer bra her, selv om vi utvidet variablenes type til basisklassen (Cat).

På grunn av overstyring kalles den riktige setMyParent-metoden.

Og det er ingenting å bekymre seg for når du kaller getMyParent-metoden , fordi returverdien, selv om Tiger-klassen, fortsatt kan tildeles til myParent-variabelen til basisklassen (Cat) uten problemer.

Tiger-objekter kan trygt lagres både i Tiger-variabler og Cat-variabler.

"Jepp. Skjønner det. Når du overstyrer metoder, må du være klar over hvordan alt dette fungerer hvis vi sender objektene våre til kode som bare kan håndtere basisklassen og ikke vet noe om klassen vår. "

"Akkurat! Da er det store spørsmålet hvorfor vi ikke kan begrense returverdiens type når vi overstyrer en metode?"

"Det er åpenbart at i dette tilfellet vil koden i basisklassen slutte å virke:"

Java-kode Forklaring av problemet
class Cat
{
 public Cat parent;
 public Cat getMyParent()
 {
  return this.parent;
 }
 public void setMyParent(Cat cat)
 {
  this.parent = cat;
 }
}
class Tiger extends Cat
{
 public Object getMyParent()
 {
  if (this.parent != null)
   return this.parent;
  else
   return "I'm an orphan";
 }
}
Vi overbelastet getMyParent-metoden og begrenset typen returverdi.

Alt er bra her.

public static void main(String[] args)
{
 Tiger parent = new Tiger();

 Cat me = new Tiger();
 Cat myParent = me.getMyParent();
}
Da slutter denne koden å fungere.

GetMyParent-metoden kan returnere enhver forekomst av et objekt, fordi det faktisk kalles på et Tiger-objekt.

Og vi har ikke sjekk før oppdraget. Dermed er det fullt mulig at Cat-type myParent-variabelen vil lagre en strengreferanse.

"Fantastisk eksempel, Amigo!"

I Java, før en metode kalles, er det ingen sjekk om objektet har en slik metode. Alle kontroller skjer ved kjøretid. Og et [hypotetisk] kall til en manglende metode vil mest sannsynlig føre til at programmet forsøker å kjøre en ikke-eksisterende bytekode. Dette ville til slutt føre til en fatal feil, og operativsystemet ville tvangslukke programmet.

"Wow. Nå vet jeg det."