CodeGym/Blog Java/Aleatoriu/Clase interioare imbricate
John Squirrels
Nivel
San Francisco

Clase interioare imbricate

Publicat în grup
Bună! Astăzi vom aborda un subiect important - cum funcționează clasele imbricate în Java. Java vă permite să creați clase în interiorul unei alte clase:
class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
Aceste clase interne se numesc imbricate. Ele sunt împărțite în 2 tipuri:
  1. Clase imbricate non-statice. Acestea sunt numite și clase interioare.
  2. Clase imbricate statice.
La rândul lor, clasele interioare au două subcategorii distincte. Pe lângă faptul că o clasă interioară este pur și simplu o clasă interioară, poate fi și:
  • o clasă locală
  • o clasă anonimă
Confuz? :) Este în regulă. Iată o diagramă pentru claritate. Reveniți la ea în timpul lecției dacă vă vedeți deodată confuz! Clase interioare imbricate - 2În lecția de astăzi, vom discuta despre clasele interioare (cunoscute și ca clase imbricate non-statice). Sunt evidențiate în mod special în diagrama de ansamblu ca să nu te pierzi :) Să începem cu întrebarea evidentă: de ce se numesc clase „interioare”? Răspunsul este destul de simplu: pentru că sunt create în cadrul altor clase. Iată un exemplu:
public class Bicycle {

   private String model;
   private int weight;

   public Bicycle(String model, int weight) {
       this.model = model;
       this.weight = weight;
   }

   public void start() {
       System.out.println("Let's go!");
   }

   public class Handlebar {

       public void right() {
           System.out.println("Steer right!");
       }

       public void left() {

           System.out.println("Steer left!");
       }
   }

   public class Seat {

       public void up() {

           System.out.println("Seat up!");
       }

       public void down() {

           System.out.println("Seat down!");
       }
   }
}
Aici avem Bicycleclasa. Are 2 câmpuri și 1 metodă: start(). Clase interioare imbricate - 3Se deosebește de o clasă obișnuită prin faptul că conține două clase: Handlebarși Seat. Codul lor este scris în Bicycleclasă. Acestea sunt clase cu drepturi depline: după cum puteți vedea, fiecare dintre ele are propriile sale metode. În acest moment, ați putea avea o întrebare: de ce naiba am pune o clasă în alta? De ce să le faci clase interioare? Ei bine, să presupunem că avem nevoie de clase separate pentru conceptele de ghidon și scaun din programul nostru. Desigur, nu este necesar ca noi să le facem cuibărate! Putem face clase obișnuite. De exemplu, așa:
public class Handlebar {
   public void right() {
       System.out.println("Steer right!");
   }

   public void left() {

       System.out.println("Steer left");
   }
}

public class Seat {

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
Foarte buna intrebarea! Desigur, nu suntem limitați de tehnologie. A face asta este cu siguranță o opțiune. Aici, cel mai important lucru este mai mult proiectarea corectă a orelor din perspectiva unui anumit program și a scopului acestuia. Clasele interioare sunt pentru a separa o entitate care este inextricabil conectată la o altă entitate. Ghidonul, scaunele și pedalele sunt componente ale unei biciclete. Despărțiți de bicicletă, nu prea au sens. Dacă am făcut toate aceste concepte să fie separate clase publice, am fi avut codul ca acesta în programul nostru:
public class Main {

   public static void main(String[] args) {
       Handlebar handlebar = new Handlebar();
       handlebar.right();
   }
}
Hmm... Sensul acestui cod este chiar greu de explicat. Avem un ghidon vag (De ce este necesar? Nici idee, să fiu sincer). Și acest mâner se întoarce la dreapta... de la sine, fără bicicletă... dintr-un motiv oarecare. Separând conceptul de ghidon de conceptul de bicicletă, am pierdut ceva logic în programul nostru. Folosind o clasă interioară, codul arată foarte diferit:
public class Main {

