Archief - [Java] inner class met een static member

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

forloRn_

Legacy Member
Code:
public class Outer {   
    private class Inner {   
        private static Object member; // static, compileert niet   
    }   
}

Deze code compileert niet. Ik zie niet in waarom Inner geen static member kan hebben die gedeeld wordt door alle instances van Inner.

Iemand een idee?

Fraggie

Legacy Member
Wij hebben daar echt diep op in gegaan, maar wat ik lees is:
- een inner klasse is geen top-level klasse (zoals Outer top-level is)
- static vars, alleen in top-level of static klassen.

Een oplossing:
Code:
public class Outer { 
    private static class Inner {   
        private static Object member; // static, compileert niet   
    }   
}

forloRn_

Legacy Member
Da's niet echt een antwoord natuurlijk. Waarom mogen static members alleen in top-level of static classes?

Met je oplossing ben ik ook niet akkoord: door Inner static te maken ben je je referentie naar je Outer instance kwijt.

Fraggie

Legacy Member
Okay:

- Een static var staat ergens op een vaste plaats in het geheugen, los van een object dus. Alle objecten kunnen deze raadplegen/manipuleren. We zeggen dat hij eigen is aan een klasse en niet een object.

- Een interne klasse is een instantie van een top-level klasse. Bij het aanmaken van de top-level klasse wordt er dus geheugen vrij gemaakt voor de uitwendige en inwendige klasse. Probeer dit te zien als 1 geheel.

- Als je dus een static var, in een interne klasse gedefinieerd hebt, die zelf niet static is, dan zou je per top-level object, een nieuwe static var gemaakt hebben. Nu bind je dus wel een static var aan een object, en niet aan een klasse.

De compiler kan dus onmogelijk de static modifier toepassen op jou var, omdat ze object gebonden is.

forloRn_

Legacy Member
Fraggie zei:
Okay:

- Een static var staat ergens op een vaste plaats in het geheugen, los van een object dus. Alle objecten kunnen deze raadplegen/manipuleren. We zeggen dat hij eigen is aan een klasse en niet een object.

Juist.

Fraggie zei:
- Een interne klasse is een instantie van een top-level klasse. Bij het aanmaken van de top-level klasse wordt er dus geheugen vrij gemaakt voor de uitwendige en inwendige klasse. Probeer dit te zien als 1 geheel.

Wat bedoel je met "een interne klasse is een instantie van een top-level klasse?" Wat bedoel je met het aanmaken van de top-level klasse? Classloading of instantiëren?

Fraggie zei:
- Als je dus een static var, in een interne klasse gedefinieerd hebt, die zelf niet static is, dan zou je per top-level object, een nieuwe static var gemaakt hebben. Nu bind je dus wel een static var aan een object, en niet aan een klasse.

De compiler kan dus onmogelijk de static modifier toepassen op jou var, omdat ze object gebonden is.

Static staat toch sowieso los van instanties? Volgens mij spreek je hier je eerste punt tegen.

Fraggie

Legacy Member
forloRn_ zei:
Wat bedoel je met "een interne klasse is een instantie van een top-level klasse?" Wat bedoel je met het aanmaken van de top-level klasse? Classloading of instantiëren?
Gewoon als je een object aanmaakt van je Outer klasse, dan moet er sowieso geheugen vrij gemaakt worden binnen het object van je Outer klasse, om de Inner te kunnen gebruiken.
M.a.w. bij het initialiseren/aanmaken van je top-level klasse.
forloRn_ zei:
Static staat toch sowieso los van instanties? Volgens mij spreek je hier je eerste punt tegen.
Aja, das juist om een punt te bewijzen he :p. Let op de "zou" en volgende uitleg.

forloRn_

Legacy Member
Fraggie zei:
Gewoon als je een object aanmaakt van je Outer klasse, dan moet er sowieso geheugen vrij gemaakt worden binnen het object van je Outer klasse, om de Inner te kunnen gebruiken.
M.a.w. bij het initialiseren/aanmaken van je top-level klasse.

Het instantiëren van Outer wilt toch niet zeggen dat er ook een Inner geïnstantieerd wordt? Voer dit eens uit:

Code:
public class Outer {
	
	public Outer() {
		System.out.println("Outer ctor");
	}
	
	private class Inner {
		Inner() {
			System.out.println("Inner ctor");
		}
	}
	
	public static void main(String[] args) {
		new Outer();
		new Outer();
		new Outer();
	}
}

Fraggie

Legacy Member
forloRn_ zei:
Het instantiëren van Outer wilt toch niet zeggen dat er ook een Inner geïnstantieerd wordt?
Nee nee, ik heb dat blijkbaar verkeerd verwoord.

