Vraag Java-binnenklasse en statische geneste klasse


Wat is het belangrijkste verschil tussen een innerlijke klasse en een statische geneste klasse in Java? Speelt ontwerp / implementatie een rol bij het kiezen van een van deze?


1464
2017-09-16 08:22


oorsprong


antwoorden:


Van de Java-zelfstudie:

Geneste klassen zijn onderverdeeld in twee categorieën: statisch en niet-statisch. Geneste klassen die statisch zijn verklaard, worden gewoon statische geneste klassen genoemd. Niet-statische geneste klassen worden innerlijke klassen genoemd.

Statische geneste klassen worden benaderd met behulp van de insluitende klassenaam:

OuterClass.StaticNestedClass

Als u bijvoorbeeld een object voor de statische geneste klasse wilt maken, gebruikt u deze syntaxis:

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

Objecten die instanties zijn van een innerlijke klasse, bestaan ​​binnen een instantie van de buitenklasse. Beschouw de volgende klassen:

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

Een instantie van InnerClass kan alleen bestaan ​​binnen een instantie van OuterClass en heeft directe toegang tot de methoden en velden van de bijbehorende instantie.

Als u een innerlijke klasse wilt instantiëren, moet u eerst de buitenklasse instellen. Maak vervolgens het binnenste object binnen het buitenste object met deze syntaxis:

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

zien: Java-zelfstudie - geneste klassen

Voor de volledigheid merk op dat er ook zoiets bestaat als een innerlijke klasse zonder een insluitende instantie:

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

Hier, new A() { ... } is een innerlijke klasse gedefinieerd in een statische context en heeft geen insluitende instantie.


1480
2017-09-16 08:28



De Java-tutorial zegt:

Terminologie: Geneste klassen zijn   verdeeld in twee categorieën: statisch   en niet-statisch. Geneste klassen dat   worden verklaard statisch worden gewoon genoemd   statische geneste klassen. Niet-statische   geneste klassen worden innerlijk genoemd   klassen.

In het spraakgebruik worden de termen 'genest' en 'innerlijk' door de meeste programmeurs door elkaar gebruikt, maar ik gebruik de juiste term 'geneste klasse' die zowel innerlijk als statisch weergeeft.

Klassen kunnen worden genest ad infinitumb.v. klasse A kan klasse B bevatten die klasse C bevat die klasse D, enz. bevat. Echter, meer dan één niveau van klassennesten is zeldzaam, omdat het over het algemeen slecht ontwerp is.

Er zijn drie redenen waarom u een geneste klasse zou kunnen maken:

  • organisatie: soms lijkt het het meest verstandig om een ​​klasse in de naamruimte van een andere klasse te sorteren, vooral wanneer deze niet in een andere context wordt gebruikt
  • toegang: geneste klassen hebben speciale toegang tot de variabelen / velden van hun bevattende klassen (welke variabelen / velden precies afhankelijk zijn van het soort geneste klasse, of dit nu innerlijk of statisch is).
  • gemak: het hebben van een nieuw bestand voor elk nieuw type is lastig, nogmaals, vooral als het type alleen in één context wordt gebruikt

Er zijn vier soorten geneste klasse in Java. Kort gezegd zijn ze:

  • statische klasse: verklaard als een statisch lid van een andere klasse
  • innerlijke klasse: verklaard als een instantie lid van een andere klasse
  • lokale innerlijke klasse: verklaard in een instantiemethode van een andere klasse
  • anonieme innerlijke klasse: als een lokale innerlijke klasse, maar geschreven als een uitdrukking die een eenmalig object retourneert

Ik zal nader ingaan op meer details.


Statische klassen

Statische klassen zijn het gemakkelijkst te begrijpen, omdat ze niets te maken hebben met instanties van de klasse containing.

Een statische klasse is een klasse die is gedeclareerd als een statisch lid van een andere klasse. Net als andere statische leden, is zo'n klasse eigenlijk slechts een hanger waarop de bevattende klasse als naamruimte wordt gebruikt, bijv. de klas Geit verklaard als een statisch lid van de klas Neushoorn in het pakket pizza staat bekend onder de naam pizza.Rhino.Goat.

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

