Ява: Class.this


112

У мене є програма Java, яка виглядає приблизно так.

public class LocalScreen {

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

Що LocalScreen.thisозначає aFuncCall?

Відповіді:


169

LocalScreen.thisвідноситься до thisкласу, що додається.

Цей приклад повинен пояснити це:

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

Вихід:

An anonymous Runnable!
A LocalScreen object

Ця публікація була переписана як стаття тут .


Що робити, якщо у вас є щось на кшталт: public class a { private class a { public void run() { System.out.println(a.this.toString()); } } я гадаю, що це та сама справа; a.thisвсередині run()повинен ставитися до огороджувальних a «S this. Маю рацію? (Ось як мінімізований код є у .jarфайлах програми OSX Kindle Previewer , я просто намагаюся зрозуміти, на що я дивлюся.)
Метт Мак,

У Java внутрішній клас може не мати того ж імені, що і будь-який із класів, що додаються (JLS 8.1), тому a.thisу вашому прикладі не визначено. Я не знаю, чи справедливо це обмеження для байт-коду. Можливо, не.
aioobe

56

Це означає thisекземпляр зовнішнього LocalScreenкласу.

Запис thisбез класифікатора поверне примірник внутрішнього класу, в якому знаходиться виклик.


4
Ще не зовсім розумію. Яка різниця, коли я кодую її як "LocalScreen.this" порівняно з "this"? Я тестував і те, і компілятор прийняв лише "LocalScreen.this". Перший параметр aFuncCall очікує клас aParent, який є батьківським класом "Somethig".
Джонні Джаз

1
Мені теж цікаво про це. Чи можете ви надати детальну інформацію про те, що це означає? Я не бачу жодних внутрішніх класів, визначених у наведеному вище коді; чи кожна функція Java має пов'язаний анонімний клас, окремий від класу, до якого він належить?
poundifdef

4
@rascher: Є внутрішні класи у використанні; ОП не включила їх у фрагмент коду. Цей синтаксис підтримується лише в нестатичному внутрішньому класі.
SLaks

Приємно, що ви надали посилання на офіційну документацію Java.
Кшиштоф Томашевський

14

Компілятор бере код і робить з ним щось подібне:

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

Як бачимо, коли компілятор приймає внутрішній клас, він перетворює його у зовнішній клас (це було дизайнерське рішення, яке було прийнято LONG час тому, і VM не потрібно було міняти для розуміння внутрішніх класів).

Коли зроблений нестатичний внутрішній клас, йому потрібна посилання на батьківський, щоб він міг викликати методи / доступу до змінних зовнішнього класу.

Це всередині внутрішнього класу не є належним типом, вам потрібно отримати доступ до зовнішнього класу, щоб отримати правильний тип для виклику методу onMake.


не повинно new LocalScreen$1().run;бути new LocalScreen$1(this).run;?
Дискутант

Це занижена відповідь на запитання. Цікаві речі.
Пінкертон

12

Class.thisдозволяє отримати доступ до екземпляра зовнішнього класу. Дивіться наступний приклад.

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

Тоді ви отримаєте.

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

Єдина добре пояснена відповідь досі ... Це дійсно "Class.this дозволяє доступ до екземпляра зовнішнього класу", а не такі речі, як "Class.this дозволяє доступ до зовнішнього класу". Клас не має "цього", лише екземпляри для того, щоб посилатися на себе ...
Żabojad

-2

Я знаю, у чому полягає ваша плутанина. Я зараз стикаюся з проблемою, у мене повинна бути спеціальна сцена, щоб їх розрізнити.

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

Ви можете побачити різницю THIS.thisта thisв цій ЦІЙ операції за допомогою хеш-коду (. ##)

тест на консолі 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.thisзавжди вказують на зовнішній ЦЕЙ клас, на який посилається val x, але thisвиходить за нову анонімну операцію.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.