Kann "dies" in Java jemals null sein?

109

Ich habe diese Zeile in einer Klassenmethode gesehen und meine erste Reaktion war, den Entwickler, der sie geschrieben hat, lächerlich zu machen. Aber dann dachte ich mir, ich sollte sicherstellen, dass ich zuerst Recht hatte.

public void dataViewActivated(DataViewEvent e) {
    if (this != null)
        // Do some work
}

Wird diese Zeile jemals als falsch bewertet?

Bryce Fischer
quelle
104
Immer zuerst lächerlich machen und später fragen. Es ist einfacher, sich zu entschuldigen, als eine einmalige Gelegenheit zu nutzen, um jemanden in Schwefel zu reißen.
Joel Etherton
5
+1 für den Begriff "Schwefelflut".
Marty Pitt
13
Weißt du was lustig ist? Dies kann in C # aufgrund eines Compiler-Fehlers passieren!
Blindy
1
@Blindy gibt +1 für das Codebeispiel.
Nathan Feger
6
gut in C # kann es null sein. In einigen Randfällen. Ich hatte den gleichen Impuls: den Trottel lächerlich machen, aber dann habe ich mich einfach beruhigt. Schauen Sie hier: stackoverflow.com/questions/2464097/…
Andrei Rînea

Antworten:

88

Nein, das kann es nicht. Wenn Sie verwenden this, befinden Sie sich in der Instanz und sind daher thisnicht null.

Die JLS sagt:

Bei Verwendung als primärer Ausdruck bezeichnet das Schlüsselwort this einen Wert, der auf das Objekt verweist, für das die Instanzmethode aufgerufen wurde (§15.12), oder auf das zu erstellende Objekt.

Wenn Sie eine Methode von einem Objekt aus aufgerufen haben, ist das Objekt vorhanden oder Sie hätten eine NullPointerExceptionvorherige (oder es ist eine statische Methode, die Sie jedoch nicht verwenden thiskönnen).


Ressourcen:

Colin Hebert
quelle
4
Ich weiß nicht viel über Java, aber in C ++ könnte die thiseiner Instanzmethode NULL sein. Ich bin also nicht ganz davon überzeugt, dass dies in Java ein ausreichender Grund ist.
Kennytm
4
Die Nullzeiger-Ausnahme in so etwas wird foo.bar()ausgelöst, wenn foofestgestellt wird, dass dies der Fall ist null. Es passiert zwar vor der Eingabe der Methode, aber die wahre Geschichte ist, dass es keine Methode gibt, mit der versucht werden kann, sie aufzurufen.
Claudiu
5
@KennyTM: Es ist ausreichend in Java. Wenn Sie das thisSchlüsselwort verwenden und es kompiliert, ist es nicht null, wenn Sie es beobachten. Aber wie andere sagen, verhindert dies nicht, dass eine NPE versucht, die Methode aufzurufen, z. B. Aber das liegt völlig außerhalb Ihrer Kontrolle als Methode, und eine Nullprüfung innerhalb der Methode wird nichts ändern.
Mark Peters
5
@Kenny: Nicht ohne undefiniertes Verhalten . Wenn Sie jedoch die Details Ihrer Implementierung kennen, können Sie diese verwenden.
4
Ich würde diese endgültige Antwort nicht abonnieren, selbst wenn sie völlig sinnvoll wäre. Ich habe Absturzberichte für eine Android-App, bei denen dies == null ist, wenn eine Instanzmethode aufgerufen wird, nachdem die Variable von einem anderen Thread auf null gesetzt wurde. Der eigentliche Aufruf wird auch dann ausgeführt, wenn die Variable null ist, und er stürzt ab, wenn versucht wird, ein Instanzmitglied zu lesen :)
Adrian Crețu
63

Es ist, als würde man sich fragen: "Bin ich am Leben?" thiskann niemals null sein

Prahler
quelle
44
Bin ich am Leben?! o Gott, ich weiß es nicht mehr
Claudiu
Du machst es so, als ob this != nulles selbstverständlich wäre. Dies ist beispielsweise in C ++ für eine nicht virtuelle Methode nicht der thisFall NULL.
Niki
1
@nikie In gewissem Sinne ist es selbstverständlich. Selbst in C ++ hat jedes Programm, in dem dies geschieht, ein undefiniertes Verhalten. Dies kann auch für virtuelle Funktionen in GCC geschehen: ideone.com/W7RmU .
Johannes Schaub - litb
8
@ John: Das bist du. Ein Teil der Folter ist, dass Sie es nicht bestätigen können.
@ JohannesSchaub-litb Es ist nicht wahr, dass das Verhalten eines C ++ - Programms mit einer Nullreferenz dafür undefiniert ist. Es ist definiert, solange Sie dies nicht dereferenzieren
Rune FS
9