Eerlijk gezegd, statische klassen zijn een behoorlijk waardeloze functie omdat klassen al door pakketten zijn verdeeld in naamruimten. De enige echt denkbare reden om een ​​statische klasse te maken is dat een dergelijke klasse toegang heeft tot de privé-statische leden van zijn bevattende klasse, maar ik vind dit een vrij zwakke rechtvaardiging voor het bestaan ​​van de statische klassefunctie.


Innerlijke klassen

Een innerlijke klasse is een klasse die is gedeclareerd als een niet-statisch lid van een andere klasse:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

Net als bij een statische klasse staat de binnenklasse bekend als gekwalificeerd door de klassenklasse, pizza.Rhino.Goat, maar binnen de klasse die het bevat, kan het bekend zijn door zijn eenvoudige naam. Elk exemplaar van een innerlijke klasse is echter gekoppeld aan een specifieke instantie van de klasse waarin het is gehuisvest: hierboven, de Geit gemaakt in Jerry, is impliciet gebonden aan de Neushoorn aanleg deze in Jerry. Anders maken we de bijbehorende Neushoorn bijvoorbeeld expliciet wanneer we instantiëren Geit:

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

(Merk op dat je naar het innerlijke type verwijst als rechtvaardig Geit in het rare nieuwe syntaxis: Java leidt het omvattende type uit de neushoorn een deel. En ja nieuwe rhino.Goat () zou ook voor mij logischer zijn geweest.)

Dus wat levert dit ons op? Welnu, de instantie van de inner class heeft toegang tot de instantie-leden van de instantie van de klasse die aanwezig is. Deze insluitende instantieleden worden binnen de innerlijke klasse aangeduid via gewoon hun eenvoudige namen, niet via  deze (deze in de binnenste klasse verwijst naar de instantie inner class, niet de bijbehorende instantie van de klasse containing):

public class Rhino {

