Java: Class.this

113

У меня есть программа на Java, которая выглядит так.

public class LocalScreen {

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

Что LocalScreen.thisзначит в aFuncCall?

Джонни Джаз
источник

Ответы:

170

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

Это сообщение было переписано как статья здесь .

aioobe
источник
Что, если у вас есть что-то вроде: 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без квалификатора вернет экземпляр внутреннего класса , внутри которого находится вызов.

SLaks
источник
4
Все еще не совсем понимаю. В чем разница, когда я кодирую его как «LocalScreen.this» по сравнению с «this»? Я протестировал оба, и компилятор принял только "LocalScreen.this". Первый параметр aFuncCall ожидает родительский класс, который является родительским классом Somethig.
Johnny Jazz
1
Мне это тоже интересно. Не могли бы вы подробнее объяснить, что это означает? Я не вижу никаких внутренних классов, определенных в приведенном выше коде; имеет ли каждая функция Java связанный анонимный класс, отдельный от класса, членом которого она является?
poundifdef 03
4
@rascher: используются внутренние классы; OP не включил их во фрагмент кода. Этот синтаксис поддерживается только в нестатическом внутреннем классе.
SLaks 03
Приятно, что вы предоставили ссылку на официальную документацию по 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!";
    }
}

Как вы можете видеть, когда компилятор принимает внутренний класс, он преобразует его во внешний класс (это было дизайнерское решение, принятое ДЛИННО назад, поэтому не нужно было менять виртуальные машины для понимания внутренних классов).

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

Это внутри того, что было внутренним классом, не является правильным типом, вам нужно получить доступ к внешнему классу, чтобы получить правильный тип для вызова метода onMake.

Тофу пиво
источник
не должно new LocalScreen$1().run;быть new LocalScreen$1(this).run;?
Diskutant
Это недооцененный ответ на вопрос. Интересный материал.
Пинкертон
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
NawaMan
источник
Единственный хорошо объясненный ответ на данный момент ... Это действительно «Class.this разрешает доступ к экземпляру внешнего класса», а не такие вещи, как «Class.this разрешает доступ к this внешнего класса». Класс не имеет никакого «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не на анонимную новую операцию.

ЛорансЧен
источник