Java: Class.this


113

Buna benzeyen bir Java programım var.

public class LocalScreen {

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

Ne anlama LocalScreen.thisgeliyor aFuncCall?

Yanıtlar:


170

LocalScreen.thisthiskapalı sınıfa atıfta bulunur .

Bu örnek bunu açıklamalıdır:

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

Çıktı:

An anonymous Runnable!
A LocalScreen object

Bu gönderi burada bir makale olarak yeniden yazılmıştır .


Ya şöyle bir şeye sahipseniz: public class a { private class a { public void run() { System.out.println(a.this.toString()); } } Bunun aynı mesele olduğunu varsayıyorum; a.thisiçinde run()başvurmalıdır kapatmakta a 's this. Haklı mıyım (Küçültülmüş kod OSX Kindle Previewer uygulamasının .jardosyalarında böyle, sadece neye baktığımı anlamaya çalışıyorum.)
Matt Mc

Java'da bir iç sınıf, kapsayıcı sınıflarından herhangi biriyle (JLS 8.1) aynı ada sahip olmayabilir, bu nedenle a.thisörneğinizde tanımlanmamıştır. Bu kısıtlamanın bayt kodu için doğru olup olmadığını bilmiyorum. Belki değil.
aioobe

56

thisDış LocalScreensınıfın örneği anlamına gelir .

Niteleyici thisolmadan yazmak , çağrının içinde bulunduğu iç sınıfın örneğini döndürür .


4
Hala tam olarak anlamadım. "LocalScreen.this" olarak kodladığımda "this" ile karşılaştırıldığında ne fark var? Her ikisini de test ettim ve derleyici yalnızca "LocalScreen.this" i kabul etti. AFuncCall'ın ilk parametresi, "Somethig" in üst sınıfı olan aParent sınıfını bekler.
Johnny Jazz

1
Bunu ben de merak ediyorum. Bunun ne anlama geldiğine dair biraz ayrıntı verebilir misiniz? Yukarıdaki kodda tanımlanan herhangi bir iç sınıf görmüyorum; her Java işlevinin üyesi olduğu sınıftan ayrı, ilişkili bir anonim sınıfı var mı?
poundifdef

4
@rascher: Kullanımda olan iç sınıflar var; OP bunları kod pasajına dahil etmedi. Bu sözdizimi yalnızca statik olmayan bir iç sınıfta desteklenir.
SLaks

Resmi Java belgelerine bir bağlantı sağlamış olmanız çok güzel.
Krzysztof Tomaszewski

14

Derleyici kodu alır ve onunla bunun gibi bir şey yapar:

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

Gördüğünüz gibi, derleyici bir iç sınıfı aldığında, onu bir dış sınıfa dönüştürür (bu, uzun zaman önce alınan bir tasarım kararıydı, böylece VM'lerin iç sınıfları anlamak için değiştirilmesine gerek yoktu).

Statik olmayan bir iç sınıf oluşturulduğunda, dış sınıfın yöntemlerini / erişim değişkenlerini çağırabilmesi için üst öğeye bir başvuruya ihtiyaç duyar.

İç sınıfın içindeki bu doğru tür değildir, onMake yöntemini çağırmak için doğru türü elde etmek için dış sınıfa erişim sağlamanız gerekir.


olmamalıdır new LocalScreen$1().run;olmak new LocalScreen$1(this).run;?
Diskutant

Bu, sorunun küçümsenmemiş bir cevabıdır. İlginç şeyler.
Pinkerton

12

Class.thisdış sınıfın örneğine erişim sağlar. Aşağıdaki örneğe bakın.

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

O zaman alacaksın.

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

Şimdiye kadar iyi açıklanmış tek cevap ... Aslında "Sınıf. Bu dış sınıfın örneğine erişime izin veriyor" ve "Sınıf. Bu dış sınıfın buna erişime izin veriyor" gibi şeyler değil. Bir sınıfta "bu" yoktur, yalnızca örneklerde kendilerine referans vermek için vardır ...
Żabojad

-2

Kafanızın karıştığını biliyorum, şu anda sorunla karşılaşıyorum, onları ayırt etmek için özel bir sahne olmalı.

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

Hashcode (. ##) ile yeni BU işlemdeki THIS.thisve thisarasındaki farkı görebilirsiniz .

scala konsolunda test edin:

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.thisher zaman val x tarafından atıfta bulunulan, ancak thisanonim yeni işlemin ötesinde olan dış THIS sınıfına işaret eder .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.