    private String barry;

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

In de innerlijke klasse kun je verwijzen naar deze van de bevattende klasse als Rhino.this, en je kunt gebruiken deze om naar zijn leden te verwijzen, bijv. Rhino.this.barry.


Lokale binnenklassen

Een lokale innerlijke klasse is een klasse die wordt gedeclareerd in de hoofdtekst van een methode. Een dergelijke klasse is alleen bekend binnen de methode die deze bevat, zodat deze alleen kan worden geïnstantieerd en de leden ervan binnen de bijbehorende methode kunnen worden benaderd. De winst is dat een instantie van de lokale inner klasse gebonden is aan en toegang heeft tot de laatste lokale variabelen van zijn bevattende methode. Wanneer de instantie een laatste lokaal van de bijbehorende methode gebruikt, behoudt de variabele de waarde die hij had op het moment van het maken van de instantie, zelfs als de variabele buiten het bereik is gegaan (dit is in feite de ruwe, beperkte versie van sluitingen van Java).

Omdat een lokale innerlijke klasse niet het lid van een klasse of pakket is, wordt deze niet aangegeven met een toegangsniveau. (Houd er echter rekening mee dat de eigen leden toegangsniveaus hebben zoals in een normale klas.)

Als een lokale innerlijke klasse wordt gedeclareerd in een instantiemethode, wordt een instantiatie van de innerlijke klasse gekoppeld aan de instantie die wordt vastgehouden door de methode die de methode bevat deze op het moment van het maken van de instantie, en dus zijn de instantieleden van de bevattende klasse toegankelijk zoals in een instantie binnenklasse. Een lokale innerlijke klasse wordt eenvoudig geïnstantieerd via Zijn naam, bijv. lokale innerlijke klasse Kat wordt geïnstantieerd als nieuwe kat (), niet nieuw this.Cat () zoals je zou verwachten.


Anonieme binnenklassen

Een anonieme innerlijke klasse is een syntactisch handige manier om een ​​lokale innerlijke klasse te schrijven. Meestal wordt een lokale innerlijke klasse maximaal één keer geïnstantieerd telkens wanneer de bijbehorende methode wordt uitgevoerd. Het zou dan leuk zijn als we de definitie van de lokale innerlijke klasse en de afzonderlijke instantiatie zouden kunnen combineren in één handige syntaxisvorm, en het zou ook leuk zijn als we geen naam voor de klas hoefden bedenken (hoe minder onbehulpzaam namen die je code bevat, des te beter). Een anonieme innerlijke klasse laat beide dingen toe:

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

Dit is een expressie die een nieuw exemplaar retourneert van een naamloze klasse die zich uitbreidt ParentClassName. Je kunt niet je eigen constructor leveren; integendeel, men wordt impliciet geleverd die eenvoudigweg de superconstructor aanroept, dus de geleverde argumenten moeten in de superconstructor passen. (Als de ouder meerdere constructors bevat, wordt de "eenvoudigste" "eenvoudigste" genoemd, zoals bepaald door een nogal ingewikkelde set regels die niet de moeite waard zijn om gedetailleerd te leren - let gewoon op wat NetBeans of Eclipse je vertellen.)

Als alternatief kunt u een interface opgeven om te implementeren:

new *InterfaceName*() {*members*}

Zo'n verklaring creëert een nieuw exemplaar van een naamloze klasse die Object en implementaties uitbreidt Interfacenaam. Nogmaals, u kunt niet uw eigen constructor leveren; in dit geval levert Java impliciet een constructor van no-arg, do-nothing (dus in dit geval zullen er nooit constructorargumenten zijn).

Hoewel je een anonieme innerlijke klasse geen constructor kunt geven, kun je nog steeds elke gewenste setup uitvoeren met behulp van een initialisatieblok (een {} blok dat buiten elke methode wordt geplaatst).

Wees duidelijk dat een anonieme innerlijke klasse eenvoudigweg een minder flexibele manier is om met één instantie een lokale innerlijke klasse te creëren. Als u een lokale innerlijke klasse wilt die meerdere interfaces implementeert of interfaces implementeert terwijl u een andere klasse uitbreidt dan Voorwerp of die zijn eigen constructor specificeert, je bent vast aan het creëren van een reguliere benoemde lokale innerlijke klasse.


524
2017-09-16 09:24



Ik denk niet dat het echte verschil in de bovenstaande antwoorden duidelijk werd.

Eerst om de voorwaarden goed te krijgen:

  • Een geneste klasse is een klasse die zich op het broncodeniveau in een andere klasse bevindt.
  • Het is statisch als u het declareert met de statisch modifier.
  • Een niet-statische geneste klasse wordt innerlijke klasse genoemd. (Ik blijf bij een niet-statische geneste klasse.)

Martin's antwoord heeft tot nu toe gelijk. De eigenlijke vraag is echter: wat is het doel van het declareren van een geneste klasse statisch of niet?

Je gebruikt statische geneste klassen als je gewoon je klassen bij elkaar wilt houden als ze lokaal bij elkaar horen of als de geneste klasse uitsluitend wordt gebruikt in de klasse omsluiten. Er is geen semantisch verschil tussen een statische geneste klasse en elke andere klasse.

Niet-statische geneste klassen zijn een ander beest. Net als anonieme innerlijke klassen, zijn dergelijke geneste klassen eigenlijk sluitingen. Dat betekent dat ze hun omringende bereik en hun omhullende instantie vastleggen en dat toegankelijk maken. Misschien zal een voorbeeld dat verduidelijken. Zie dit streepje van een container:

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);
    }
}

In dit geval wilt u een verwijzing van een onderliggende artikel naar de bovenliggende container. Met een niet-statische geneste klasse werkt dit zonder enig werk. U kunt het insluitende exemplaar van Container openen met de syntaxis Container.this.

Meer hardcore uitleg volgt:

Als u de Java-bytecodes bekijkt die de compiler genereert voor een (niet-statische) geneste klasse, wordt deze mogelijk nog duidelijker:

// 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
}

Zoals u kunt zien, maakt de compiler een verborgen veld Container this$0. Dit wordt ingesteld in de constructor die een extra parameter van het type Container heeft om de insluitende instantie op te geven. U kunt deze parameter niet in de bron zien, maar de compiler genereert deze impliciet voor een geneste klasse.