Nein, niemals , das Schlüsselwort 'this' selbst repräsentiert die aktuell lebende Instanz (Objekt) dieser Klasse im Bereich dieser Klasse, mit der Sie auf alle Felder und Mitglieder (einschließlich Konstruktoren) und die sichtbaren Felder der übergeordneten Klasse zugreifen können.

Und, was noch interessanter ist, versuchen Sie es einzustellen:

this = null;

Denk darüber nach? Wie kann es möglich sein, wird es nicht so sein, als würde man den Ast abschneiden, auf dem man sitzt? Da das Schlüsselwort 'this' im Rahmen der Klasse verfügbar ist, sobald Sie dies sagen = null; Überall in der Klasse fordern Sie JVM auf, den diesem Objekt zugewiesenen Speicher während einer Operation freizugeben, die JVM einfach nicht zulassen kann, da sie nach Abschluss dieser Operation sicher zurückkehren muss.

Darüber hinaus führt ein Versuch this = null;zu einem Compilerfehler. Der Grund ist ziemlich einfach: Einem Schlüsselwort in Java (oder einer anderen Sprache) kann niemals ein Wert zugewiesen werden, dh ein Schlüsselwort kann niemals der linke Wert einer Zuweisungsoperation sein.

Andere Beispiele kann man nicht sagen:

true = new Boolean(true);
true = false;
sactiw
quelle
Gute Erklärung Freund.
Pankaj Sharma
@ PankajSharma Danke :)
sactiw
Ich fand das, weil ich sehen wollte, ob ich es benutzen könnte this = null. Meine Instanz war in Android, wo ich eine Ansicht entfernen und das Objekt, das die Ansicht behandelt, auf null setzen wollte. Dann wollte ich eine Methode verwenden, remove()die die eigentliche Ansicht entfernt und dann das Handler-Objekt unbrauchbar macht, also wollte ich es auf Null setzen.
Yokich
Ich bin mir nicht sicher, ob ich Ihren Behauptungen zustimme. (Zumindest der mittlere Teil; der lvalue-Teil ist in Ordnung ... obwohl ich mir ziemlich sicher bin, dass es tatsächlich defekte Sprachen gibt, mit denen Sie z. B. true = false zuweisen können (und sogar Sprachen, die ich nicht als defekt bezeichnen würde, können dies zulassen Reflexion oder ähnliche Tricks)). Wie auch immer, wenn ich ein Objekt foo habe und foo.this = null tun würde (ohne zu ignorieren, dass es illegal ist), würde foo immer noch auf den Speicher verweisen und die JVM würde es nicht durch Müll sammeln.
Foon
@Foon gut, die Frage spricht genau über die Java-Sprache, außerdem bin ich auf keine Sprache gestoßen, in der das Setzen von this = null erlaubt ist. Das heißt, wenn es solche Sprachen gibt, dann bezweifle ich sehr, dass "dies" in solchen Sprachen den gleichen Kontext und die gleiche Ideologie haben wird.
Sactiw
7

Wenn Sie mit -target 1.3oder früher kompilieren , kann ein äußeres this sein null. Oder zumindest früher ...

Tom Hawtin - Tackline
quelle
2
Ich denke, durch Reflexion können wir das Äußere auf Null setzen. könnte ein Aprilscherz über jemanden sein, als er eine Nullzeiger-Ausnahme beim Referenzieren bekamOuter.this.member
unwiderlegbar
3

Nein. Um eine Methode einer Instanz einer Klasse aufzurufen, muss die Instanz vorhanden sein. Die Instanz wird implizit als Parameter an die Methode übergeben, auf die verwiesen wird this. Wenn thiswurde nulldann gäbe es keine Instanz gewesen , ein Verfahren zu nennen.

Claudiu
quelle
3

