Bestätigung bzgl Shadowing/this

Wolfone

Mitglied
Hallo liebe Forumler,

vorab: mir ist bewusst, dass es zu diesem Thema eine Menge Beiträge gibt. Mir hilft es verständnistechnisch oft Dinge slebst nochmal zu formulieren und ich würde gerne wissen, ob die Erklärung, die ich gliech liefern werde so stehengelassen werden kann. Ich wäre dankbar, wenn jemand da für mich drüberschauen könnte.

Es dreht sich um folgendes Beispiel (bin nciht mehr sicher, wo ich es gesehen habe, mag sogar von Oracle kommen):

Java:
public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

Die Ausgabe ist:
x = 23
this.x = 1
ShadowTest.this.x = 0

Erklärung in eigenen Worten:
"this" bezieht sich auf das aktuelle Objekt (bzw. das Objekt, aus dem ein Konstruktor oder eine methode aufgerufen wird).
Daher liefert this.x die 1, weil die methode in fl aufgerufen wird, was eine Instanz der nested class FirstLevel ist in der x = 1 war, was wir auch nicht verändert haben.
Mit ShadowTest.this.x arbeiten wir uns zu der "Oberklasse" durch.

Wenn man in ShadowTest.this.x das this streicht, gibt's einen Fehler (cannot make static reference to non static field); das ist sinnig. ShadowTest ist ja erstmal nur der Klassenname. Statisch bezieht sich auf die Klasse an sich, nicht statisch auf veränderbare Felder von Instanzen von Klassen
In meiner Klasse ShadowTest ist x ein nicht statisches Feld, es kann theoretisch nach der Instanzierung verändert werden. Würde ich also einfach nur ShadowTest.x ansprechen, wäre das ein logischer faux-pas, da ich ja meinem Programm ja nicht mitgeteilt habe, aus welcher Instanz er das x hernehmen soll.
Deswegen "this". Die andere Möglichkeit eine Fehlermeldung zu vermeiden wäre x zu einem static zu machen, dann ist es immer gleich und ein ShadowTest.x würde keine Probleme verursachen.
Hier sage ich mit ShadowTest.this.x, wenn ich es richtig verstanden habe: "Ich meine das Shadowtest, welches zum this gehört, sprich die "Mutterklasse" von fl, in dem ich gerade die Methode aufrufe".
Diese ist bereits instanziert und dort ist x = 0, also alles paletti. Ich darf allerdings nicht schreiben st.x, weil innerhalb der Methode ja per se noch kein st erzeugt ist. Das passiert in dem Beispiel erst zur Laufzeit, weswegen hier der Aufruf nur über den Typ ShadowTest geschieht.


Kann man das so stehen lassen?

Wäre dankbar für Bestätigung/Ergänzung/Verbesserung.

Beste Grüße
Wolf
 

InfectedBytes

Top Contributor
Du sprichst von Oberklasse bzw. Mutterklasse, aber typischerweise werden diese Begriffe nur benutzt, wenn deine Klasse davon erbt, dass tut sie aber nicht.

In diesem Fall hast du einfach nur eine Klasse innerhalb einer anderen erstellt (Stichwort: non-static nested class).
Hierbei greifst per ShadowTest.this auf die Instanz der äußeren Klasse zu. Dies geht nur bei non-static nested classes.
 

Baldur

Aktives Mitglied
Ein bisschen klarar wird es vielleicht auch, wenn man sich etwas veranschaulicht, was der Compiler denn so treibt, wenn du das Beispiel erstellst. Der erstellt dir nämlich heimlich ein Feld in der Inneren Klasse, das eine Referenz auf die äußere Klasse abspeichert. Mit ShadowTest.this greifst du dann auf dieses generierte Feld zu. Deshalb kannst du auch keine Instanz von FirstLevel erzeugen, ohne zuvor schon eine Instanz von ShadowTest zu haben.

Was dir der Compiler generiert sieht etwa so aus:
Java:
public class ShadowTest {
    public int x = 0;

    class FirstLevel {
        private ShadowTest ShadowTestThis;
        public int x = 1;

        public FirstLevel(ShadowTest st) {
            ShadowTestThis = st;
        }

