Java: Class.this

112

Tengo un programa Java que se parece a esto.

public class LocalScreen {

   public void onMake() {
       aFuncCall(LocalScreen.this, oneString, twoString);
   }
}

¿Qué LocalScreen.thissignifica en aFuncCall?

Johnny Jazz
fuente

Respuestas:

169

LocalScreen.thisse refiere a thisla clase adjunta.

Este ejemplo debería explicarlo:

public class LocalScreen {
    
    public void method() {
        
        new Runnable() {
            public void run() {
                // Prints "An anonymous Runnable"
                System.out.println(this.toString());
                
                // Prints "A LocalScreen object"
                System.out.println(LocalScreen.this.toString());
                
                // Won't compile! 'this' is a Runnable!
                onMake(this);
                
                // Compiles! Refers to enclosing object
                onMake(LocalScreen.this);
            }
            
            public String toString() {
                return "An anonymous Runnable!";
            }
        }.run();
    }
    
    public String toString() { return "A LocalScreen object";  }
    
    public void onMake(LocalScreen ls) { /* ... */ }
    
    public static void main(String[] args) {
        new LocalScreen().method();
    }
}

Salida:

An anonymous Runnable!
A LocalScreen object

Esta publicación ha sido reescrita como un artículo aquí .

aioobe
fuente
¿Qué pasa si tienes algo como: public class a { private class a { public void run() { System.out.println(a.this.toString()); } } supongo que es el mismo asunto; el a.thisplazo run()hay que referirse a la envolvente a 's this. Estoy en lo cierto? (Así es como está el código minimizado en los .jararchivos de la aplicación OSX Kindle Previewer , solo estoy tratando de entender lo que estoy viendo).
Matt Mc
En Java, una clase interna puede no tener el mismo nombre que cualquiera de sus clases adjuntas (JLS 8.1), por lo que a.thisen su ejemplo no está definida. No sé si esta restricción es cierta para el código de bytes. Tal vez no.
aioobe
56

Significa la thisinstancia de la LocalScreenclase externa .

Escribir thissin un calificador devolverá la instancia de la clase interna en la que se encuentra la llamada.

SLaks
fuente
4
Todavía no lo entiendo del todo. ¿Cuál es la diferencia cuando lo codifico como "LocalScreen.this" en comparación con "esto"? Probé ambos y el compilador solo aceptó "LocalScreen.this". El primer parámetro de aFuncCall espera una claseParent que es una clase padre de "Somethig".
Johnny Jazz
1
También tengo curiosidad por esto. ¿Puede proporcionar algunos detalles sobre lo que esto significa? No veo ninguna clase interna definida en el código anterior; ¿Cada función de Java tiene una clase anónima asociada separada de la clase a la que pertenece?
poundifdef
4
@rascher: hay clases internas en uso; el OP no los incluyó en el fragmento de código. Esta sintaxis solo se admite en una clase interna no estática.
SLaks
Es bueno que haya proporcionado un enlace a la documentación oficial de Java.
Krzysztof Tomaszewski
14

El compilador toma el código y hace algo como esto con él:

public class LocalScreen 
{
    public void method() 
    {
        new LocalScreen$1(this).run;
    }

    public String toString() 
    {
        return "A LocalScreen object"; 
    }

    public void onMake(LocalScreen ls) { /* ... */ }

    public static void main(String[] args) 
    {
        new LocalScreen().method();
    }
}

class LocalScreen$1
     extends Runnable
{
    final LocalScreen $this;

    LocalScreen$1(LocalScreen $this)
    {
        this.$this = $this;
    }

    public void run() 
    {
        // Prints "An anonymous Runnable"
        System.out.println(this.toString());

        // Prints "A LocalScreen object"
        System.out.println($this.toString());

        // Won't compile! 'this' is a Runnable!
        //onMake(this);

        // Compiles! Refers to enclosing object
        $this.onMake($this);
    }

    public String toString() 
    {
        return "An anonymous Runnable!";
    }
}

Como puede ver, cuando el compilador toma una clase interna, la convierte en una clase externa (esta fue una decisión de diseño tomada hace MUCHO tiempo, por lo que las máquinas virtuales no necesitaban cambiarse para comprender las clases internas).

Cuando se crea una clase interna no estática, necesita una referencia al padre para que pueda llamar a métodos / variables de acceso de la clase externa.

El this dentro de lo que era la clase interna no es el tipo adecuado, necesita obtener acceso a la clase externa para obtener el tipo correcto para llamar al método onMake.

Tofu cerveza
fuente
no debería new LocalScreen$1().run;ser new LocalScreen$1(this).run;?
Diskutant
Esta es una respuesta subestimada a la pregunta. Cosas interesantes.
Pinkerton
12

Class.thispermite el acceso a la instancia de la clase externa. Vea el siguiente ejemplo.

public class A
{
  final String name;
  final B      b;
  A(String name) {
    this.name = name;
    this.b = new B(name + "-b");
  }

  class B
  {
    final String name;
    final C      c;
    B(String name) {
      this.name = name;
      this.c = new C(name + "-c");
    }

    class C
    {
      final String name;
      final D      d;
      C(String name) {
        this.name = name;
        this.d = new D(name + "-d");
      }

      class D
      {
        final String name;
        D(String name) {
          this.name = name;
        }

        void printMe()
        {
          System.out.println("D: " + D.this.name); // `this` of class D
          System.out.println("C: " + C.this.name); // `this` of class C
          System.out.println("B: " + B.this.name); // `this` of class B
          System.out.println("A: " + A.this.name); // `this` of class A
        }
      }
    }
  }
  static public void main(String ... args)
  {
    final A a = new A("a");
    a.b.c.d.printMe();
  }
}

Entonces obtendrás.

D: a-b-c-d
C: a-b-c
B: a-b
A: a
NawaMan
fuente
La única respuesta bien explicada hasta ahora ... De hecho es "Class.this permite el acceso a la instancia de la clase externa" y no cosas como "Class.this permite el acceso al this de la clase externa". Una clase no tiene "esto", solo las instancias tienen para hacer referencia a sí mismas ...
Żabojad
-2

Sé cuál es tu confusión. Me encuentro con el problema en este momento, debería tener una escena especial para distinguirlos.

class THIS {
  def andthen = {
    new THIS {
      println(THIS.this.## + ":inner-THIS.this.##")
      println(this.## + ":inner-this.##")
      new THIS {
        println(THIS.this.## + ":inner-inner-THIS.this.##")
        println(this.## + ":inner-this.##")
      }
    }
  }
  def getInfo = {
    println(THIS.this.## + ":THIS.this.##")
    println(this.## + ":this.##")
  }
}

Puede ver la diferencia entre THIS.thisy thisen la nueva operación ESTA por código hash (. ##)

prueba en la consola scala:

scala> val x = new THIS
x: THIS = THIS@5ab9b447

scala> val y = x.andthen
1522119751:inner-THIS.this.##
404586280:inner-this.##
1522119751:inner-inner-THIS.this.##
2027227708:inner-this.##
y: THIS = THIS$$anon$1@181d7f28

scala> x.getInfo
1522119751:THIS.this.##
1522119751:this.##

THIS.thissiempre apunte a la clase ESTE externa que se refiere mediante val x, pero thisestá más allá de una nueva operación anónima.

LoranceChen
fuente