Java vidinė klasė ir statinė įdėtinė klasė

Koks yra pagrindinis skirtumas tarp vidinės klasės ir statinės įdėtos klasės Java? Ar dizainas / įgyvendinimas gali atlikti svarbų vaidmenį pasirenkant vieną iš jų?

1541
16 сент. nustatė „ Omnipotent“ rugsėjo 16 d 2008-09-16 11:22 '08 at 11:22 2008-09-16 11:22
@ 27 atsakymai

Iš „ Java“ vadovo :

Įdėtos klasės skirstomos į dvi kategorijas: statinis ir nestandartinis. Įdėtos klasės, paskelbtos statinėmis, tiesiog vadinamos statinėmis įdėtomis klasėmis. Ne statinės įdėtos klasės vadinamos vidinėmis klasėmis.

Statinės įdėtos klasės pasiekiamos naudojant klasės pavadinimą:

 OuterClass.StaticNestedClass 

Pvz., Norėdami sukurti statinio įdėtos klasės objektą, naudokite šią sintaksę:

 OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass(); 

Išorinės klasės egzemplioriuje yra objektų, kurie yra vidinės klasės atvejai. Apsvarstykite šias klases:

 class OuterClass { ... class InnerClass { ... } } 

„InnerClass“ egzempliorius gali egzistuoti tik „OuterClass“ atveju ir turi tiesioginę prieigą prie jos pridedamo pavyzdžio metodų ir laukų.

Norėdami sukurti vidinės klasės egzempliorių, pirmiausia turite sukurti išorinės klasės egzempliorių. Tada sukurkite vidinį objektą išoriniame objekte, naudodami šią sintaksę:

 OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 

žiūrėkite: Java Tutorial - Nested Classes

Norint išsiaiškinti, atkreipkite dėmesį į tai, kad taip pat yra ir vidinė klasė , kurioje nėra uždarymo pavyzdžio :

 class A { int t() { return 1; } static A a = new A() { int t() { return 2; } }; } 

Čia new A() { ... } yra vidinė klasė, kuri yra apibrėžta statiniame kontekste ir neturi apimties pavyzdžio.

1534
16 сент. Atsakymą pateikė Martin 16 Sep 2008-09-16 11:28 '08 at 11:28 2008-09-16 11:28

„Java“ vadovėlyje sakoma :

Terminologija: įdėtos klasės skirstomos į dvi kategorijas: statinis ir nestandartinis. Įdėtos klasės, kurios yra paskelbtos statinėmis, tiesiog vadinamos statinėmis įdėtomis klasėmis. Ne statinės įdėtos klasės vadinamos vidinėmis klasėmis.

Bendrąja kalba daugelis programuotojų vartoja terminus „įdėtos“ ir „vidinės“, tačiau aš naudosiu teisingą terminą „įdėtos klasės“, kuri apima ir vidinį, ir statinį.

Pavyzdžiui, klasės gali būti įdėtos be galo. A klasėje gali būti B klasės, kurioje yra C klasės, kurioje yra D klasės ir tt Tačiau daugiau nei vienas klasės lizdas yra retas, nes tai paprastai yra prastas dizainas.

Yra trys priežastys, kodėl galite sukurti įdėtą klasę:

  • : kartais atrodo tikslinga rūšiuoti klasę kitos klasės vardų erdvėje, ypač kai ji nebus naudojama kitame kontekste.
  • prieiga: įdėtos klasės turi ypatingą prieigą prie klasių, kuriose jie yra, kintamieji / laukai (tiksliai, kurie kintamieji / laukai priklauso nuo įdėtos klasės, ar vidaus, ar statinio) tipo.
  • patogumas: naujo failo sukūrimas kiekvienam naujam tipui dar kartą erzina, ypač jei tipas bus naudojamas tik viename kontekste.

