W3docs

La palabra clave this en Java

Referencia al objeto actual en Java con this: desambiguación de campos, encadenamiento de constructores y llamadas a métodos.

Dentro de un método de instancia o constructor, this hace referencia a el objeto sobre el que se está llamando al método. Es un parámetro implícito que la JVM te pasa automáticamente. La mayor parte del tiempo no necesitas mencionarlo — los nombres simples ya se resuelven a través de this — pero hay un puñado de situaciones que te obligan a escribirlo explícitamente. Este capítulo las cubre.

Qué es this

Cuando llamas a dog.bark(), la JVM pasa dog en secreto como primer argumento. Dentro de bark, ese argumento se llama this. Así:

public class Dog {
  String name;
  void bark() {
    System.out.println(this.name + " says woof");   // this == dog
  }
}

Dog rex = new Dog();
rex.name = "Rex";
rex.bark();    // inside, this == rex

Puedes omitir this. y escribir simplemente name — Java busca el identificador simple en el ámbito actual, no encuentra ninguna variable local con ese nombre, luego sube a los campos de instancia, encuentra name y lo resuelve como this.name. Las dos formas compilan al mismo bytecode.

Uso 1 — desambiguar un parámetro de un campo

La razón más común para escribir this. explícitamente es cuando un parámetro o variable local tiene el mismo nombre que un campo:

public class Point {
  int x, y;
  public Point(int x, int y) {
    this.x = x;        // field = parameter
    this.y = y;
  }
}

Sin this., x = x; asignaría el parámetro a sí mismo y dejaría el campo en 0. El compilador no advierte — es una instrucción válida — por lo que este es un error silencioso muy popular.

Podrías renombrar los parámetros (int newX, int newY) para evitar la colisión, pero hacer que los nombres de los parámetros coincidan con los nombres de los campos es con diferencia la convención más legible y, por eso, el patrón this. está en todas partes en el código Java.

Uso 2 — pasar el objeto actual

A veces un método necesita pasar this a otro método o constructor como argumento:

public class Order {
  List<Item> items = new ArrayList<>();
  void register(Tracker t) {
    t.watch(this);          // pass myself to the tracker
  }
}

No hay otra forma de referirse al objeto actual como un valor, por lo que this es obligatorio aquí.

Una variante común es un builder fluido donde cada setter devuelve this para que las llamadas puedan encadenarse:

public class Url {
  String scheme, host, path;
  public Url scheme(String s) { this.scheme = s; return this; }
  public Url host(String h)   { this.host   = h; return this; }
  public Url path(String p)   { this.path   = p; return this; }
}

Url u = new Url().scheme("https").host("w3docs.com").path("/learn-java");

Uso 3 — this(...) para llamar a otro constructor

Dentro de un constructor, this(args) llama a otro constructor de la misma clase — consulta constructores. Debe ser la primera instrucción y un constructor solo puede delegar en otro:

public Rectangle()                  { this(1, 1); }
public Rectangle(double side)       { this(side, side); }
public Rectangle(double w, double h){ this.width = w; this.height = h; }

Esto es diferente del calificador this.this(...) con argumentos es la forma de llamada al constructor; this.foo (o simplemente this solo) es la forma de referencia.

Cuándo this es ilegal

this solo existe en contextos de instancia. Desde un método static o inicializador, no hay objeto actual, por lo que escribir this es un error de compilación:

public class Counter {
  static int total;
  static void reset() {
    this.total = 0;     // ERROR: cannot use this in a static context
  }
}

main es static, razón por la cual no puedes referirte directamente a campos de instancia dentro de él — primero debes crear un objeto.

this frente al acceso implícito a campos

Si no hay colisión de nombres, this. es puramente estilístico:

double area()      { return Math.PI * radius * radius; }
double areaThisly(){ return Math.PI * this.radius * this.radius; }

Ambas funcionan. La forma implícita es más común; algunas bases de código usan this. en todas partes por consistencia o para que el receptor sea visible de un vistazo. Cualquiera está bien — elige uno y aplícalo dentro de un archivo.

Clases internas y el this externo

Una clase interna no estática tiene una referencia implícita a su instancia envolvente. Desde la clase interna, this hace referencia al objeto interno; la instancia externa es Outer.this:

public class Outer {
  int x = 1;
  class Inner {
    int x = 2;
    void demo() {
      System.out.println(this.x);          // 2  — Inner's x
      System.out.println(Outer.this.x);    // 1  — Outer's x
    }
  }
}

Esto aparece solo en escenarios de clases anidadas, cubiertos en clases anidadas y los capítulos siguientes.

Lambdas frente a clases anónimas

Una lambda no introduce un nuevo this. Dentro de una lambda, this es la instancia envolvente — el mismo objeto sobre el que se ejecuta el método circundante. Una clase anónima, en cambio, es su propio objeto, por lo que dentro de ella this hace referencia a esa instancia anónima:

public class Demo {
  String label = "outer";
  void run() {
    Runnable lambda = () -> System.out.println(this.label);   // "outer"
    Runnable anon = new Runnable() {
      String label = "inner";
      public void run() { System.out.println(this.label); }   // "inner"
    };
    lambda.run();   // prints outer
    anon.run();     // prints inner
  }
}

Esta es una de las pocas diferencias de comportamiento entre las dos formas: una lambda captura this de su entorno, mientras que una clase anónima lo oculta.

Un ejemplo completo

java— editable, runs on the server

Qué sigue

this es una de las dos referencias implícitas en Java; la otra, super, aparece una vez que tienes herencia. Antes de eso, sin embargo, necesitamos hablar de visibilidad — quién puede ver y llamar a los métodos y campos de tu clase. Continúa con modificadores de acceso.

Práctica

Práctica
Un constructor está escrito como public Point(int x, int y) { x = x; y = y; }. ¿Cuál es el error?
Un constructor está escrito como public Point(int x, int y) { x = x; y = y; }. ¿Cuál es el error?
Was this page helpful?