Java: Class.this


112

Ho un programma Java simile a questo.

public class LocalScreen {

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

Cosa LocalScreen.thissignifica in aFuncCall?

Risposte:


169

LocalScreen.thissi riferisce alla thisclasse allegata.

Questo esempio dovrebbe spiegarlo:

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();
    }
}

Produzione:

An anonymous Runnable!
A LocalScreen object

Questo post è stato riscritto come articolo qui .


E se avessi qualcosa del tipo: public class a { private class a { public void run() { System.out.println(a.this.toString()); } } suppongo che sia la stessa cosa; il a.thisraggio run()deve fare riferimento alla racchiude a s' this. Ho ragione? (Ecco come si trova il codice minimizzato nei file dell'app OSX Kindle Previewer .jar, sto solo cercando di capire cosa sto guardando.)
Matt Mc

In Java una classe interna potrebbe non avere lo stesso nome di nessuna delle sue classi che la racchiudono (JLS 8.1), quindi a.thisnel tuo esempio non è definita. Non so se questo vincolo sia vero per bytecode. Forse no.
aioobe

56

Significa l' thisistanza della LocalScreenclasse esterna .

La scrittura thissenza un qualificatore restituirà l'istanza della classe interna in cui si trova la chiamata.


4
Ancora non capisco bene. Qual è la differenza quando lo codice come "LocalScreen.this" rispetto a "this"? Ho provato entrambi e il compilatore ha accettato solo "LocalScreen.this". Il primo parametro di aFuncCall prevede una classe Parent che è una classe genitore di "Somethig".
Johnny Jazz

1
Sono curioso anche di questo. Puoi fornire alcuni dettagli su cosa significa? Non vedo nessuna classe interna definita nel codice sopra; ogni funzione Java ha una classe anonima associata separata dalla classe di cui è membro?
poundifdef

4
@rascher: ci sono classi interne in uso; l'OP non li ha inclusi nello snippet di codice. Questa sintassi è supportata solo in una classe interna non statica.
SLaks

È bello che tu abbia fornito un collegamento alla documentazione ufficiale di Java.
Krzysztof Tomaszewski

14

Il compilatore prende il codice e fa qualcosa del genere con esso:

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!";
    }
}

Come puoi vedere, quando il compilatore prende una classe interna, la converte in una classe esterna (questa era una decisione di progettazione presa molto tempo fa in modo che le VM non dovevano essere modificate per comprendere le classi interne).

Quando viene creata una classe interna non statica, è necessario un riferimento al genitore in modo che possa chiamare metodi / variabili di accesso della classe esterna.

Questo all'interno di quella che era la classe interna non è del tipo corretto, è necessario accedere alla classe esterna per ottenere il tipo giusto per chiamare il metodo onMake.


non dovrebbe new LocalScreen$1().run;essere new LocalScreen$1(this).run;?
Diskutant

Questa è una risposta sottovalutata alla domanda. Roba interessante.
Pinkerton

12

Class.thisconsente l'accesso all'istanza della classe esterna. Vedi il seguente esempio.

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();
  }
}

Allora otterrai.

D: a-b-c-d
C: a-b-c
B: a-b
A: a

L'unica risposta ben spiegata finora ... È infatti "Class.this consente l'accesso all'istanza della classe esterna" e non cose come "Class.this consente l'accesso a this della classe esterna". Una classe non ha alcun "questo", solo le istanze hanno per fare riferimento a se stesse ...
Żabojad

-2

So qual è la tua confusione. Sto incontrando il problema proprio ora, dovrebbe avere una scena speciale per distinguerli.

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.##")
  }
}

Puoi vedere la differenza tra THIS.thise thisnella nuova QUESTA operazione tramite hashcode (. ##)

test in scala console:

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.thispunta sempre a QUESTA classe esterna a cui fa riferimento val x, ma thisè al di là di una nuova operazione anonima.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.