JavaRush /Java Blog /Random-TL /Mga klase, mga uri ng mga nested na klase na may mga hali...
Ярослав
Antas
Днепр

Mga klase, mga uri ng mga nested na klase na may mga halimbawa

Nai-publish sa grupo
Kamusta kayong lahat. Sa paksang ito, gusto kong pag-usapan nang detalyado ang tungkol sa mga klase ng Java at ang kanilang mga uri upang matulungan ang mga nagsisimula na maunawaan ang paksang ito, at marahil ang mga hindi baguhan ay matuto ng bago. Kung posible, ang lahat ay ipapakita gamit ang mga totoong buhay na halimbawa na may kasamang mga halimbawa ng code. Magsimula na tayo. Mga klase, mga uri ng mga nested na klase na may mga halimbawa - 1At nais kong tandaan na ang pangunahing bagay ay upang maunawaan ang unang dalawang uri ng mga klase, at ang lokal at hindi kilalang mga subtype lamang ng panloob na klase.

Ano ang isang klase?

Ang isang klase ay isang lohikal na paglalarawan ng isang bagay, isang template kung saan maaari kang lumikha ng mga tunay na pagkakataon ng mismong bagay na iyon. Sa madaling salita, isa lamang itong paglalarawan kung ano dapat ang mga nilikhang entity: kung anong mga katangian at pamamaraan ang dapat mayroon sila. Ang mga katangian ay mga katangian ng isang entity, ang mga pamamaraan ay mga aksyon na magagawa nito. Ang isang magandang halimbawa ng isang klase mula sa totoong buhay, na nagbibigay ng pag-unawa sa kung ano ang isang klase, ay maaaring ituring na mga guhit: ang mga guhit ay ginagamit upang ilarawan ang mga istruktura (tirador, distornilyador), ngunit ang pagguhit ay hindi isang disenyo. Tulad ng mga inhinyero na gumagamit ng mga blueprint upang lumikha ng mga disenyo, ang programming ay gumagamit ng mga klase upang lumikha ng mga bagay na naglalarawan ng mga katangian at pamamaraan.
public class Student {
    private String name, group, specialty;

    public Student(String name, String group, String specialty) {
       this.name = name;
       this.group = group;
       this.specialty = specialty;
   }

   // getters/setters
}
Sa halimbawang ito, gumawa kami ng Java class na naglalarawan sa entity na "mag-aaral": bawat mag-aaral ay may pangalan, grupo at espesyalidad. Ngayon, sa ibang mga lugar sa programa, maaari tayong lumikha ng mga tunay na halimbawa ng klase na ito. Sa madaling salita: kung ang klase Studentay isang larawan ng kung ano ang dapat na maging isang mag-aaral, kung gayon ang nilikha na halimbawa ay ang aktwal na mag-aaral mismo. Isang halimbawa ng paglikha ng bagong mag-aaral: Hinahanap new Student("Ivan", "KI-17-2", "Computer Engineering");ng operator newang klase Studentat pagkatapos ay tumawag ng isang espesyal na pamamaraan (tagabuo) ng klase na ito. Ang constructor ay nagbabalik ng isang handa na bagay sa klase Student- ang aming mahal, gutom na mag-aaral na walang scholarship :))

Mga uri ng klase sa Java

Sa Java mayroong 4 na uri ng mga klase sa loob ng isa pang klase:
  1. Ang mga nested inner class ay mga non-static na klase sa loob ng isang panlabas na klase.

  2. Ang mga nested static na klase ay mga static na klase sa loob ng isang panlabas na klase.

  3. Ang mga lokal na klase ng Java ay mga klase sa loob ng mga pamamaraan.

  4. Ang mga anonymous na klase sa Java ay mga klase na mabilis na ginawa.

Pag-uusapan natin ang bawat isa sa kanila nang hiwalay.

Non-static na mga klase sa loob ng isang panlabas na klase

