java class this forward-reference

java - ¿Por qué debo usar la palabra clave "this" para referencias futuras?



class forward-reference (5)

Consulte la especificación del lenguaje Java: https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.2.3

Esta es la razón, OMI: The usage is via a simple name.

Entonces, en este caso, debe especificar el nombre con this .

Cuando uso la palabra clave this para acceder a una variable no estática en una clase, Java no da ningún error. Pero cuando no lo uso, Java da un error. ¿Por qué debo usar this ?

Sé cuándo debería usar this normalmente, pero este ejemplo es muy diferente de los usos normales.

Ejemplo:

class Foo { // int a = b; // gives error. why ? int a = this.b; // no error. why ? int b; int c = b; int var1 = this.var2; // very interesting int var2 = this.var1; // very interesting }


Has presentado 3 casos:

  1. int a = b; int b;
    Esto da error porque el compilador buscará b en la memoria y no estará allí. pero cuando utiliza this palabra clave, especifica explícitamente que b está definida en el alcance de la clase, se buscarán todas las referencias de clase y finalmente la encontrará.
  2. El segundo escenario es bastante simple y, como describí, b se define en el alcance antes de c y no será un problema mientras se busca b en la memoria.
  3. int var1 = this.var2;
    int var2 = this.var1;
    En este caso no hay error porque en cada caso la variable se define en la clase y la asignación usa this que buscará la variable asignada en la clase, no solo el contexto al que va seguida.

La descripción completa se encuentra en la sección 8.3.3 de la Especificación del lenguaje Java: " Reenviar referencias durante la inicialización de campo "

Una referencia directa (que se refiere a una variable que aún no se ha declarado en ese punto) es solo un error si se cumple lo siguiente:

  • La declaración de una variable de instancia en una clase o interfaz C aparece textualmente después de un uso de la variable de instancia;

  • El uso es un nombre simple en un inicializador de variable de instancia de C o un inicializador de instancia de C;

  • El uso no está en el lado izquierdo de una tarea;

  • C es la clase o interfaz más interna que encierra el uso.

Vea el texto en negrita: "el uso es un nombre simple". Un nombre simple es un nombre de variable sin calificación adicional. En su código, b es un nombre simple, pero this.b no lo es.

¿Pero por qué?

La razón es que, como dice el texto cursivo en el ejemplo en JLS:

"Las restricciones anteriores están diseñadas para detectar, en tiempo de compilación, inicializaciones circulares o malformadas".

En otras palabras, permiten esto. this.b porque piensan que una referencia calificada hace que sea más probable que hayas pensado cuidadosamente sobre lo que estás haciendo, pero simplemente usando b probablemente significa que cometiste un error.

Esa es la razón de ser de los diseñadores del lenguaje Java. Si eso es cierto en la práctica, hasta donde sé, nunca se ha investigado.

Orden de inicialización

Para ampliar lo anterior, en referencia al comentario de Dukeling sobre la pregunta, utilizando una referencia calificada this.b probablemente no le dará los resultados que desea.

Estoy restringiendo esta discusión a variables de instancia porque el OP solo se refirió a ellas. El orden en que se asignan las variables de instancia se describe en JLS 12.5 Creación de nuevas instancias de clase . Debe tener en cuenta que los constructores de superclase se invocan primero y que el código de inicialización (asignaciones y bloques de inicialización) se ejecuta en orden de texto.

Así dado

int a = this.b; int b = 2;

terminarás con a ser cero (el valor de b en el momento en que se ejecutó el inicializador de a) b siendo 2.

Incluso se pueden lograr resultados más extraños si el constructor de la superclase invoca un método que se anula en la subclase y ese método asigna un valor a b .

Por lo tanto, en general, es una buena idea creerle al compilador y reordenar sus campos o solucionar el problema subyacente en caso de inicializaciones circulares.

Si necesita usar this.b para evitar el error del compilador, entonces probablemente esté escribiendo un código que será muy difícil de mantener por la persona que lo sigue.


Las variables se declaran primero y luego se asignan. Esa clase es la misma que esta:

class Foo { int a; int b; int c = b; int var1; int var2; public Foo() { a = b; var1 = var2; var2 = var1; } }

La razón por la que no puedes hacer int a = b; es porque b todavía no está definido en el momento en que se crea el objeto, pero el objeto en sí (es decir, this ) existe con todas sus variables miembro.

Aquí hay una descripción para cada uno:

int a = b; // Error: b has not been defined yet int a = this.b; // No error: ''this'' has been defined (''this'' is always defined in a class) int b; int c = b; // No error: b has been defined on the line before


Para cualquier clase en Java, this es una variable de referencia predeterminada (cuando no se proporciona una referencia específica) que el usuario puede proporcionar o que el compilador proporcionará dentro de un bloque no estático. Por ejemplo

public class ThisKeywordForwardReference { public ThisKeywordForwardReference() { super(); System.out.println(b); } int a; int b; public ThisKeywordForwardReference(int a, int b) { super(); this.a = a; this.b = b; } }

Dijiste que int a = b; // gives error. why ? int a = b; // gives error. why ? da un error en tiempo de compilación porque b se declara después de a que es una Illegal Forward Reference en Java y se considera un error en tiempo de compilación

Pero en el caso de los methods Forward Reference vuelve legal

int a = test(); int b; int test() { return 0; }

Pero en mi código, el constructor con el argumento se declara antes de a & b , pero no da ningún error en tiempo de compilación, porque System.out.println(b); será reemplazado por System.out.println(this.b); por el compilador

La palabra clave this simplemente significa referencia de clase actual o la referencia en la que se accede al método, el constructor o el atributo.

A a1 = new A(); // Here this is nothing but a1 a1.test(); // Here this is again a1

Cuando decimos a = this.b; especifica que b es un atributo de clase actual, pero cuando decimos a = b; Como no está dentro de un bloque no estático, no estará presente y buscará un atributo declarado previamente que no está presente.