        void methodInFirstLevel(int x) {
            System.out.println("ShadowTest.this.x = " + ShadowTestThis.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = ShadowTest.FirstLevel(st);
        fl.methodInFirstLevel(23);
    }
}

Wenn du FirstLevel als static markierst, macht der Compiler an der Stelle gar nichts, und FirstLevel verhält sich wie eine ganz normale Klasse.
 

Wolfone

Mitglied
Hallo ihr Beiden!

Danke für die Antworten. Entschuldige bitte die ungenaue Terminologie, mir ist da im Eifer des Gefechts nicht die beste Möglichkeit in den Sinn gekommen.

Interessant zu sehen, wie das so intern funktioniert.

Was ich mir gerade spontan nicht so richtig vorstellen kann ist der Sinn einer static inner class, da ich allen unveränderlichen Inhalt ja auch einfach so angeben könnte.
Gibt es da ein Standard-Beispiel, wo das zum Einsatz kommt?
Mir kommt fürs erste nur die Idee, dass das evtl. den Code ansatzweise lesbarer machen kann, je nach Umständen.
 

InfectedBytes

Top Contributor
Auch statische Felder sind veränderbar. Nur finale Variablen sind unveränderbar. Aber Achtung, wenn diese Variable ein Objekt ist, heißt dass nur, dass die Variable immer auf die gleiche Instanz zeigt, innerhalb des Objekts kann man weiterhin Änderungen durchführen.

Du scheinst mir hier sehr viele Dinge durcheinander zu bringen.
Schau dir am besten mal ein Buch/Tutorial zu statischen inneren Klassen, statischen Variablen und finalen Variablen an.
http://openbook.rheinwerk-verlag.de/javainsel/
bzw. Genauer:
static
static inner class
final
 

Wolfone

Mitglied
In der Tat. Ich habe static mit final verschwurbelt.
Danke für die Links! Interessante Anmerkungen zum allgemeinen "do and don't".
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Nach einer erstmaligen Eingabe, eine zweite Eingabe nur noch gegen bestätigung möglich Java Basics - Anfänger-Themen 2
A Grundrechenarten; Aufforderung zur Bestätigung oder Auswahl Java Basics - Anfänger-Themen 25
K Neues Bild bei eingabe bestätigung erscheinen Java Basics - Anfänger-Themen 21
D Frage bzgl. Enum-Handhabung Java Basics - Anfänger-Themen 16
N Was passiert wenn wir Daten auf der Festplatte abspeichern wollen? bzgl. BufferStreams Java Basics - Anfänger-Themen 9
A Variablen Verständnisfrage bzgl. Variablen/Referenzen Java Basics - Anfänger-Themen 3
J Worte auf Gültigkeit bzgl. Alphabet testen Java Basics - Anfänger-Themen 1
D Frage bzgl. Interfaces Java Basics - Anfänger-Themen 10
G Datentypen Tipps, Ratschläge erwünscht bzgl. Datentyp bestimmen über Wertebereich Java Basics - Anfänger-Themen 5
M Frage bzgl. Testbarkeit von Methoden in Relation zu Ihren Abhängigkeiten Java Basics - Anfänger-Themen 11
J Klassen Hilfe bei unbekannten Zeilen bzgl. Klassen / Komponenten Java Basics - Anfänger-Themen 12
K Frage bzgl. Multithreading Java Basics - Anfänger-Themen 5
M Frage bzgl. Oracle Java Zertifizierung Java Basics - Anfänger-Themen 4
1 Frage bzgl. Polymorphismus Java Basics - Anfänger-Themen 6
C Best Practice Was ist die elegantere Lösung bzgl. Klassenaufteilung in Robocode ? Java Basics - Anfänger-Themen 3
E Threads Verständnisfrage bzgl. Threads und Sleep Java Basics - Anfänger-Themen 2
X Frage zur Vererbung (bzgl Supercontruktor) Java Basics - Anfänger-Themen 7
F Verständisproblem bzgl. nicht Vorhandensein von Call-by-reference Java Basics - Anfänger-Themen 2
P Fehlersuche bzgl. Array-Keys Java Basics - Anfänger-Themen 6
L Frage bzgl. Threads beim Bilder laden Java Basics - Anfänger-Themen 3
0x7F800000 Elemente einer Äquivalenzklasse bzgl einer Ordnung vereinen? Java Basics - Anfänger-Themen 18
P Verständnis bzgl. MVC Java Basics - Anfänger-Themen 11
P Frage bzgl. Class Sharing Java Basics - Anfänger-Themen 2
G Dringende Frage bzgl. meines Codes Java Basics - Anfänger-Themen 30
C Frage bzgl. main Java Basics - Anfänger-Themen 2
C Frage bzgl. action von Button Java Basics - Anfänger-Themen 6

Ähnliche Java Themen

Neue Themen


Oben