Java: Class.this

129

我有一个像这样的Java程序。

public class LocalScreen {

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

LocalScreen.thisaFuncCall 中是什么意思?


1
这个回答解决了你的问题吗?在类名中使用“this” - rainbow.gekota
5个回答

195

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

这篇文章已经在这里被重写为一篇文章:Java类中的this关键字


如果你有这样的代码:public class a { private class a { public void run() { System.out.println(a.this.toString()); } } 我猜想它是同样的问题;在run()中的a.this必须引用封闭的 athis。我对吗?(这是OSX Kindle预览器应用程序的.jar文件中的缩小代码,我只是想理解我正在查看的内容。) - Matt Mc
在Java中,内部类的名称不能与其封闭类之一相同(JLS 8.1),因此您示例中的a.this未定义。我不知道这个约束是否适用于字节码。也许不是。 - aioobe

62

这意味着是外部 LocalScreen 类的实例。

如果没有限定符地写入 this,将返回调用所在的内部类的实例。


4
我翻译如下:仍然不太明白。当我将代码编写为“LocalScreen.this”和“this”时有什么区别?我测试了两者,编译器只接受“LocalScreen.this”。aFuncCall的第一个参数需要一个父类,该父类是“Something”的父类。 - Johnny Jazz
1
我也很好奇。你能详细说明一下这是什么意思吗?我在上面的代码中没有看到任何内部类定义;每个Java函数都有一个与其所属类分离的匿名类吗? - poundifdef
4
代码中使用了内部类,但是 OP 没有在代码片段中包含它们。这种语法仅支持非静态内部类。 - SLaks
很好,你提供了官方Java文档的链接。 - Krzysztof Tomaszewski

16
编译器会将代码处理成类似以下的形式:
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!";
    }
}

如您所见,当编译器处理内部类时,它将其转换为外部类(这是一个长时间以前做出的设计决策,因此不需要更改VM来理解内部类)。
创建非静态内部类时,它需要引用父类,以便可以调用外部类的方法/访问变量。
内部类中的this不是正确的类型,您需要访问外部类以获取调用onMake方法的正确类型。

“new LocalScreen$1().run;” 应该改为 “new LocalScreen$1(this).run;” 吗? - MetalSnake
这是一个被低估的回答。有趣的东西。 - Lv99Zubat

13

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允许访问外部类的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.thisthis之间的差异。

在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 总是指向外部的 THIS 类,由 val x 引用,但 this 超出了匿名新操作的范围。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接