Una, gusto kong maunawaan mo kung ano ito sa isang tunay na halimbawa, dahil ginagawa nitong mas madaling maunawaan. Kaya ngayon, sisirain natin ang isang tunay na malaking bagay sa mas maliliit na bahagi, at i-disassemble natin ang isang eroplano! Gayunpaman, para sa kapakanan ng halimbawa ito ay sapat na upang ipakita ang kaunti; hindi namin ito ganap na masira. Upang mailarawan ang prosesong ito, gagamit kami ng diagram ng eroplano. Mga klase, mga uri ng mga nested na klase na may mga halimbawa - 2 Una, kailangan nating lumikha ng isang klase Airplanekung saan maaari tayong magdagdag ng kaunting paglalarawan: pangalan ng sasakyang panghimpapawid, code ng pagkakakilanlan, paglipad.
public class Airplane {
    private String name, id, flight;

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    // getters/setters
}
Ngayon gusto naming magdagdag ng mga pakpak. Gumawa ng hiwalay na klase? Marahil ito ang lohika kung mayroon tayong isang kumplikadong programa para sa pagdidisenyo ng mga eroplano, at kung saan kailangan nating lumikha ng isang malaking bilang ng mga nagmula na mga klase (mga klase na may parehong lohika sa parent class, iyon ay, ang klase kung saan sila nagmamana, ngunit kaya pinahaba nila ang klase ng magulang sa pamamagitan ng pagdaragdag ng lohika o mas detalyadong mga katangian), ngunit paano kung mayroon lamang tayong laro kung saan mayroon tayong isang eroplano? Pagkatapos ay magiging mas makatwiran para sa amin na kumpletuhin ang buong istraktura sa isang lugar (sa isang klase). Dito pumapasok ang mga non-static na nested na klase. Sa pangkalahatan, ito ay isang mas detalyadong paglalarawan ng ilang mga detalye ng aming panlabas na klase. Sa halimbawang ito, kailangan nating lumikha ng mga pakpak para sa isang eroplano - kaliwa at kanan. Lumikha tayo!
public class Airplane {
    private String name, id, flight;
    private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    private class Wing {
        private String color, model;

        private Wing(String color, String model) {
            this.color = color;
            this.model = model;
        }

        // getters/setters
    }

    // getters/setters
}
Kaya gumawa kami ng non-static na nested class Wing(pakpak) sa loob ng isang klase Airplane(eroplano), at nagdagdag ng dalawang variable - kaliwang pakpak at kanang pakpak. At ang bawat pakpak ay may sariling katangian (kulay, modelo) na maaari nating baguhin. Sa ganitong paraan maaari mong i-staff ang mga istruktura hangga't kailangan mo. At tandaan: mas maaga sa diagram ay medyo maraming bahagi para sa sasakyang panghimpapawid, at, sa katunayan, maaari nating hatiin ang lahat ng mga bahagi sa mga panloob na klase, ngunit ang ganitong proseso ay hindi palaging maipapayo. Ang ganitong mga sandali ay kailangang masubaybayan depende sa gawain. Maaaring hindi mo kailangan ng mga pakpak upang malutas ang problema. Pagkatapos ay hindi na kailangang gawin ang mga ito. Ito ay tulad ng pagputol ng isang tao sa mga binti, braso, katawan at ulo - posible, ngunit bakit kung ang klase na ito ay ginagamit lamang upang mag-imbak ng data tungkol sa mga tao? Mga tampok ng hindi static na nested na mga klase ng Java:
  1. Umiiral lamang ang mga ito sa mga bagay, kaya upang malikha ang mga ito kailangan mo ng isang bagay. Sa madaling salita: idinisenyo namin ang aming pakpak upang maging bahagi ng isang eroplano, kaya upang lumikha ng isang pakpak kailangan namin ng isang eroplano, kung hindi, hindi namin ito kailangan.
  2. Hindi maaaring magkaroon ng mga static na variable sa loob ng isang klase ng Java. Kung kailangan mo ng ilang mga constant o anumang bagay na static, kailangan mong ilipat ang mga ito sa isang panlabas na klase. Ito ay dahil sa malapit na pagkakabit ng non-static na nested na klase sa panlabas na klase.
  3. Ang klase ay may ganap na access sa lahat ng pribadong larangan ng panlabas na klase. Gumagana ang feature na ito sa dalawang paraan.
  4. Maaari kang makakuha ng reference sa isang instance ng isang panlabas na klase. Halimbawa: Eroplano.ito ay isang link sa isang eroplano, ito ay isang link sa isang pakpak.

Mga static na klase sa loob ng isang panlabas na klase

Ang ganitong uri ng klase ay hindi naiiba sa isang regular na panlabas na klase, maliban sa isang bagay: upang lumikha ng isang halimbawa ng naturang klase, kailangan mong ilista ang buong landas mula sa panlabas na klase hanggang sa nais, na pinaghihiwalay ng isang tuldok. Halimbawa: Building.Plaftorm platform = new Building.Platform(); Ang mga static na klase ay ginagamit upang ilagay ang magkakaugnay na mga klase nang magkatabi upang ang lohikal na istraktura ay mas madaling gamitin. Halimbawa: maaari tayong lumikha ng panlabas na klase Building, kung saan magkakaroon ng partikular na listahan ng mga klase na kakatawan sa isang partikular na gusali.
public abstract class Building {
    private String name, address, type;

    Building(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public static class Platform extends Building {
        public Platform(String name, String address) {
            super(name, address);
            setType("Platform");
        }

        // some additional logic
    }

    public static class House extends Building {
        public House(String name, String address) {
            super(name, address);
            setType("House");
        }

        // some additional logic
    }

    public static class Shop extends Building {
        public Shop(String name, String address) {
            super(name, address);
            setType("Shop");
        }

        // some additional logic
    }

    // getters/setters
}
Ang halimbawang ito ay nagpapakita kung paano pinapayagan ka ng mga static na klase na mag-package ng isang lohikal na istraktura sa isang mas maginhawang anyo. Kung wala ang mga ito, kakailanganin nating lumikha ng 4 na ganap na magkakaibang klase. Ang mga bentahe ng diskarteng ito:
  1. Bumaba ang bilang ng mga klase.
  2. Lahat ng klase ay nasa loob ng kanilang parent class. Nasusubaybayan namin ang buong hierarchy nang hindi binubuksan nang hiwalay ang bawat klase.
  3. Maaari tayong sumangguni sa klase ng Building, at ipo-prompt na ng IDE ang buong listahan ng lahat ng mga subclass ng klase na ito. Gagawin nitong mas madaling mahanap ang mga klase na kailangan mo at ipakita ang buong larawan nang mas holistically.
Isang halimbawa ng paglikha ng isang instance ng isang nested static na klase:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); Gusto ko ring tandaan na ang diskarteng ito ay ginagamit sa AWT 2D na mga klase upang ilarawan ang mga hugis, tulad ng Line2D, Arc2D, Ellipse2D at iba pa.

Mga lokal na klase

Ang mga klase na ito ay ipinahayag sa loob ng ibang mga pamamaraan. Sa katunayan, mayroon silang lahat ng mga katangian ng isang non-static na nested na klase, tanging ang kanilang mga pagkakataon ay magagawa lamang sa isang pamamaraan, at ang pamamaraan ay hindi maaaring maging static (upang lumikha ng mga ito kailangan mo ng isang halimbawa ng isang panlabas na klase, isang sanggunian sa isang instance ng calling object ay tahasang ipinapasa sa mga non-static na pamamaraan, at sa isang static na pamamaraan ay walang paraan para sa link na ito). Ngunit mayroon silang sariling mga katangian:
  1. Ang mga lokal na klase ay maaari lamang gumana sa mga variable na panghuling pamamaraan. Ang bagay ay ang mga pagkakataon ng mga lokal na klase ay maaaring maimbak sa heap pagkatapos makumpleto ang pamamaraan, at ang variable ay maaaring mabura. Kung ang variable ay idineklara na pangwakas, ang compiler ay maaaring mag-save ng isang kopya ng variable para magamit sa ibang pagkakataon ng object. At isa pang bagay: dahil 8+ na bersyon ng Java, maaari kang gumamit ng mga hindi panghuling variable sa mga lokal na klase, ngunit sa kondisyon lamang na hindi sila magbabago.
  2. Ang mga lokal na klase ay hindi maaaring ideklara na may mga access modifier.
  3. Ang mga lokal na klase ay may access sa mga variable ng pamamaraan.
Ang mga lokal na klase ay maaaring matagpuan nang napakabihirang, dahil ginagawa nilang mahirap basahin ang code at walang anumang mga pakinabang, maliban sa isa - pag-access sa mga variable ng pamamaraan. Hindi ko alam kung anong halimbawa ng isang lokal na klase ang maaaring kunin na magpapakita ng kanilang epektibong paggamit, kaya ipapakita ko na lang ang aking halimbawa. Sabihin na nating may klase tayo Person(ipapalagay na tao ito) na may mga ari-arian street(kalye), house(bahay). Nais naming ibalik ang ilang bagay upang ma-access lamang ang lokasyon ng tao. Upang gawin ito, ginawa namin ang interface ng AddressContainer, na nagpapahiwatig ng pag-iimbak ng data tungkol sa lokasyon ng isang tao.
public class Person {
    private String name, street, house;

    public Person(String name, String street, String house) {
        this.name = name;
        this.street = street;
        this.house = house;
    }

    private interface AddressContainer {
        String getStreet();
        String getHouse();
    }

    public AddressContainer getAddressContainer() {
        class PersonAddressContainer implements AddressContainer {
            final String street = Person.this.street, house = Person.this.house;

            @Override
            public String getStreet() {
                return this.street;
            }

            @Override
            public String getHouse() {
                return this.house;
            }
        }

        return new PersonAddressContainer();
    }

    public static void main(String[] args) {
        Person person = new Person("Nikita", "Sholohova", "17");

        AddressContainer address = person.getAddressContainer();

        System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
    }

    // getters/setters
}
Tulad ng nakikita mo, sa loob ng pamamaraan ay lumikha kami ng isang klase na nagpapatupad ng pag-iimbak ng lokasyon ng isang tao, lumikha ng mga pare-parehong variable doon (upang matapos na lumabas sa pamamaraan, ang mga variable ay naka-imbak sa isang bagay) at nagpatupad ng isang paraan para sa pagkuha ng address at bahay. Ngayon ay magagamit na natin ang bagay na ito sa ibang mga lugar sa programa para makuha ang lokasyon ng isang tao. Nauunawaan ko na ang halimbawang ito ay hindi perpekto at mas tamang gawin ito sa pamamagitan lamang ng pag-iwan ng mga getter sa klase Person, gayunpaman, ang paglikha ng klase na ito at ang posibleng paggamit nito ay ipinakita, at pagkatapos ay nasa iyo na.

Anonymous na klase

Sa ilalim ng hood, ang mga anonymous na klase ay mga regular na non-static na nested na klase lamang. Ang kanilang kakaiba ay ang kanilang kadalian ng paggamit. Maaari mong direktang isulat ang iyong klase kapag gumagawa ng isang instance ng isa pang klase.
public class Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public static void main(String[] args) {
        Animal anonTiger = new Animal() {
            @Override
            public void meow() {
                System.out.println("Raaar!");
            }
        };

        Animal notAnonTiger = new Animal().new Tiger();

        anonTiger.meow(); // будет выведено Raaar!
        notAnonTiger.meow(); // будет выведено Raaar!
    }

    private class Tiger extends Animal {
        @Override
        public void meow() {
            System.out.println("Raaar!");
        }
    }
}
Sa esensya, pinagsasama-sama lang namin ang dalawang bagay sa isang lugar: paggawa ng instance ng isang klase ( Animal) at paggawa ng instance ng inheritor nitong inner class ( Tiger). Kung hindi, kailangan nating lumikha ng klase nang hiwalay at gumamit ng mas mahabang mga konstruksyon upang makamit ang parehong resulta. Ang paggamit ng mga hindi kilalang klase ay makatwiran sa maraming mga kaso, lalo na kapag:
  • ang katawan ng klase ay napakaikli;
  • isang pagkakataon lamang ng klase ang kailangan;
  • ang klase ay ginagamit sa lugar kung saan ito nilikha o kaagad pagkatapos nito;
  • Ang pangalan ng klase ay hindi mahalaga at hindi ginagawang mas madaling maunawaan ang code.
Ang mga anonymous na klase ay kadalasang ginagamit sa mga GUI upang lumikha ng mga tagapangasiwa ng kaganapan. Halimbawa, para gumawa ng button at tumugon sa pag-click nito:
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
Gayunpaman, pagkatapos ng Java 8 nagsimula silang gumamit ng mga expression ng lambda, ngunit marami pa ring code ang naisulat bago ang bersyon 8 at maaari kang makatagpo (at makatagpo sa panahon ng iyong pagsasanay sa JavaRush) ng mga naturang inskripsiyon.\ Analogue with lambdas:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
Katapusan ng artikulo Salamat sa lahat ng iyong atensyon at sana ay may natutunan kang bago o naunawaan ang isang bagay na hindi mo naiintindihan noon. Gusto ko ring linawin na ang artikulong ito ay kabilang sa kategoryang "pansin sa detalye . " Ito ang aking unang gawa, kaya umaasa ako na ito ay kapaki-pakinabang sa isang tao. In the near future, kapag may mga bagong ideya na dumating, susubukan kong magsulat ng iba, isa lang ang ideya ko... Good luck sa lahat at tagumpay sa programming :)
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION