¿Puede "esto" ser nulo en Java?


109

Vi esta línea en un método de clase y mi primera reacción fue ridiculizar al desarrollador que la escribió ... Pero luego, pensé que primero debería asegurarme de tener la razón.

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

¿Esa línea alguna vez se evaluará como falsa?


104
Siempre ridiculice primero y pregunte después. Es más fácil disculparse que recuperar una oportunidad de oro para derribar a alguien en una ráfaga de azufre.
Joel Etherton

5
+1 para el término "ráfaga de azufre".
Marty Pitt

13
¿Sabes qué es gracioso? ¡Esto puede suceder en C # debido a un error del compilador!
Blindy

1
@Blindy dará +1 para la muestra de código.
Nathan Feger

6
bueno, en C # puede ser nulo. En algunos casos extremos. Tuve el mismo impulso: ridiculizar al tonto, pero luego me calmé. Eche un vistazo aquí: stackoverflow.com/questions/2464097/…
Andrei Rînea

Respuestas:


88

No, no puede. Si está usando this, entonces está en la instancia, por thislo que no es nulo.

El JLS dice:

Cuando se usa como expresión primaria, la palabra clave this denota un valor que es una referencia al objeto para el cual se invocó el método de instancia (§15.12), o al objeto que se está construyendo.

Si invocaste un método desde un objeto, entonces el objeto existe o tendrías un NullPointerExceptionantes (o es un método estático pero luego no puedes usarlo this).


Recursos:


4
No sé mucho sobre Java, pero en C ++ el thismétodo de una instancia podría ser NULL. Así que no estoy del todo convencido de que esta sea una razón suficiente en Java.
kennytm

4
la excepción de puntero nulo en algo como foo.bar()se lanzaría cuando foose descubra que es null. sucede antes de ingresar al método, pero la verdadera historia es que no hay ningún método para intentar llamar.
Claudiu

5
@KennyTM: es suficiente en Java. Si está utilizando la thispalabra clave y se compila, no es nula cuando la observa. Pero como dicen otros, eso no evita una NPE al intentar invocar el método, por ejemplo, pero eso está completamente fuera de su control como método y una verificación nula dentro del método no va a cambiar nada.
Mark Peters

5
@Kenny: No sin un comportamiento indefinido , aunque si conoce los detalles de su implementación, puede usarlo.

4
No suscribiría esta respuesta definitiva, incluso si tiene mucho sentido. Tengo informes de fallas para una aplicación de Android donde esto == nulo cuando se llama a un método de instancia justo después de que la variable se anula desde otro hilo. La llamada real se realiza incluso si la variable es nula y se bloquea cuando intenta leer un miembro de instancia :)
Adrian Crețu

63

Es como preguntarse a sí mismo "¿Estoy vivo?" thisnunca puede ser nulo


44
estoy vivo? Dios mío, ya no sé
Claudiu

Lo estás haciendo sonar como si this != nullfuera evidente. No lo es; en C ++, por ejemplo, thisbien puede serlo NULLpara un método no virtual.
Niki

1
@nikie En cierto sentido, es evidente. Incluso en C ++, cualquier programa en el que esto ocurra tiene un comportamiento indefinido. También puede suceder para funciones virtuales en GCC: ideone.com/W7RmU .
Johannes Schaub - litb

8
@John: Lo eres. Parte de la tortura es que no puedes confirmarlo.

@ JohannesSchaub-litb No es cierto que el comportamiento de un programa en C ++ con una referencia nula para esto no esté definido. Está definido siempre y cuando no elimine la referencia a esto
Rune FS

9

No , nunca , la palabra clave 'this' en sí misma representa la instancia viva actual (objeto) de esa clase dentro del alcance de esa clase, con la que puede acceder a todos sus campos y miembros (incluidos los constructores) y los visibles de su clase padre.

Y, lo que es más interesante, intente configurarlo:

this = null;

¿Piénsalo? ¿Cómo puede ser posible? ¿No será como cortar la rama en la que estás sentado? Dado que la palabra clave 'esto' está disponible dentro del alcance de la clase, tan pronto como diga esto = nulo; en cualquier lugar dentro de la clase, básicamente le está pidiendo a JVM que libere la memoria asignada a ese objeto en medio de alguna operación que JVM simplemente no puede permitir que suceda, ya que necesita regresar de manera segura después de terminar esa operación.

Además, intentarlo this = null;resultará en un error del compilador. La razón es bastante simple, a una palabra clave en Java (o en cualquier idioma) nunca se le puede asignar un valor, es decir, una palabra clave nunca puede ser el valor izquierdo de una operación de asignación.

Otros ejemplos, no puedes decir:

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

Buena explicación amiga.
Pankaj Sharma

@PankajSharma Gracias :)
sactiw