   public static void main(String[] args) {

       Bicycle peugeot = new Bicycle("Peugeot", 120);
       Bicycle.Handlebar handlebar = peugeot.new Handlebar();
       Bicycle.Seat seat = peugeot.new Seat();

       seat.up();
       peugeot.start();
       handlebar.left();
       handlebar.right();
   }
}
Ieșire din consolă:
Seat up!
Let's go!
Steer left!
Steer right!
Acum ceea ce vedem deodată are sens! :) Am creat un obiect bicicleta. Am creat două „subobiecte” pentru biciclete — un ghidon și un scaun. Am ridicat scaunul pentru confort și am pornit: pedalând și volând la nevoie! :) Metodele de care avem nevoie sunt chemate pe obiectele adecvate. Totul este simplu și convenabil. În acest exemplu, separarea ghidonului și a scaunului îmbunătățește încapsularea (ascundem datele despre piesele bicicletei în cadrul clasei relevante) și ne permite să creăm o abstractizare mai detaliată. Acum să ne uităm la o situație diferită. Să presupunem că vrem să creăm un program care simulează un magazin de biciclete și piese de schimb pentru biciclete. Clase interioare imbricate - 4În această situație, soluția noastră anterioară nu va funcționa. La un magazin de biciclete, fiecare piesă individuală de bicicletă are sens chiar și atunci când este separată de o bicicletă. De exemplu, vom avea nevoie de metode precum „vindem pedale unui client”, „cumpărați un scaun nou”, etc. Ar fi o greșeală să folosim clase interioare aici - fiecare piesă individuală de bicicletă din noul nostru program are un sens care rămâne pe propriu: poate fi separat de conceptul de bicicletă. Acesta este exact ceea ce trebuie să acordați atenție dacă vă întrebați dacă ar trebui să folosiți clase interioare sau să organizați toate entitățile ca clase separate. Programarea orientată pe obiecte este bună prin faptul că ușurează modelarea entităților din lumea reală. Acesta poate fi principiul tău călăuzitor atunci când te decizi dacă să folosești clasele interioare. Într-un magazin adevărat, piesele de schimb sunt separate de biciclete - este în regulă. Aceasta înseamnă că este în regulă și atunci când proiectați un program. Bine, ne-am dat seama de „filozofia” :) Acum să ne familiarizăm cu caracteristicile „tehnice” importante ale claselor interioare. Iată ce trebuie neapărat să vă amintiți și să înțelegeți:
  1. Un obiect al unei clase interioare nu poate exista fără un obiect al unei clase exterioare.

    Acest lucru are sens: acesta este motivul pentru care am creat clasele Seatinterioare Handlebarîn programul nostru, astfel încât să nu ajungem cu ghidon și scaune orfane.

    Acest cod nu compilează:

    public static void main(String[] args) {
    
       Handlebar handlebar = new Handlebar();
    }

    Din aceasta rezultă o altă caracteristică importantă:

  2. Un obiect al unei clase interioare are acces la variabilele clasei exterioare.

    De exemplu, să adăugăm o int seatPostDiametervariabilă (reprezentând diametrul tijei de șa) la Bicycleclasa noastră.

    Apoi, în Seatclasa interioară, putem crea o displaySeatProperties()metodă care afișează proprietățile scaunului:

    public class Bicycle {
    
       private String model;
       private int weight;
    
       private int seatPostDiameter;
    
       public Bicycle(String model, int weight, int seatPostDiameter) {
           this.model = model;
           this.weight = weight;
           this.seatPostDiameter = seatPostDiameter;
    
       }
    
       public void start() {
           System.out.println("Let's go!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println("Seat up!");
           }
    
           public void down() {
    
               System.out.println("Seat down!");
           }
    
           public void displaySeatProperties() {
    
               System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }

    Și acum putem afișa aceste informații în programul nostru:

    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
           Bicycle.Seat seat = bicycle.new Seat();
    
           seat.displaySeatProperties();
       }
    }

    Ieșire din consolă:

    Seat properties: seatpost diameter = 40

    Notă:noua variabilă este declarată cu cel mai strict modificator de acces ( private). Și totuși clasa interioară are acces!

  3. Un obiect al unei clase interioare nu poate fi creat într-o metodă statică a unei clase exterioare.

    Acest lucru se explică prin caracteristicile specifice ale modului în care sunt organizate clasele interioare. O clasă interioară poate avea constructori cu parametri sau doar constructorul implicit. Dar indiferent, atunci când creăm un obiect al unei clase interioare, o referință la obiectul clasei exterioare este transmisă în mod invizibil obiectului creat al clasei interioare. La urma urmei, prezența unei astfel de referințe la obiect este o cerință absolută. În caz contrar, nu vom putea crea obiecte din clasa interioară.

    Dar dacă o metodă din clasa exterioară este statică, atunci s-ar putea să nu avem un obiect din clasa exterioară! Și aceasta ar fi o încălcare a logicii modului în care funcționează o clasă interioară. În această situație, compilatorul va genera o eroare:

    public static Seat createSeat() {
    
       // Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
  4. O clasă interioară nu poate conține variabile și metode statice.

    Logica este aceeași: metodele și variabilele statice pot exista și pot fi numite sau referite chiar și în absența unui obiect.

    Dar fără un obiect al clasei exterioare, nu vom avea acces la clasa interioară.

    O contradicție clară! Acesta este motivul pentru care variabilele și metodele statice nu sunt permise în clasele interne.

    Compilatorul va genera o eroare dacă încercați să le creați:

    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
    
           // An inner class cannot have static declarations
           public static void displaySeatProperties() {
    
               System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
  5. Când creați un obiect dintr-o clasă interioară, modificatorul de acces al acestuia este important.

    O clasă interioară poate fi marcată cu modificatorii de acces standard: public, private, protected, și package private.

    De ce contează asta?

    Acest lucru afectează locul în care putem crea instanțe ale clasei interioare în programul nostru.

    Dacă Seatclasa noastră este declarată ca public, putem crea Seatobiecte în orice altă clasă. Singura cerință este că trebuie să existe și un obiect din clasa exterioară.

    Apropo, am făcut deja asta aici:

    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle peugeot = new Bicycle("Peugeot", 120);
           Bicycle.Handlebar handlebar = peugeot.new Handlebar();
           Bicycle.Seat seat = peugeot.new Seat();
    
           seat.up();
           peugeot.start();
           handlebar.left();
           handlebar.right();
       }
    }

    Am obținut ușor acces la Handlebarclasa interioară din Mainclasă.

    Dacă declarăm clasa interioară ca private, vom putea crea obiecte numai în interiorul clasei exterioare.

    Nu mai putem crea un Seatobiect „în exterior”:

    private class Seat {
    
       // Methods
    }
    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
    
           // Bicycle.Seat has private access in Bicycle
           Bicycle.Seat seat = bicycle.new Seat();
       }
    }

    Probabil ai inteles deja logica :)

  6. Modificatorii de acces pentru clasele interne funcționează la fel ca pentru variabilele obișnuite.

    Modificatorul protectedoferă acces la o variabilă de instanță în subclase și clase care sunt în același pachet.

    protectedfuncționează și pentru clasele interioare. Putem crea protectedobiecte din clasa interioara:

    • în clasa exterioară;
    • în subclasele sale;
    • în clasele care sunt în același pachet.

    Dacă clasa interioară nu are un modificator de acces ( package private), pot fi create obiecte din clasa interioară:

    • în clasa exterioară;
    • în clasele care sunt în același pachet.

    Sunteți familiarizat cu modificatorii de mult timp, așa că nu există probleme aici.

Asta e tot deocamdată :) Dar nu te slăbi! Orele interioare sunt un subiect destul de extins pe care îl vom explora în continuare în lecția următoare. Acum vă puteți reîmprospăta memoria despre lecția cursului nostru despre clasele interioare . Și data viitoare, să vorbim despre clase imbricate statice.
Comentarii
  • Popular
  • Nou
  • Vechi
Trebuie să fii conectat pentru a lăsa un comentariu
Această pagină nu are încă niciun comentariu