Java: Kelas. Ini

112

Saya memiliki program Java yang terlihat seperti ini.

public class LocalScreen {

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

Apa LocalScreen.thisartinya dalam aFuncCall?

Johnny Jazz
sumber

Jawaban:

169

LocalScreen.thismengacu thispada kelas penutup.

Contoh ini harus menjelaskannya:

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

Keluaran:

An anonymous Runnable!
A LocalScreen object

Posting ini telah ditulis ulang sebagai artikel di sini .

aioobe
sumber
Bagaimana jika Anda memiliki sesuatu seperti: public class a { private class a { public void run() { System.out.println(a.this.toString()); } } Saya mengira itu masalah yang sama; yang a.thisdalam run()harus mengacu pada melampirkan a 's this. Apakah saya benar? (Beginilah cara kode yang diperkecil ada di .jarfile aplikasi OSX Kindle Previewer , saya hanya mencoba memahami apa yang saya lihat.)
Matt Mc
Di Java kelas dalam mungkin tidak memiliki nama yang sama dengan kelas yang melingkupinya (JLS 8.1), jadi a.thisdalam contoh Anda tidak ditentukan. Saya tidak tahu apakah batasan ini benar untuk bytecode. Mungkin tidak.
aioobe
56

Itu berarti thisturunan dari LocalScreenkelas luar .

Menulis thistanpa qualifier akan mengembalikan instance kelas dalam tempat pemanggilan berada.

SLaks
sumber
4
Masih belum begitu mengerti. Apa perbedaan ketika saya mengkodekannya sebagai "LocalScreen.this" dibandingkan dengan "this"? Saya menguji keduanya dan kompilator hanya menerima "LocalScreen.this". Parameter pertama dari aFuncCall mengharapkan kelas aParent yang merupakan kelas induk dari "Somehig".
Johnny Jazz
1
Saya juga penasaran tentang ini. Dapatkah Anda memberikan beberapa detail tentang apa artinya ini? Saya tidak melihat kelas dalam yang ditentukan dalam kode di atas; apakah setiap fungsi Java memiliki kelas anonim terkait yang terpisah dari kelas yang menjadi anggotanya?
poundifdef
4
@rascher: Ada kelas dalam yang digunakan; OP tidak memasukkannya ke dalam potongan kode. Sintaks ini hanya didukung di kelas dalam non-statis.
SLaks
Senang Anda telah memberikan tautan ke dokumentasi resmi Java.
Krzysztof Tomaszewski
14

Kompiler mengambil kode dan melakukan sesuatu seperti ini dengannya:

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

Seperti yang Anda lihat, ketika kompilator mengambil kelas dalam, ia mengubahnya menjadi kelas luar (ini adalah keputusan desain yang dibuat sejak lama sehingga VM tidak perlu diubah untuk memahami kelas dalam).

Ketika kelas dalam non-statis dibuat, ia membutuhkan referensi ke induk sehingga dapat memanggil metode / variabel akses dari kelas luar.

Bagian dalam kelas dalam ini bukanlah jenis yang tepat, Anda perlu mendapatkan akses ke kelas luar untuk mendapatkan jenis yang tepat untuk memanggil metode onMake.

TofuBeer
sumber
seharusnya tidak new LocalScreen$1().run;menjadi new LocalScreen$1(this).run;?
Diskutan
Ini adalah jawaban yang diremehkan untuk pertanyaan itu. Hal menarik.
Pinkerton
12

Class.thismemungkinkan akses ke instance dari kelas luar. Lihat contoh berikut.

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

Maka Anda akan mendapatkannya.

D: a-b-c-d
C: a-b-c
B: a-b
A: a
NawaMan
sumber
Satu-satunya jawaban yang dijelaskan dengan baik sejauh ini ... Ini memang "Kelas. Ini memungkinkan akses ke instance dari kelas luar" dan bukan hal-hal seperti "Kelas. Ini memungkinkan akses ke kelas luar ini". Kelas tidak memiliki "ini", hanya instance yang memiliki referensi sendiri ...
Żabojad
-2

Saya tahu apa kebingungan Anda. Saya menemukan masalah sekarang, harus ada adegan khusus untuk membedakannya.

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

Anda dapat melihat perbedaan antara THIS.thisdan thisdalam operasi INI baru dengan kode hash (. ##)

uji di konsol 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.thisselalu menunjuk ke luar kelas INI yang dirujuk oleh val x, tetapi thisberada di luar operasi baru anonim.

LoranceChen
sumber