«This» peut-il jamais être nul en Java?

109

J'ai vu cette ligne dans une méthode de classe et ma première réaction a été de ridiculiser le développeur qui l'a écrite. Mais ensuite, j'ai pensé que je devais m'assurer que j'avais raison en premier.

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

Cette ligne sera-t-elle jamais évaluée comme fausse?

Bryce Fischer
la source
104
Ridicule toujours d'abord et question plus tard. Il est plus facile de s'excuser que de récupérer une occasion en or de démolir quelqu'un dans une rafale de soufre.
Joel Etherton
5
+1 pour le terme "rafale de soufre".
Marty Pitt
13
Tu sais ce qui est drôle? Cela peut arriver en C # en raison d'un bogue du compilateur!
Blindy
1
@Blindy donnera +1 pour un exemple de code.
Nathan Feger
6
bien en C #, il peut être nul. Dans certains cas extrêmes. J'ai eu la même impulsion: ridiculiser la ventouse mais ensuite je me suis juste calmée. Jetez un œil ici: stackoverflow.com/questions/2464097/…
Andrei Rînea

Réponses:

88

Non, ça ne peut pas. Si vous utilisez this, vous êtes dans l'instance et thisn'est donc pas nul.

Le JLS dit:

Lorsqu'il est utilisé comme expression principale, le mot-clé this désigne une valeur qui est une référence à l'objet pour lequel la méthode d'instance a été appelée (§15.12), ou à l'objet en cours de construction.

Si vous avez appelé une méthode à partir d'un objet, alors l'objet existe ou vous auriez un NullPointerExceptionavant (ou c'est une méthode statique mais alors, vous ne pouvez pas l'utiliser this).


Ressources :

Colin Hebert
la source
4
Je ne connais pas profondément Java, mais en C ++, la thisméthode d'une instance pourrait être NULL. Je ne suis donc pas tout à fait convaincu que ce soit une raison suffisante en Java.
kennytm
4
l'exception de pointeur nul dans quelque chose comme foo.bar()serait levée quand fooest découverte null. cela arrive avant d'entrer dans la méthode, mais la vraie histoire est qu'il n'y a pas de méthode à tenter d'appeler.
Claudiu
5
@KennyTM: c'est suffisant en Java. Si vous utilisez le thismot - clé et qu'il se compile, il n'est pas nul lorsque vous l'observez. Mais comme d'autres le disent, cela n'empêche pas un NPE d'essayer d'appeler la méthode, par exemple, mais c'est complètement hors de votre contrôle en tant que méthode et une vérification nulle dans la méthode ne changera rien.
Mark Peters
5
@Kenny: Pas sans comportement indéfini , mais si vous connaissez les détails de votre implémentation, vous pouvez l'utiliser.
4
Je ne souscrirais pas à cette réponse définitive, même si elle a tout son sens. J'ai des rapports d'erreur pour une application Android où ceci == null lorsqu'une méthode d'instance est appelée juste après que la variable est en cours de nullité à partir d'un autre thread. L'appel réel se déroule même si la variable est nulle, et il se bloque lorsqu'il tente de lire un membre d'instance :)
Adrian Crețu
63

C'est comme vous demander "Suis-je vivant?" thisne peut jamais être nul

bragboy
la source
44
suis- je vivant?! o god je ne sais plus
Claudiu
Vous donnez l'impression que cela va de this != nullsoi. Ce n'est pas le cas - en C ++, par exemple, thispourrait bien l'être NULL, pour une méthode non virtuelle.
Niki
1
@nikie Dans un certain sens, cela va de soi. Même en C ++, tout programme où cela se produit a un comportement indéfini. Cela peut également arriver pour les fonctions virtuelles sur GCC: ideone.com/W7RmU .
Johannes Schaub - litb le
8
@John: Vous l'êtes. Une partie de la torture est que vous ne pouvez pas le confirmer.
@ JohannesSchaub-litb Ce n'est pas vrai que le comportement d'un programme C ++ avec une référence nulle pour cela ne soit pas défini. Il est défini tant que vous ne le déréférencez pas
Rune FS
9

Non jamais , le mot-clé 'this' lui-même représente l'instance (objet) active actuelle de cette classe dans la portée de cette classe, avec laquelle vous pouvez accéder à tous ses champs et membres (y compris les constructeurs) et à ceux visibles de sa classe parente.

Et, plus intéressant encore, essayez de le configurer:

this = null;

Pensez-y? Comment est-ce possible, n'est-ce pas comme couper la branche sur laquelle vous êtes assis? Puisque le mot-clé «ceci» est disponible dans la portée de la classe donc dès que vous dites this = null; n'importe où dans la classe, vous demandez en gros à JVM de libérer la mémoire affectée à cet objet au milieu d'une opération que JVM ne peut tout simplement pas permettre car elle doit revenir en toute sécurité après avoir terminé cette opération.