Encontré esto porque quería ver si podía usarlo this = null. Mi instancia estaba en Android donde quería eliminar una vista y establecer el objeto que maneja la vista en nulo. Luego quería usar un método remove()que eliminara la vista real y luego el objeto controlador se volvería inútil, así que quería anularlo.
Yokich

No estoy seguro de estar de acuerdo con sus afirmaciones. (al menos la parte media; la parte lvalue está bien ... aunque estoy bastante seguro de que, de hecho, hay idiomas rotos que le permiten asignar, por ejemplo, verdadero = falso (e incluso los idiomas que no llamaría roto pueden permitirlo con Reflexión o engaños similares)). De todos modos, si tengo algún objeto foo y tuviera que hacer (ignorando que es ilegal) foo.this = null, foo aún apuntaría a la memoria y, por lo tanto, la JVM no la recolectaría.
Foon

@ Muy pronto, la pregunta habla precisamente sobre el lenguaje Java, además, no me he encontrado con ningún lenguaje en el que se permita la configuración de this = null. Es decir, si existen tales lenguajes, dudo mucho que 'esto' en tales lenguajes tenga el mismo contexto e ideología.
sábado

7

Si compila con -target 1.3o antes, entonces un externo this puede ser null. O al menos solía hacerlo ...


2
Supongo que a través de la reflexión podemos establecer el exterior esto en nulo. podría ser una broma de los tontos de abril para alguien cuando obtuvo una excepción de puntero nulo en la referenciaOuter.this.member
irrefutable

3

No. Para llamar a un método de una instancia de una clase, la instancia debe existir. La instancia se pasa implícitamente como un parámetro al método, referenciado por this. Si thislo nullhubiera, no habría habido ninguna instancia para llamar a un método.


3

No es suficiente que el lenguaje lo haga cumplir. La VM necesita hacerla cumplir. A menos que la VM lo aplique, puede escribir un compilador que no aplique la verificación nula antes de llamar al método escrito en Java. Los códigos de operación para la invocación de un método de instancia incluyen cargar esta referencia en la pila; consulte: http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 . Sustituir esto por una referencia nula daría como resultado que la prueba fuera falsa


3

En los métodos de clases estáticas, thisno se define, ya que thisestá asociado con instancias y no con clases. Creo que daría un error de compilador intentar usar una thispalabra clave en un contexto estático.


2

Un normal thisnunca puede estar nullen el código 1 de Java real , y su ejemplo usa un normal this. Vea otras las otras respuestas para más detalles.

Un calificado nunca this debería serlo null, pero es posible romper esto. Considera lo siguiente:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

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

Cuando queremos crear una instancia de Inner, necesitamos hacer esto:

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 salida es:

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

mostrando que nuestro intento de crear un Innercon una nullreferencia a su Outerha fallado.

De hecho, si te quedas dentro del sobre de "Java puro", no podrás romperlo.

Sin embargo, cada Innerinstancia tiene un finalcampo sintético oculto (llamado "this$0") que contiene la referencia al Outer. Si es realmente complicado, es posible utilizar medios "no puros" para asignar nullal campo.

  • Podrías usar Unsafepara hacerlo.
  • Puede usar código nativo (por ejemplo, JNI) para hacerlo.
  • Podrías hacerlo usando la reflexión.

De cualquier manera que lo haga, el resultado final es que la Outer.thisexpresión se evaluará como null2 .

En resumen, es posible que un calificado thissea null. Pero es imposible si su programa sigue las reglas de "Java puro".


1 - Descarto trucos como "escribir" los códigos de bytes a mano y pasarlos como Java real, ajustar los códigos de bytes usando BCEL o similar, o saltar al código nativo y jugar con los registros guardados. En mi opinión, eso NO es Java. Hipotéticamente, estas cosas también podrían suceder como resultado de un error de JVM ... pero no recuerdo todos los informes de errores que vi.

2 - En realidad, el JLS no dice cuál será el comportamiento, y podría depender de la implementación ... entre otras cosas.


1

Cuando invoca un método en nullreferencia, se NullPointerExceptionlanzará desde Java VM. Esto es por especificación, por lo que si su máquina virtual Java cumple estrictamente con la especificación, thisnunca lo sería null.


1

Si el método es estático, entonces no hay ninguno this. Si el método es virtual, entonces thisno puede ser nulo, porque para llamar al método, el tiempo de ejecución necesitará hacer referencia a la vtable usando el thispuntero. Si el método no es virtual , entonces sí, es posible que thissea ​​nulo.

C # y C ++ permiten métodos no virtuales, pero en Java todos los métodos no estáticos son virtuales, por thislo que nunca serán nulos.


0

tl; dr, "this" sólo se puede llamar desde un método no estático y todos sabemos que se llama a un método no estático desde algún tipo de objeto que no puede ser nulo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.