Martin's voorbeeld

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

zou zo worden gecompileerd tot een oproep van zoiets (in bytecodes)

new InnerClass(outerObject)

Voor de volledigheid:

Een anonieme les is een perfect voorbeeld van een niet-statische geneste klasse waaraan gewoon geen naam is gekoppeld en waaraan later niet kan worden gerefereerd.


124
2017-09-16 09:12



Ik denk dat geen van de bovenstaande antwoorden u het echte verschil uitleggen tussen een geneste klasse en een statische geneste klasse in termen van toepassingsontwerp:

Overzicht

Een geneste klasse kan niet-statisch of statisch zijn en in elk geval is een klasse die is gedefinieerd in een andere klasse. Een geneste klasse moet alleen bestaan ​​om te dienen om klasse bij te sluiten, als een geneste klasse nuttig is voor andere klassen (niet alleen de insluitingen), moet deze worden gedeclareerd als een klasse op het hoogste niveau.

Verschil

Niet-statische geneste klasse : is impliciet geassocieerd met de omsluitende instantie van de bevattende klasse, dit betekent dat het mogelijk is om methoden en toegangsvariabelen van de omsluitende instantie op te roepen. Een veelgebruikt gebruik van een niet-statische geneste klasse is het definiëren van een adapterklasse.

Statische geneste klasse : kan geen toegang krijgen tot insluitende klasseninstantie en invoke-methoden erop, dus moet worden gebruikt wanneer de geneste klasse geen toegang vereist tot een instantie van de insluitende klasse. Een veelgebruikt gebruik van statische geneste klasse is het implementeren van een component van het buitenste object.

Conclusie

Dus het belangrijkste verschil tussen de twee vanuit een ontwerpstandpunt is: niet-gestapelde geneste klasse heeft toegang tot de instantie van de containerklasse, terwijl statische niet kan.


82
2018-05-27 07:43



In eenvoudige termen hebben we geneste klassen nodig, voornamelijk omdat Java geen sluitingen biedt.

Geneste klassen zijn klassen die zijn gedefinieerd in de hoofdtekst van een andere insluitende klasse. Ze zijn van twee soorten - statisch en niet-statisch.

Ze worden behandeld als leden van de omsluitende klasse, vandaar dat u een van de vier toegangsspecificaties kunt specificeren - private, package, protected, public. We hebben deze luxe niet bij klassen van het hoogste niveau, die alleen kunnen worden uitgeroepen public of pakket-privé.

Inner classes aka Non-stack klassen hebben toegang tot andere leden van de topklasse, zelfs als ze privé worden verklaard, terwijl statische geneste klassen geen toegang hebben tot andere leden van de topklasse.

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

Inner1 is onze statische innerlijke klasse en Inner2 is onze innerlijke klasse die niet statisch is. Het belangrijkste verschil tussen beide is dat je geen kunt maken Inner2 bijvoorbeeld zonder een Outer waar je een kunt maken Inner1 object onafhankelijk.

Wanneer zou je Innerlijke klasse gebruiken?

Denk aan een situatie waarin Class A en Class B zijn verwant, Class B moet toegang hebben Class A leden, en Class B is alleen gerelateerd aan Class A. Innerlijke klassen komen in beeld.

Voor het maken van een instantie van de innerlijke klasse, moet je een instantie van je uiterlijke klasse maken.

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

of

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

Wanneer zou u de statische Innerklasse gebruiken?

U zou een statische binnenklasse definiëren als u weet dat deze geen relatie heeft met de instantie van de omsluitende klasse / topklasse. Als je innerlijke klasse geen methoden of velden van de uiterlijke klasse gebruikt, is het alleen maar verspilling van ruimte, dus maak het statisch.

Als u bijvoorbeeld een object voor de statische geneste klasse wilt maken, gebruikt u deze syntaxis:

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

Het voordeel van een statische geneste klasse is dat deze geen object van de klasse containing / topklasse nodig heeft om te werken. Dit kan u helpen om het aantal objecten dat uw toepassing tijdens runtime maakt te verminderen.