Java yra keturių tipų įdėtos klasės. Trumpai tariant, tai yra:

  • statinė klasė : deklaruojama kaip kitos klasės statinis narys
  • vidinė klasė : deklaruojama kaip kitos klasės egzemplioriaus narys
  • vietinė vidinė klasė : deklaruojama kitoje klasėje
  • anoniminė vidinė klasė : kaip vietinė vidinė klasė, bet parašyta kaip išraiška, kuri grąžina vienkartinį objektą

Leiskite išsiaiškinti tai.


Statinės klasės

Statinės klasės yra paprasčiausia forma, nes jos neturi nieko bendro su turinčios klasės egzemplioriais.

Statinė klasė yra klasė, deklaruota kaip kitos klasės statinis narys. Kaip ir kiti statiški nariai, tokia klasė iš tikrųjų yra tik pakabukas, kuris, pavyzdžiui, naudoja vardinę erdvę turinčią klasę. Ožkų klasė, paskelbta statiniu Rhino klasės nariu partijos picoje, yra žinoma kaip pizza.Rhino.Goat.

 package pizza; public class Rhino { ... public static class Goat { ... } } 

Tiesą sakant, statinės klasės yra gana nenaudinga funkcija, nes klasės jau yra suskirstytos į vardų vietas paketais. Vienintelė reali priežastis galvoti apie statinės klasės kūrimą yra ta, kad tokia klasė turi prieigą prie reikšmingų privačios statinės klasės klasių, bet manau, kad tai yra gana prastas pasiteisinimas dėl statinės klasės funkcijos.


Vidinės klasės

Vidinė klasė yra klasė, deklaruota kaip nestatinė kitos klasės narė:

 package pizza; public class Rhino { public class Goat { ... } private void jerry() { Goat g = new Goat(); } } 

Kaip ir statinei klasei, žinoma, kad vidinė klasė yra kvalifikuojama naudojant turimą klasės pavadinimą pica.Rhino.Goat, bet viduje esančioje klasėje ji gali būti žinoma pagal paprastą pavadinimą. Tačiau kiekvienas vidinės klasės egzempliorius yra susietas su konkrečiu jo turinio klasės egzemplioriumi: aukščiau, jerry sukurta ožka yra netiesiogiai susieta su Rhino pavyzdžiu jerry. Priešingu atveju, kai susikuriame ožką, aiškiai nurodome susijusį Rhino pavyzdį:

 Rhino rhino = new Rhino(); Rhino.Goat goat = rhino.new Goat(); 

(Atkreipkite dėmesį, kad į vidinį tipą kaip paprastą Kota kalbate keistoje naujajame sintaksėje: „Java“ sulaiko ribotą tipą iš ragino. Ir taip, naujasis rhino.Goat () man būtų prasmingesnis.)

Taigi, ką tai mums padeda? Na, vidinis klasės egzempliorius turi prieigą prie turinčio klasės egzemplioriaus narių. Šie įtraukti pavyzdžių nariai nurodo vidinę klasę per savo paprastus vardus, o ne per tai (tai reiškia vidinės klasės egzempliorių vidinėje klasėje, o ne atitinkamoje klasėje esančioje instancijoje):

 public class Rhino { private String barry; public class Goat { public void colin() { System.out.println(barry); } } } 

Vidinėje klasėje galite kreiptis į jį iš turinčios klasės kaip Rhino.this, ir jūs galite jį naudoti, pavyzdžiui, kreiptis į savo narius. Rhino.this.barry.


Vietinės vidinės klasės

Vietinė vidinė klasė yra klasė, deklaruota metodo kūne. Tokia klasė yra žinoma tik jos pridėjimo metodu, todėl ją gali sukurti ir prieiti tik jos nariai kaip savo metodo dalį. Pelnas slypi tuo, kad vietinė vidinė klasės kopija yra susieta ir gali gauti prieigą prie ribinių vietinių kintamųjų, turinčių jo turinį. Kai egzempliorius naudoja galutinį lokalumą iš savo turinio metodo, kintamasis išlaiko vertę, kurią jis išlaikė egzemplioriaus kūrimo metu, net jei kintamasis yra neveiksmingas (tai iš tikrųjų yra aiški apytikslė versija, ribota uždarymo versija).

