"Questo" può mai essere nullo in Java?


109

Ho visto questa frase in un metodo di classe e la mia prima reazione è stata quella di mettere in ridicolo lo sviluppatore che l'ha scritta .. Ma poi, ho pensato che avrei dovuto assicurarmi prima di aver ragione.

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

Quella linea sarà mai considerata falsa?


104
Prima ridicolizza e poi domanda. È più facile scusarsi che riconquistare un'opportunità d'oro per abbattere qualcuno in una raffica di zolfo.
Joel Etherton,

5
+1 per il termine "raffica di zolfo".
Marty Pitt

13
Sai cosa è divertente? Questo può accadere in C # a causa di un bug del compilatore!
Blindy

1
@Blindy darà +1 per il codice di esempio.
Nathan Feger

6
bene in C # può essere nullo. In alcuni casi limite. Ho avuto lo stesso impulso: ridicolizzare il fesso ma poi mi sono calmato. Date un'occhiata qui: stackoverflow.com/questions/2464097/...
Andrei Rinea

Risposte:


88

No, non può. Se stai usando this, allora sei nell'istanza, quindi thisnon è nullo.

Il JLS dice:

Quando viene utilizzata come espressione primaria, la parola chiave this denota un valore che è un riferimento all'oggetto per il quale è stato invocato il metodo di istanza (§15.12) o all'oggetto in costruzione.

Se hai invocato un metodo da un oggetto, allora l'oggetto esiste o avresti un NullPointerExceptionprima (o è un metodo statico ma poi non puoi usarlo this).


Risorse:


4
Non conosco a fondo Java, ma in C ++ il thismetodo di un'istanza potrebbe essere NULL. Quindi non sono del tutto convinto che questa sia una ragione sufficiente in Java.
kennytm

4
l'eccezione del puntatore nullo in qualcosa di simile foo.bar()verrebbe lanciata quando foosi scopre che è null. accade prima di entrare nel metodo, ma la vera storia è che non esiste alcun metodo da tentare di chiamare.
Claudiu

5
@KennyTM: è sufficiente in Java. Se stai usando la thisparola chiave e si compila, non è nulla quando la osservi. Ma come dicono altri, ciò non impedisce un NPE quando si tenta di invocare il metodo, ad esempio, ma è completamente fuori dal tuo controllo come metodo e un controllo nullo all'interno del metodo non cambierà nulla.
Mark Peters

5
@ Kenny: Non senza un comportamento indefinito , anche se se conosci i dettagli della tua implementazione, potresti usarlo.

4
Non mi iscriverei a questa risposta definitiva, anche se ha perfettamente senso. Ho rapporti sugli arresti anomali per un'app Android in cui questo == null quando un metodo di istanza viene chiamato subito dopo che la variabile viene annullata da un altro thread. La chiamata effettiva viene eseguita anche se la variabile è nulla e si arresta in modo anomalo quando tenta di leggere un membro dell'istanza :)
Adrian Crețu

63

È come chiederti "Sono vivo?" thisnon può mai essere nullo


44
sono vivo ?! o dio non lo so più
Claudiu

Stai facendo sembrare che this != nullfosse ovvio. Non lo è - in C ++, ad esempio, thispotrebbe essere NULL, per un metodo non virtuale.
Niki

1
@nikie In un certo senso, è ovvio. Anche in C ++, qualsiasi programma in cui ciò accade ha un comportamento indefinito. Può accadere anche per funzioni virtuali su GCC: ideone.com/W7RmU .
Johannes Schaub - litb

8
@ John: lo sei. Parte della tortura è che non puoi confermarlo.

@ JohannesSchaub-litb Non è vero che il comportamento di un programma c ++ con un riferimento nullo per questo non è definito. È definito fintanto che non si dereferenzia questo
Rune FS

9

No mai , la parola chiave 'this' stessa rappresenta l'istanza (oggetto) attiva corrente di quella classe nell'ambito di quella classe, con la quale è possibile accedere a tutti i suoi campi e membri (inclusi i costruttori) ea quelli visibili della sua classe genitore.

E, cosa più interessante, prova a impostarlo:

this = null;

Pensaci? Come può essere possibile, non sarà come tagliare il ramo su cui sei seduto. Poiché la parola chiave "this" è disponibile nell'ambito della classe, non appena si dice this = null; ovunque all'interno della classe, in pratica stai chiedendo a JVM di liberare la memoria assegnata a quell'oggetto nel mezzo di un'operazione che JVM non può permettere che avvenga poiché deve tornare indietro in sicurezza dopo aver terminato quell'operazione.

Inoltre, il tentativo this = null;risulterà in un errore del compilatore. La ragione è piuttosto semplice, a una parola chiave in Java (o in qualsiasi linguaggio) non può mai essere assegnato un valore, ovvero una parola chiave non può mai essere il valore a sinistra di un'operazione di assegnazione.

Altri esempi, non puoi dire:

true = new Boolean(true);
true = false;

Buona spiegazione amico.
Pankaj Sharma

@PankajSharma Thanks :)
sactiw