30
2017-10-17 22:35



Ik denk dat de conventie die over het algemeen wordt gevolgd, deze is:

  • statische klasse binnen een klasse op het hoogste niveau is een geneste klasse
  • niet-statische klasse binnen een klasse op het hoogste niveau is een innerlijke klasse, welke verder heeft nog twee vormen:
    • lokale klasse - benoemde klassen gedeclareerd binnen een blok, zoals een methode of een constructor-instantie
    • anonieme les - klassen zonder naam waarvan de instanties zijn gemaakt in uitdrukkingen en verklaringen

Er zijn echter weinig andere punten om te onthouden zijn:

  • Klassen op het hoogste niveau en statische geneste klassen zijn semantisch hetzelfde, behalve dat in geval van statische geneste klasse het statische verwijzing kan maken naar private statische velden / methoden van de buitenste [bovenliggende] klasse en vice versa.

  • Binnenklassen hebben toegang tot instantievariabelen van het insluitende exemplaar van de klasse Outer [boven]. Niet alle binnenklassen hebben echter insluitende instanties, bijvoorbeeld innerlijke klassen in statische contexten, zoals een anonieme klasse die wordt gebruikt in een statisch initialisatieblok, niet.

  • De anonieme klasse standaard breidt de bovenliggende klasse uit of implementeert de bovenliggende interface en er is geen verdere clausule om een ​​andere klasse uit te breiden of meer interfaces te implementeren. Zo,

    • new YourClass(){};middelen class [Anonymous] extends YourClass {}
    • new YourInterface(){};   middelen class [Anonymous] implements YourInterface {}

Ik voel dat de grotere vraag die openblijft welke moet worden gebruikt en wanneer? Nou dat hangt meestal af van het scenario waarmee je te maken hebt, maar het lezen van het antwoord van @jrudolph kan je helpen een beslissing te nemen.


24
2017-12-16 11:38



Hier zijn de belangrijkste verschillen en overeenkomsten tussen de Java-binnenklasse en de statische geneste klasse.

Hoop dat het helpt!

Innerlijke klasse

  • Heeft toegang naar de buitenklasse zowel instantie als statisch methoden en velden
  • Geassocieerd met instantie van omsluitende klasse dus om te instantiëren heeft het eerst een instantie van de buitenklasse nodig (noot nieuwe trefwoord plaats):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
    
  • Kan niet definieer een statische leden zelf

  • Kan niet hebben Klasse of Interface verklaring

Statische geneste klasse

  • Geen toegang buitenste klasse aanleg methoden of velden

  • Niet geassocieerd met een instantie van klasse omsluiten Dus om het te tonen:

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

overeenkomsten

  • Beide Innerlijke klassen kan zelfs toegang krijgen privévelden en -methoden van buitenste klasse
  • Ook de Buitenste klasse toegang hebben tot privévelden en -methoden van innerlijke klassen
  • Beide klassen kunnen een private, protected of public access modifier hebben

Waarom geneste klassen gebruiken?

Volgens de documentatie van Oracle zijn er verschillende redenen (volledige documentatie):

  • Het is een manier om lesgroepen logisch te groeperen die slechts op één plaats worden gebruikt: Als een klasse nuttig is voor slechts één andere klasse, is het logisch om de klasse in die klasse in te bedden en de twee bij elkaar te houden. Door dergelijke "helperklassen" te nesten, wordt hun pakket gestroomlijnder.

  • Het verhoogt de inkapseling: Overweeg twee klassen op het hoogste niveau, A en B, waarbij B toegang nodig heeft tot leden van A die anders privé zouden zijn verklaard. Door klasse B te verbergen in klasse A, kunnen A-leden privé worden verklaard en kan B toegang krijgen. Bovendien kan B zelf worden verborgen voor de buitenwereld.

  • Het kan leiden tot meer leesbare en onderhoudbare code: Door kleine klassen in klassen van het hoogste niveau te nestelen, wordt de code dichter bij de locatie geplaatst.


23
2017-12-31 20:53



Geneste klasse: klasse in de klas