Es reicht nicht aus, dass die Sprache dies erzwingt. Die VM muss dies erzwingen. Sofern die VM dies nicht erzwingt, können Sie einen Compiler schreiben, der die Nullprüfung nicht erzwingt, bevor Sie die in Java geschriebene Methode aufrufen. Zu den Opcodes für einen Aufruf einer Instanzmethode gehört das Laden dieser Referenz in den Stapel (siehe: http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787) . Das Ersetzen einer Nullreferenz würde tatsächlich dazu führen, dass der Test falsch ist

Rune FS
quelle
3

Wird in statischen Klassenmethoden thisnicht definiert, da thisInstanzen und keine Klassen zugeordnet sind. Ich glaube, es würde einen Compilerfehler geben, wenn versucht wird, das thisSchlüsselwort im statischen Kontext zu verwenden.

Burkestar
quelle
2

Ein Normal thiskann niemals nullin echtem Java-Code 1 enthalten sein , und in Ihrem Beispiel wird ein Normal verwendet this. Weitere Details finden Sie in den anderen Antworten.

Ein Qualifizierter this sollte niemals sein null, aber es ist möglich, dies zu brechen. Folgendes berücksichtigen:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

       public String toString() {
           return "outer is " + Outer.this;  // Qualified this!!
       }
   }
}

Wenn wir eine Instanz von erstellen möchten Inner, müssen wir Folgendes tun:

public static void main(String[] args) {
    Outer outer = new Outer();
    Inner inner = outer.new Inner();
    System.out.println(inner);

    outer = null;
    inner = outer.new Inner();  // FAIL ... throws an NPE
}

Die Ausgabe ist:

outer is Outer@2a139a55
Exception in thread "main" java.lang.NullPointerException
        at Outer.main(Outer.java:19)

Dies zeigt, dass unser Versuch, ein Innermit einem nullVerweis darauf zu erstellen, Outerfehlgeschlagen ist.

In der Tat, wenn Sie innerhalb des Umschlags "Pure Java" bleiben, können Sie dies nicht brechen.

Jede InnerInstanz hat jedoch ein verstecktes finalsynthetisches Feld (aufgerufen "this$0"), das den Verweis auf das enthält Outer. Wenn Sie wirklich knifflig sind, können Sie nulldem Feld "nicht reine" Mittel zuweisen .

  • Sie könnten es verwenden Unsafe, um es zu tun.
  • Sie können dazu nativen Code (z. B. JNI) verwenden.
  • Sie könnten es tun, indem Sie Reflexion verwenden.

In beiden Fällen führt das Endergebnis dazu, dass der Outer.thisAusdruck null2 ergibt .

Kurz gesagt, es ist möglich, dass ein Qualifizierter thisist null. Es ist jedoch unmöglich, wenn Ihr Programm den "Pure Java" -Regeln folgt.


1 - Ich rabattiere Tricks wie das "Schreiben" der Bytecodes von Hand und deren Weitergabe als echtes Java, das Optimieren von Bytecodes mit BCEL oder ähnlichem oder das Springen in nativen Code und das Durcheinander mit den gespeicherten Registern. IMO, das ist NICHT Java. Hypothetisch könnten solche Dinge auch als Ergebnis eines JVM-Fehlers passieren ... aber ich erinnere mich nicht an jeden Fehlerbericht.

2 - Tatsächlich sagt das JLS nicht, wie sich das Verhalten verhalten wird, und es könnte unter anderem von der Implementierung abhängen.

Stephen C.
quelle
1

Wenn Sie eine nullReferenzmethode aufrufen , NullPointerExceptionwird diese von Java VM ausgelöst. Dies erfolgt nach Spezifikation. Wenn Ihre Java-VM die Spezifikation strikt einhält, ist thisdies niemals der Fall null.

tia
quelle
1

Wenn die Methode statisch ist, gibt es keine this. Wenn die Methode virtuell ist, thiskann sie nicht null sein, da die Laufzeit zum Aufrufen der Methode mithilfe des thisZeigers auf die vtable verweisen muss . Wenn die Methode nicht virtuell ist, ist es möglich, dass sie thisnull ist.

C # und C ++ erlauben nicht virtuelle Methoden, aber in Java sind alle nicht statischen Methoden virtuell und werden daher thisniemals null sein.

John Henckel
quelle
0

tl; dr, "this" kann nur von einer nicht statischen Methode aufgerufen werden, und wir alle wissen, dass eine nicht statische Methode von einer Art Objekt aufgerufen wird, das nicht null sein kann.

Adam
quelle