Kadangi vietinė vidinė klasė nėra klasės ar paketo narė, ji nėra deklaruojama su prieigos lygiu. (Tačiau aišku, kad jos pačių nariai turi prieigos lygį, kaip ir įprastoje klasėje.)

Jei egzemplioriaus metode yra deklaruojama vietinė vidinė klasė, vidinės klasės egzempliorius yra susietas su egzemplioriumi, esančiame turinčiame metode, kuris buvo sukurtas kuriant egzempliorių, ir todėl turinio klasės instancijos nariai yra prieinami kaip vidinės klasės atveju. Vietinė vidinė klasė sukuriama paprasčiausiai pagal jo pavadinimą. vietinė „Cat“ vidinė klasė yra sukurta kaip nauja katė (), o ne nauja this.Cat (), kaip galite tikėtis.


Anoniminės vidinės klasės

Anoniminė vidinė klasė yra sintaksiškai patogus vietinės vidinės klasės rašymo būdas. Dažniausiai vietinė vidinė klasė sukuriama ne daugiau kaip vieną kartą kiekvieną kartą, kai jo metodas vykdomas. Būtų malonu, jei galėtume sujungti vidinės klasės ir jos vienintelės kūrybos vietinę apibrėžtį į vieną patogią sintaksinę formą, ir būtų malonu, jei neturėtume sugalvoti klasės pavadinimo (tuo mažiau naudingi jūsų kodų pavadinimai, tuo geriau). Anoniminė vidinė klasė leidžia abu šiuos dalykus:

 new *ParentClassName*(*constructorArgs*) {*members*} 

Ši išraiška grąžina naują nenurodytos klasės egzempliorių, išplečiantį ParentClassName. Jūs negalite pateikti savo konstruktoriaus; tai yra netiesiogiai sukurtas, kuris paprasčiausiai vadina super konstruktorių, todėl pateikti argumentai turi atitikti super konstruktorių. (Jei tėvui yra keli konstruktoriai, „paprasčiausias“ elementas vadinamas „paprasčiausia“, kaip apibrėžta gana sudėtingu taisyklių rinkiniu, kuris neturėtų būti išsamiai ištirtas - tiesiog atkreipkite dėmesį į tai, ką pasakoja „NetBeans“ ar „Eclipse“.)

Arba galite nurodyti sąsają, kurią norite įgyvendinti:

 new *InterfaceName*() {*members*} 

Ši deklaracija sukuria naują nenurodytos klasės egzempliorių, kuris išplečia Objektą ir įgyvendina sąsajos pavadinimą. Vėlgi, negalite pateikti savo konstruktoriaus; šiuo atveju „Java“ netiesiogiai numato ne-arg, do-nothing konstruktorių (todėl niekada nebus jokių konstruktoriaus argumentų).

Net jei negalite suteikti konstruktoriui anoniminės vidinės klasės, vis tiek galite atlikti bet kokį pageidaujamą pritaikymą naudodami iniciatoriaus bloką ({} blokuoti, esančius už bet kurio metodo ribų).

Akivaizdu, kad anoniminė vidinė klasė yra tik mažiau lankstus būdas sukurti vietinę vidinę klasę su vienu egzemplioriumi. Jei jums reikia vietinės vidinės klasės, kuri įgyvendina kelias sąsajas ar įgyvendina sąsajas, kai pratęsia bet kurią kitą klasę nei Objektas, arba kuri apibrėžia savo konstruktorių, esate įstrigę kurdami įprastą vietinę vidinę klasę.

540
16 сент. Jegschemesch atsakymas . 2008-09-16 12:24 '08, 12:24 val. 2008-09-16 12:24

Nemanau, kad realus skirtumas paaiškėjo pirmiau pateiktuose atsakymuose.

Pirmiausia gauti teisingus žodžius:

  • Įdėta klasė yra klasė, kuri yra kitoje klasėje pirminio kodo lygiu.
  • Tai yra statinis, jei deklaruojate jį su statiniu modifikatoriumi.
  • Ne statinė įdėta klasė vadinama vidine klase. (Aš pasilikau su nestatine įdėta klase.)