Soorten:

  1. Statische geneste klasse
  2. Niet-statische geneste klasse [Innerlijke klasse]

Verschil:

Niet-statische geneste klasse [Innerlijke klasse]

In niet-statisch genest klasseobject van innerlijke klasse bestaan ​​binnen het object van de buitenklasse. Zodat het datalid van de uiterlijke klasse toegankelijk is voor de innerlijke klasse. Dus om een ​​object van innerlijke klasse te creëren, moeten we eerst een object van de uiterlijke klasse maken.

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

Statische geneste klasse

In statisch genest klasseobject van binnenklasse geen object van de buitenklasse nodig, omdat het woord "statisch" aangeeft dat er geen object hoeft te worden gemaakt.

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

Als u toegang wilt tot x, schrijf dan de volgende inside-methode

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);

13
2018-04-04 10:14



Het exemplaar van de binnenklasse wordt gemaakt wanneer een instantie van de buitenklasse wordt gemaakt. Daarom hebben de leden en methoden van de binnenste klasse toegang tot de leden en methoden van de instantie (object) van de buitenklasse. Wanneer de instantie van de buitenklasse buiten bereik raakt, houden ook de voorbeelden uit de innerlijke klasse op te bestaan.

De statische geneste klasse heeft geen concrete instantie. Het wordt gewoon geladen wanneer het voor de eerste keer wordt gebruikt (net als de statische methoden). Het is een volledig onafhankelijke entiteit, waarvan de methoden en variabelen geen toegang hebben tot de instanties van de buitenklasse.

De statisch geneste klassen zijn niet gekoppeld aan het buitenobject, ze zijn sneller en nemen geen Heap / Stack-geheugen aan, omdat het niet nodig is om een ​​instantie van een dergelijke klasse te maken. Daarom is de vuistregel om te proberen om statische geneste klasse te definiëren, met een zo beperkt mogelijk bereik (privé> = klasse> = beschermd> = openbaar), en het vervolgens om te zetten naar de binnenklasse (door de "statische" identifier te verwijderen) en los te maken het bereik, als het echt nodig is.


11
2017-09-16 08:58



Er is een subtiliteit over het gebruik van geneste statische klassen die in bepaalde situaties nuttig kunnen zijn.

Terwijl statische attributen worden geïnstantieerd voordat de klasse wordt geïnstantieerd via zijn constructor, Statische kenmerken in geneste statische klassen lijken niet te worden geïnstantieerd tot na de de constructor van de klasse wordt aangeroepen, of ten minste niet tot nadat eerst naar de attributen is verwezen, zelfs als ze zijn gemarkeerd als 'definitief'.

Beschouw dit voorbeeld:

public class C0 {

    static C0 instance = null;

    // Uncomment the following line and a null pointer exception will be
    // generated before anything gets printed.
    //public static final String outerItem = instance.makeString(98.6);

    public C0() {
        instance = this;
    }

    public String makeString(int i) {
        return ((new Integer(i)).toString());
    }

    public String makeString(double d) {
        return ((new Double(d)).toString());
    }

    public static final class nested {
        public static final String innerItem = instance.makeString(42);
    }

    static public void main(String[] argv) {
        System.out.println("start");
        // Comment out this line and a null pointer exception will be
        // generated after "start" prints and before the following
        // try/catch block even gets entered.
        new C0();
        try {
            System.out.println("retrieve item: " + nested.innerItem);
        }
        catch (Exception e) {
            System.out.println("failed to retrieve item: " + e.toString());
        }
        System.out.println("finish");
    }
}

Hoewel 'genest' en 'innerItItIt' beide worden gedeclareerd als 'statische finale'. de instelling van nested.innerItem vindt niet plaats tot nadat de klasse is geïnstantieerd (of tenminste pas nadat er eerst naar het genestelde statische item is verwezen), zoals u zelf kunt zien door commentaar te geven en de opmerkingen ongedaan te maken waar ik naar verwijs, hierboven. Hetzelfde geldt niet waar voor 'outerItem'.

Dit is tenminste wat ik zie in Java 6.0.


10
2018-03-26 12:38