Ho trovato questo perché volevo vedere se potevo usare this = null. La mia istanza era in Android dove volevo rimuovere una vista e impostare l'oggetto che gestisce la vista su null. Quindi volevo utilizzare un metodo remove()che rimuovesse la vista effettiva e quindi l'oggetto gestore sarebbe stato reso inutilizzabile, quindi volevo annullarlo.
Yokich

Non sono sicuro di essere d'accordo con le tue affermazioni. (almeno la parte centrale; la parte lvalue va bene ... anche se sono abbastanza sicuro che in realtà ci siano linguaggi non funzionanti che ti permettono di assegnare ad es. true = false (e anche linguaggi che non chiamerei interrotti potrebbero consentirlo con Riflessione o simili inganni)). Ad ogni modo, se ho un oggetto foo e dovessi fare (ignorando che è illegale) foo.this = null, foo punterebbe comunque alla memoria e quindi la JVM non lo raccoglierà in modo inutile.
Foon

@Foon bene la domanda parla precisamente del linguaggio Java, inoltre, non mi sono imbattuto in nessun linguaggio in cui è consentito impostare this = null. Cioè, se esistono tali lingue, dubito fortemente che "questo" in tali lingue avrà lo stesso contesto e ideologia.
sactiw

7

Se compili con -target 1.3o prima, allora potrebbe essere un file esterno . O almeno era solito ...thisnull


2
Immagino che attraverso la riflessione possiamo impostare il valore esterno this su null. potrebbe essere uno scherzo di Outer.this.member
pesce

3

No. Per chiamare un metodo di un'istanza di una classe, l'istanza deve esistere. L'istanza viene passata implicitamente come parametro al metodo, a cui fa riferimento this. Se thisfosse stato nullallora non ci sarebbe stata alcuna istanza di cui chiamare un metodo.


3

Non è sufficiente che la lingua lo imponga. La VM deve applicarlo. A meno che la VM non lo imponga, è possibile scrivere un compilatore che non imponga il controllo null prima di chiamare il metodo scritto in Java. I codici operativi per l'invocazione di un metodo di istanza includono il caricamento di this ref sullo stack, vedere: http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 . Sostituire questo con un riferimento nullo comporterebbe effettivamente che il test sia falso


3

Nei metodi delle classi statiche, thisnon è definito poiché thisè associato alle istanze e non alle classi. Credo che darebbe un errore del compilatore per tentare di utilizzare la thisparola chiave nel contesto statico.


2

Un normale thisnon può mai essere nullnel codice Java reale 1 e il tuo esempio utilizza un normale this. Vedi altre le altre risposte per maggiori dettagli.

Un qualificato non this dovrebbe mai esserlo null, ma è possibile rompere questo. Considera quanto segue:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

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

Quando vogliamo creare un'istanza di Inner, dobbiamo fare questo:

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
}

L'output è:

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

dimostrando che il nostro tentativo di creare un Innercon un nullriferimento al suo Outerè fallito.

In effetti, se rimani nella busta "Pure Java" non puoi romperla.

Tuttavia, ogni Inneristanza ha un finalcampo sintetico nascosto (chiamato "this$0") che contiene il riferimento a Outer. Se sei veramente astuto, puoi usare mezzi "non puri" da assegnare nullal campo.

  • Potresti usarlo Unsafeper farlo.
  • È possibile utilizzare codice nativo (ad esempio JNI) per farlo.
  • Puoi farlo usando la riflessione.

In ogni caso, il risultato finale è che l' Outer.thisespressione restituirà null2 .

Insomma, per un qualificato è possibilethis esserlo null. Ma è impossibile se il tuo programma segue le regole "Pure Java".


1 - Sconto trucchi come "scrivere" i bytecode a mano e spacciarli per Java reale, modificare i bytecode usando BCEL o simili, o saltare nel codice nativo e scherzare con i registri salvati. IMO, questo NON è Java. Ipoteticamente, cose del genere potrebbero anche accadere a seguito di un bug di JVM ... ma non ricordo tutte le segnalazioni di bug viste.

2 - In realtà, il JLS non dice quale sarà il comportamento e potrebbe dipendere dall'implementazione ... tra le altre cose.


1

Quando si richiama un metodo su nullriferimento, NullPointerExceptionverrà lanciato da Java VM. Questo è per specifica, quindi se la tua Java VM è strettamente conforme alla specifica, thisnon lo sarebbe mai null.


1

Se il metodo è statico, non ce n'è this. Se il metodo è virtuale, thisnon può essere nullo, perché per chiamare il metodo, il runtime dovrà fare riferimento alla tabella v utilizzando il thispuntatore. Se il metodo non è virtuale , sì, è possibile che thissia nullo.

C # e C ++ consentono metodi non virtuali, ma in Java tutti i metodi non statici sono virtuali, quindi thisnon saranno mai nulli.


0

tl; dr, "this" può essere chiamato solo da un metodo non statico e sappiamo tutti che un metodo non statico viene chiamato da una sorta di oggetto che non può essere nullo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.