Er wordt dus van de Inner class geen object aangemaakt, maar de VM moet wel weten hoe groot ze zou moeten worden (later kan dat natuurlijk nog uitbreiden).

Het uiteindelijke resultaat moet er zo uit zien: http://java.sun.com/docs/books/tutorial/figures/java/classes-inner.gif

De Inner class is een instantie van de Outer class.

forloRn_

Legacy Member
Dat tekeningetje wilt toch gewoon zeggen dat een inner class een referentie heeft naar haar outer class, en dat ze aan alle members van die outer class kan.

Fraggie zei:
De Inner class is een instantie van de Outer class.

Met permissie, maar dat slaat op niks. Een object kan een instantie zijn van een klasse. Outer en Inner behoren niet tot dezelfde klassenhiërarchie. Je kunt de ene klasse zelfs laden zonder dat de andere geladen wordt en omgekeerd.

Fraggie

Legacy Member
forloRn_ zei:
Dat tekeningetje wilt toch gewoon zeggen dat een inner class een referentie heeft naar haar outer class, en dat ze aan alle members van die outer class kan.
Dit komt letterlijk uit de Java tutorial:
"Objects that are instances of an inner class exist within an instance of the outer class."

forloRn_ zei:
Met permissie, maar dat slaat op niks.
Oke ik geef toe dat die zin nu totaal niet klopt, maar je zou nu toch al moeten weten in welke richting ik ga.

beter zou zijn:

Per object van de klasse Outer, kan je verschillende objecten van de klasse Inner aanmaken. Deze zijn hoe dan ook volledig toegewijd aan Outer:
http://img193.imageshack.us/img193/4053/java.gif
Als de groene rechthoek het geheugen bereik is van het Outer-object. Dan stelt elke blauwe rechthoek 1 instantie van de Inner-klasse voor.
(daarom dat ik zei inner behoord tot outer (maar dan in iets wat andere woorden :p))

forloRn_ zei:
Outer en Inner behoren niet tot dezelfde klassenhiërarchie. Je kunt de ene klasse zelfs laden zonder dat de andere geladen wordt en omgekeerd.
Hoe bedoel je juist?

forloRn_

Legacy Member
Dat mag je toch niet letterlijk nemen. 't Is niet omdat wij objecten als een mooi geheel zien dat ze daarom ook netjes een continu gebied in het geheugen innemen. Hoe ze juist in het geheugen terechtkomen is interne keuken van het virtual machine en het OS en staat los van Java op zich.

Ze willen gewoon zeggen dat 1) een Inner object niet kan bestaan zonder een instance van een Outer object omdat een Inner object altijd een referentie heeft naar haar Outer object (per definitie!) en 2) een Inner object toegang heeft tot alle members van haar Outer object, ongeacht de visibility.

Hoe dan ook, ik zie nog altijd geen enkele reden waarom er geen static members in inner classes mogen. Ik heb dezelfde vraag ook eens gepost op javaranch.com. Als je geïnteresseerd bent in hun reactie, kan je hier eens gaan kijken.

MilM

Legacy Member
forloRn_ zei:
Code:
Deze code compileert niet. Ik zie niet in waarom Inner geen static member kan hebben die gedeeld wordt door alle instances van Inner.
[/QUOTE]

Zal gewoon een beslissing zijn van Java in hun design. (of eventueel om een historische reden, dunno)
De reden waarom het niet toegelaten is zal je volgens mij niet echt kunnen achterhalen, tenzij iemand van Java zelf er een statement over gemaakt heeft.

Fraggie