De plus, toute tentative this = null;entraînera une erreur du compilateur. La raison est assez simple, un mot-clé en Java (ou dans n'importe quel langage) ne peut jamais recevoir de valeur, c'est-à-dire qu'un mot-clé ne peut jamais être la valeur de gauche d'une opération d'affectation.

Autres exemples, vous ne pouvez pas dire:

true = new Boolean(true);
true = false;
sactiw
la source
Bon ami d'explication.
Pankaj Sharma
@PankajSharma Thanks :)
sactiw
J'ai trouvé cela parce que je voulais voir si je pouvais l'utiliser this = null. Mon instance était dans Android où je voulais supprimer une vue et définir l'objet gérant la vue sur null. Ensuite, j'ai voulu utiliser une méthode remove()qui supprimerait la vue réelle et ensuite l'objet gestionnaire serait rendu inutile, donc j'ai voulu l'annuler.
Yokich le
Je ne suis pas sûr d’accepter vos affirmations. (au moins la partie centrale; la partie lvalue est bien ... même si je suis à peu près sûr qu'il existe en fait des langues cassées qui vous permettent d'affecter par exemple true = false (et même les langues que je n'appellerais pas cassées peuvent le permettre avec Réflexion ou supercherie similaire)). Quoi qu'il en soit, si j'ai un objet foo et que je devais faire (en ignorant que c'est illégal) foo.this = null, foo pointerait toujours vers la mémoire et ainsi la JVM ne la ramasserait pas.
Foon
@Bientôt la question parle précisément du langage Java, de plus, je n'ai rencontré aucun langage où la définition de this = null est autorisée. Autrement dit, s'il existe de telles langues, je doute fortement que «ceci» dans de telles langues ait le même contexte et la même idéologie.
sactiw
7

Si vous compilez avec -target 1.3ou une version antérieure, un externe this peut être null. Ou du moins, c'était le cas ...

Tom Hawtin - Tackline
la source
2
Je suppose que grâce à la réflexion, nous pouvons définir le paramètre externe this sur null. pourrait être une blague de Outer.this.member
poisson d'
3

Non. Pour appeler une méthode d'une instance d'une classe, l'instance doit exister. L'instance est implicitement transmise en tant que paramètre à la méthode, référencée par this. Si thisc'était le cas , nullil n'y aurait pas eu d'instance pour appeler une méthode.

Claudiu
la source
3

Il ne suffit pas que la langue l'applique. La VM doit l'appliquer. À moins que la machine virtuelle ne l'applique, vous pouvez écrire un compilateur qui n'applique pas la vérification de null avant d'appeler la méthode écrite en Java. Les opcodes pour un appel de méthode d'instance incluent le chargement de cette référence dans la pile, voir: http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 . Substituer ceci à une référence nulle entraînerait en effet un test faux

Rune FS
la source
3

Dans les méthodes de classe statique, thisn'est pas défini car thisest associé à des instances et non à des classes. Je crois que cela donnerait une erreur du compilateur pour essayer d'utiliser un thismot-clé dans un contexte statique.

Burkestar
la source
2

Une normale thisne peut jamais être nulldans le vrai code Java 1 , et votre exemple utilise une normale this. Voir les autres réponses pour plus de détails.

Un qualifié ne this devrait jamais l'être null, mais il est possible de briser cela. Considérer ce qui suit:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

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

Lorsque nous voulons créer une instance de Inner, nous devons le faire:

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
}

La sortie est:

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

montrant que notre tentative de créer un Inneravec une nullréférence à son Outera échoué.

En fait, si vous vous en tenez à l'enveloppe "Pure Java", vous ne pouvez pas le casser.

Cependant, chaque Innerinstance a un finalchamp synthétique masqué (appelé "this$0") qui contient la référence au Outer. Si vous êtes vraiment délicat, il est possible d'utiliser des moyens "non purs" pour attribuer nullau champ.

  • Vous pourriez utiliser Unsafepour le faire.
  • Vous pouvez utiliser du code natif (par exemple JNI) pour le faire.
  • Vous pouvez le faire en utilisant la réflexion.

Quoi qu'il en soit, le résultat final est que l' Outer.thisexpression sera évaluée à null2 .

Bref, il est possible qu'un qualifié thissoit null. Mais c'est impossible si votre programme suit les règles "Pure Java".


1 - J'écarte des astuces telles que "écrire" les bytecodes à la main et les faire passer pour de vrais Java, peaufiner les bytecodes en utilisant BCEL ou similaire, ou sauter dans le code natif et faire des emplettes avec les registres sauvegardés. IMO, ce n'est PAS Java. Hypothétiquement, de telles choses peuvent également se produire à la suite d'un bogue JVM ... mais je ne me souviens pas de tous les rapports de bogues.

2 - En fait, le JLS ne dit pas quel sera le comportement, et cela pourrait dépendre de l'implémentation ... entre autres.

Stephen C
la source
1

Lorsque vous appelez une méthode sur nullréférence, le NullPointerExceptionsera renvoyé à partir de Java VM. C'est par spécification, donc si votre machine virtuelle Java est strictement conforme à la spécification, thiscela ne le sera jamais null.

tia
la source
1

Si la méthode est statique, il n'y en a pas this. Si la méthode est virtuelle, elle thisne peut pas être nulle, car pour appeler la méthode, le moteur d'exécution devra référencer la vtable à l'aide du thispointeur. Si la méthode n'est pas virtuelle alors, oui, il est possible qu'elle thissoit nulle.

C # et C ++ autorisent les méthodes non virtuelles, mais en Java, toutes les méthodes non statiques sont virtuelles et thisne seront donc jamais nulles.

John Henckel
la source
0

tl; dr, "this" ne peut être appelé qu'à partir d'une méthode non statique et nous savons tous qu'une méthode non statique est appelée à partir d'une sorte d'objet qui ne peut pas être null.

Adam
la source