Martin atsakymas yra teisus. Tačiau tikrasis klausimas yra toks: koks tikslas yra deklaruoti įmontuotą statinę klasę?

Jei naudojatės klasėmis, jei naudojatės vietiniu mastu, arba jei įdėtos klasės naudojamos tik apvyniojimo klasėje, naudojate statines įdėtas klases . Nėra semantinio skirtumo tarp statinės įdėtos klasės ir kiekvienos kitos klasės.

Ne statiniai įdėtos klasės yra dar vienas žvėris. Kaip anoniminės vidinės klasės, tokios įdėtos klasės iš tikrųjų artimos. Tai reiškia, kad jie užfiksuoja supančią skalę ir jų pridedamą pavyzdį ir pateikia jį. Galbūt pavyzdys tai paaiškins. Žr. Šį konteinerio dangtelį:

 public class Container { public class Item{ Object data; public Container getContainer(){ return Container.this; } public Item(Object data) { super(); this.data = data; } } public static Item create(Object data){ // does not compile since no instance of Container is available return new Item(data); } public Item createSubItem(Object data){ // compiles, since 'this' Container is available return new Item(data); } } 

Tokiu atveju norite turėti nuorodą iš vaiko į pagrindinį konteinerį. Naudojant ne statinį įdėtą klasę, jis veikia be jokio darbo. Konteinerio aplinkos egzemplioriui galite pasiekti sintaksę Container.this .

Išsamesni paaiškinimai:

Jei žiūrite į „Java“ bytekodus, kuriuos kompiliatorius generuoja nestatinei įdėtai klasei, jis gali tapti dar aiškesnis:

 // class version 49.0 (49) // access flags 33 public class Container$Item { // compiled from: Container.java // access flags 1 public INNERCLASS Container$Item Container Item // access flags 0 Object data // access flags 4112 final Container this$0 // access flags 1 public getContainer() : Container L0 LINENUMBER 7 L0 ALOAD 0: this GETFIELD Container$Item.this$0 : Container ARETURN L1 LOCALVARIABLE this Container$Item L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 1 public <init>(Container,Object) : void L0 LINENUMBER 12 L0 ALOAD 0: this ALOAD 1 PUTFIELD Container$Item.this$0 : Container L1 LINENUMBER 10 L1 ALOAD 0: this INVOKESPECIAL Object.<init>() : void L2 LINENUMBER 11 L2 ALOAD 0: this ALOAD 2: data PUTFIELD Container$Item.data : Object RETURN L3 LOCALVARIABLE this Container$Item L0 L3 0 LOCALVARIABLE data Object L0 L3 2 MAXSTACK = 2 MAXLOCALS = 3 } 

Kaip matote, kompiliatorius sukuria paslėptą lauką „ Container this$0 . Tai nustatoma konstruktoriuje, kuris turi papildomą tipo „Container“ parametrą, kad būtų galima nurodyti pakuotės pavyzdį. Šį parametrą nematote šaltinyje, bet kompiliatorius netiesiogiai generuoja ją įdėtai klasei.

Martino pavyzdys

 OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 

bus sukompiliuotas, kad vadintumėte kažką panašaus (baitų kodais)

 new InnerClass(outerObject) 

Dėl išsamumo:

Anoniminė klasė yra puikus nestatinio įdėtos klasės pavyzdys, kuris tiesiog neturi su juo susijusio pavadinimo ir negali būti vėliau nurodytas.

129
16 сент. atsakymas pateikiamas jrudolph rugsėjo 16 d 2008-09-16 12:12 '08 12:12 val. 2008-09-16 12:12

Manau, kad nė vienas iš pirmiau pateiktų atsakymų jums nepaaiškina realaus skirtumo tarp įdėtos klasės ir statinio įdėtos klasės, atsižvelgiant į taikymo dizainą:

Apžvalga

Įdėta klasė gali būti ne statinė ar statinė, ir kiekvienu atveju tai yra klasė, apibrėžta kitoje klasėje . Įdėta klasė turėtų egzistuoti tik tam, kad tarnautų klasei , jei įdėta klasė yra naudinga kitoms klasėms (ir ne tik įdėtos), turėtų būti paskelbta aukščiausio lygio klasė.

Skirtumas

Ne statinė įdėta klasė : netiesiogiai susieta su turinčios klasės egzemplioriumi, tai reiškia, kad galite skambinti metodais ir prieiga prie aplinkos kintamųjų. Vienas įprastas būdas naudoti nestatinę įdėtą klasę yra nustatyti adapterio klasę.

Statinė įdėta klasė : negali prieiti prie klasės ir skambučių metodų egzemplioriaus, todėl ji turėtų būti naudojama, kai įdėtos klasės nereikia prieigos prie gaunamos klasės egzemplioriaus. Bendras statinio įdėtos klasės naudojimas yra išorinio objekto komponentų įgyvendinimas.

Išvada

Taigi pagrindinis skirtumas tarp dviejų dizaino aspektų: nestatinė įdėtinė klasė gali pasiekti konteinerių klasės egzempliorių, tačiau negalima statinio.

85
27 мая '12 в 10:43 2012-05-27 10:43 atsakymas pateikiamas „ aleroot “ gegužės 27 d. 12 val. 10:43 2012-05-27 10:43

Paprastai mums reikia įdėtos klasės, visų pirma todėl, kad „Java“ nesuteikia uždarymo.

Įdėtos klasės yra klasės, apibrėžtos kitos apimančios klasės kūne. Jie turi dviejų tipų - statinį ir nestatinį.

Jie traktuojami kaip klasifikuojančios klasės nariai, todėl galite nurodyti bet kurį iš keturių prieigos specifikų - private, package, protected, public . Neturime šio prabangos su aukščiausio lygio klasėmis, kurios gali būti paskelbtos tik public arba privačiais paketais.

Vidinėms klasėms, kurios priskiriamos neklasifikuotoms klasėms, suteikiama prieiga prie kitų viršutinės klasės narių, net jei jos yra paskelbtos privačiomis, o įdėtos statinės klasės neturi prieigos prie kitų aukštesnės klasės narių.

 public class OuterClass { public static class Inner1 { } public class Inner2 { } } 

Inner1 yra mūsų statiška vidinė klasė, o Inner2 yra mūsų vidinė klasė, kuri nėra statinė. Pagrindinis skirtumas tarp jų yra tas, kad negalite sukurti Inner2 instancijos be išorinio, kur galite sukurti „ Inner1 objektą.

Kada naudosite vidinę klasę?

Pagalvokite apie situaciją, kai Class A ir Class B yra prijungtos, Class B turėtų turėti prieigą prie Class A narių, o Class B susijusi tik su Class A Vidinės klasės ateina į paveikslėlį.

Norėdami sukurti vidinės klasės egzempliorių, turite sukurti savo išorinės klasės egzempliorių.

 OuterClass outer = new OuterClass(); OuterClass.Inner2 inner = outer.new Inner2(); 

arba

 OuterClass.Inner2 inner = new OuterClass().new Inner2(); 

Kada naudosite statinę klasę Vidinė?

Jei žinote, kad ji nėra susijusi su klasės / aukščiausios klasės egzemplioriumi, galite nustatyti statinę vidinę klasę. Jei jūsų vidinė klasė nenaudoja išorinės klasės metodų ar laukų, tai tik erdvės švaistymas, todėl padarykite jį statinį.

Pvz., Norėdami sukurti statinio įdėtos klasės objektą, naudokite šią sintaksę:

 OuterClass.Inner1 nestedObject = new OuterClass.Inner1(); 

Statinės įdėtos klasės privalumas yra tas, kad jam nereikia objekto, kuriame yra klasė / aukščiausia klasė. Tai gali padėti jums sumažinti taikomosiomis programomis sukurtų objektų skaičių.

31
18 окт. Atsakyti Thalaivar 18 okt. 2013-10-18 01:35 '13 ne 1:35 2013-10-18 01:35

Čia pateikiami pagrindiniai skirtumai ir panašumai tarp vidinės „Java“ klasės ir statinės įdėtos klasės.

Tikiuosi, kad tai padės!

Vidinė klasė

  • Prieiga prie išorinės klasės abiem atvejais ir statiniai metodai bei laukai
  • Susijęs su pridedamos klasės egzemplioriumi , todėl, norėdami ją sukurti, pirmiausia reikia išorinės klasės egzemplioriaus (atkreipkite dėmesį į naują raktinio žodžio vietą):

     Outerclass.InnerClass innerObject = outerObject.new Innerclass(); 
  • Negalima nustatyti jokių statinių elementų.

  • Negalima turėti klasės ar skelbimo

Statinė įdėta klasė

  • Nepavyksta pasiekti išorinių klasių metodų ar laukų atvejų

  • Nėra susieta su jokia pridedamos klasės instancija . Norėdami ją sukurti:

     OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass(); 

Panašumai

  • Abi vidinės klasės gali patekti į privačius laukus ir metodus išorinėje klasėje.
  • Be to, išorinė klasė turi prieigą prie privačių laukų ir vidinių klasių metodų.
  • Abi klasės gali turėti privačią, saugią arba atvirą prieigos modifikatorių.

Kodėl naudoti įdėtos klasės?

Pagal „Oracle“ dokumentus yra keletas priežasčių ( išsamūs dokumentai ):

  • Tai būdas logiškai grupuoti klases, kurios naudojamos tik vienoje vietoje: Jei klasė yra naudinga tik vienai kitai klasei, tai logiška ją įterpti į šią klasę ir laikyti juos kartu. Tokių „pagalbinių klasių“ įterpimas daro jų paketą labiau užsakomą.

  • Jis padidina kapsulių skaičių: Apsvarstykite dvi aukščiausio lygio klases: A ir B, kur B reikalauja prieigos prie narių, kurie priešingu atveju būtų paskelbti privačiais. Paslėpęs A klasės A klasę, A nariai gali būti paskelbti privačiais ir B gali juos pasiekti. Be to, pats B gali būti paslėptas nuo išorinio pasaulio.

  • Tai gali padėti geriau skaityti ir tvarkyti kodą: įdėtos mažos klasės aukščiausio lygio klasėse priartina kodą arčiau to, kur jis naudojamas.

26
31 дек. Atsakymas pateikiamas Behzad Bahmanyar gruodžio 31 d. 2015-12-31 23:53 '16 at 11:53 pm 2015-12-31 23:53

Manau, kad paprastai laikomasi konvencijos yra:

  • statinė klasė aukščiausio lygio klasėje
  • ne statinė klasė aukščiausio lygio klasėje yra vidinė klasė , kuri dar turi dvi formas:
    • vietinės klasės pavadinimai, paskelbti bloko viduje, kaip metodo ar konstruktoriaus kūnas
    • anoniminės klasės - nenurodytos klasės, kurių egzemplioriai yra sukurti išraiškose ir operatoriuose

Tačiau reikia paminėti kelis kitus dalykus :

  • Aukščiausio lygio klasės ir statinė įdėta klasė yra semantiškai tos pačios, išskyrus tai, kad statinės įdėtos klasės atveju ji gali statiškai nurodyti privačius statinius laukus / metodus savo išorinėje klasėje ir atvirkščiai.

  • Vidinės klasės turi prieigą prie išorinio [tėvų] klasės egzempliorių kintamųjų. Однако не все внутренние классы включают экземпляры, например, внутренние классы в статических контекстах, такие как анонимный класс, используемый в статическом блоке инициализатора, не делают.

  • Анонимный класс по умолчанию расширяет родительский класс или реализует родительский интерфейс, и нет дополнительного предложения для расширения любого другого класса или реализации каких-либо дополнительных интерфейсов. Taigi,

    • new YourClass(){}; означает class [Anonymous] extends YourClass {}
    • new YourInterface(){}; означает class [Anonymous] implements YourInterface {}