Legacy Member
forloRn_ zei:
Dat mag je toch niet letterlijk nemen. 't Is niet omdat wij objecten als een mooi geheel zien dat ze daarom ook netjes een continu gebied in het geheugen innemen. Hoe ze juist in het geheugen terechtkomen is interne keuken van het virtual machine en het OS en staat los van Java op zich.
Okay, laat me toe om het nog 1x te proberen:
  1. Een inner class is geen top-level class, net als in VHDL en µC. Je mag er dus ook niet van uit gaan dat ze beide dezelfde eigenschappen hebben.

  2. Je mag zeggen dat in C de voorloper van een class een struct was. En een struct houd alle variabelen in 1 stuk geheugen (we spreken hier over de primitieve datatypes van in Java).

  3. Ik heb een vriend die als afstudeer richting compilers doet, en daar beginnen ze met uitleg te geven over bestaande compilers/technieken. Ook hij zegt dat dat bij het aanmaken van een object de attributen samen gehouden worden.

    Het komt er altijd op neer dat, je de hoeveelheid geheugen van je attributen, moet kunnen bezetten in RAM. Hoewel een String nu in Java toch beter is dan een string in C++, zou ik ze nu beschouwen als een plain char array (char = primitief). Nu is het gemakkelijk te begrijpen dat elke klasse een vaste grootte heeft.

    Wanneer je objecten van je klassen maakt, en er mee begint te werken ga je alleen maar pointers bij maken en locale variabelen. De Java compilers kan dus onmogelijk weten hoeveel je er zal bij maken (vergelijk dit een beetje met de stack and heap van C++).

  4. Als je in je top-level klasse een static attribuut hebt, dan weet de JVM waar deze staat, tot je alle referenties naar het object verliest.


    Nu komt het:
  5. Bij het aanmaken van een object, van de Outer klasse, MOET er geheugen gemaakt worden voor op zijn minst de attributen, van de Inner klasse. Want de Inner klasse is geprogrammeerd IN de Outer klasse. Dus nog vóór er een object gemaakt wordt van de Inner klasse, zou er reeds nu een stukje “shared memory” moeten bestaan, voor die static attribuut. Waar zou de VM dit moeten schrijven? In de geheugen ruimte van het Outer object? Dan behoord het toch tot het Outer object en niet tot het Inner object?

  6. Stel nu dat jij gelijkt hebt, en er alleen referenties naar Inner objecten in een Outer object staan. Dan vind ik dat als je 1 Outer object en 20 Inner objecten aanmaakt, en je het Outer object vrij geeft de Inner objecten moeten blijven bestaan. Want ze bestaan op hen eentje zonder link/klassenhiërarchie naar het Outer object, zoals jij hier zegt:

    Outer en Inner behoren niet tot dezelfde klassenhiërarchie. Je kunt de ene klasse zelfs laden zonder dat de andere geladen wordt en omgekeerd.

    Dan heb je toch een huge memory leak gemaakt? 20 objecten die blijven bestaan zonder pointers en shared memory gebruiken die nooit meer zal vrij gegeven worden.

    Met dit puntje kan ik dus geen vrede sluiten want dit kan gewoon niet in Java. memory leaks zouden verleden tijd moeten zijn in Java, maar daar hebben we totaal geen zicht over.

  7. Moest je echter wel 2 aparte top-level klassen schrijven, die gewoon gebruik maken van elkaar, dan is er geen probleem. Elk object wordt op zijn tijd aangemaakt.

    Het verschil zit hem hier in:
    Inner.java
    Code:
     public class Inner 
    {
         private static Object member;
    }

    Outer.java
    Code:
    public class Outer 
    {
        int x;
        Inner innerObject;
        public Outer(int x)
        {
            this.x = x;
            innerObject = new Inner();
        }
    }

    Nu beschik je over 2 top-level klassen. Hoewel een object van de klasse Outer nu ook ooit wel eens gebruik zal maken van een object uit de klasse Inner. Daarom kies ik bewust niet voor de default constructor. Dan is de grootte van de klasse Outer bij het aanmaken, echter perfect gekend. Want de regel Inner innerObject; is gewoon een pointer (precies zoals jij al meerdere keren gezegd hebt) naar null en neemt een pointer is altijd even groot (int? long? ala primitief data type).


    Om het nu volledig over de schreef te gaan (staat los van de jou klassen):
  8. Ik denk dat het logisch is dat je geen static attributen kan gebruiken, die van globaal belang zijn in en naamloze instantie van een anonieme (interne) klasse.

MilM

Legacy Member
Fraggie zei:
[*] Stel nu dat jij gelijkt hebt, en er alleen referenties naar Inner objecten in een Outer object staan. Dan vind ik dat als je 1 Outer object en 20 Inner objecten aanmaakt, en je het Outer object vrij geeft de Inner objecten moeten blijven bestaan. Want ze bestaan op hen eentje zonder link/klassenhiërarchie naar het Outer object, zoals jij hier zegt:

Dit geldt ook voor Outer klassen. Het is niet omdat je alle instanties vrijgeeft, dat je daarom geen statische variabele of methode meer zou kunnen oproepen.

Technisch is het mijn inziens wel mogelijk om te zorgen dat een Inner klasse op dat vlak dezelfde mogelijkheden heeft als Outer klasse op low level, alleen voorziet Java het niet.

Waarom ze het niet voorzien is dan denk ik ook een kwestie van historische redenen (ik ken te weinig van de mapping van de high lvl naar low lvl, maar hiermee bedoel ik dat het eerst niet voorzien was en dat het achteraf te moeilijk of teveel werk is om het nog te voorzien.) of designredenen. Ze vinden het mss niet proper en verplichten u dan maar om een echte klasse te gebruiken (outer klasse)
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan