W3docs

Palavra-chave this em Java

Referencie o objeto atual em Java com a palavra-chave this — desambiguando campos, encadeando construtores e chamadas de métodos.

Dentro de um método de instância ou construtor, this refere-se ao objeto no qual o método está sendo chamado. É um parâmetro implícito que a JVM passa para você. Na maioria das vezes você não precisa mencioná-lo — nomes simples já são resolvidos através de this — mas algumas situações específicas forçam você a escrevê-lo explicitamente. Este capítulo cobre essas situações.

O que é this

Quando você chama dog.bark(), a JVM passa dog secretamente como o primeiro argumento. Dentro de bark, esse argumento é chamado this. Portanto:

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

Você pode omitir this. e escrever apenas name — Java procura o identificador simples no escopo atual, não encontra nenhuma variável local com esse nome, então percorre até os campos de instância, encontra name e o resolve como this.name. As duas formas compilam para o mesmo bytecode.

Uso 1 — desambiguando um parâmetro de um campo

A razão mais comum para escrever this. explicitamente é quando um parâmetro ou variável local tem o mesmo nome que um campo:

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

Sem this., x = x; atribuiria o parâmetro a si mesmo e deixaria o campo em 0. O compilador não avisa — é uma instrução válida — então esse é um bug silencioso bastante comum.

Você poderia renomear os parâmetros (int newX, int newY) para evitar a colisão, mas fazer os nomes dos parâmetros coincidirem com os nomes dos campos é de longe a convenção mais legível, por isso o padrão this. está em todo lugar no código Java.

Uso 2 — passando o objeto atual

Às vezes um método precisa passar this para outro método ou construtor como argumento:

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

Não há outra forma de se referir ao objeto atual como um valor, portanto this é obrigatório aqui.

Uma variante comum é um builder fluente onde cada setter retorna this para que as chamadas possam ser encadeadas:

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 chamar outro construtor

Dentro de um construtor, this(args) chama outro construtor da mesma classe — consulte construtores. Deve ser a primeira instrução, e um construtor só pode delegar para um outro:

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

Isso é diferente do qualificador this.this(...) com argumentos é a forma de chamada de construtor; this.foo (ou apenas this sozinho) é a forma de referência.

Quando this é ilegal

this só existe em contextos de instância. Em um método ou inicializador static, não existe objeto atual, portanto escrever this é um erro de compilação:

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

main é static, por isso você não pode se referir a campos de instância diretamente dentro dele — você deve primeiro criar um objeto.

this vs acesso implícito a campo

Se não houver colisão de nomes, this. é puramente estilístico:

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

Ambos funcionam. A forma implícita é mais comum; algumas bases de código usam this. em todo lugar para consistência ou para tornar o receptor visível num relance. Qualquer uma está correta — escolha uma e aplique-a dentro de um arquivo.

Classes internas e o this externo

Uma classe interna não estática tem uma referência implícita à sua instância envolvente. Dentro da classe interna, this refere-se ao objeto interno; a instância externa é 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
    }
  }
}

Isso surge apenas em cenários de classe aninhada, abordados em classes aninhadas e nos capítulos seguintes.

Lambdas vs classes anônimas

Um lambda não introduz um novo this. Dentro de um lambda, this é a instância envolvente — o mesmo objeto no qual o método circundante é executado. Uma classe anônima, por outro lado, é seu próprio objeto, portanto dentro dela this refere-se a essa instância 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
  }
}

Essa é uma das poucas diferenças comportamentais entre as duas formas: um lambda captura this de seu entorno, enquanto uma classe anônima o oculta.

Um exemplo prático

java— editable, runs on the server

O que vem a seguir

this é uma das duas referências implícitas em Java; a outra, super, surge quando você tem herança. Antes disso, porém, precisamos falar sobre visibilidade — quem pode ver e chamar os métodos e campos da sua classe. Continue para modificadores de acesso.

Prática

Prática
Um construtor é escrito como public Point(int x, int y) { x = x; y = y; }. Qual é o bug?
Um construtor é escrito como public Point(int x, int y) { x = x; y = y; }. Qual é o bug?
Was this page helpful?