Java: Class.this


112

Tôi có một chương trình Java trông như thế này.

public class LocalScreen {

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

Điều gì có LocalScreen.thisnghĩa là trong aFuncCall?

Câu trả lời:


169

LocalScreen.thisđề cập đến thislớp bao quanh.

Ví dụ này sẽ giải thích nó:

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

Đầu ra:

An anonymous Runnable!
A LocalScreen object

Bài đăng này đã được viết lại thành một bài báo ở đây .


Điều gì sẽ xảy ra nếu bạn có điều gì đó như: public class a { private class a { public void run() { System.out.println(a.this.toString()); } } Tôi cho rằng đó là vấn đề tương tự; các a.thisbên trong run()phải tham khảo các kèm theo a 's this. Tôi nói đúng chứ? (Đây là cách mã minified là trong ứng dụng của OSX Kindle previewer .jarfile, Tôi chỉ cố gắng để hiểu những gì tôi đang nhìn vào.)
Matt Mc

Trong Java, một lớp bên trong có thể không trùng tên với bất kỳ lớp nào bao quanh nó (JLS 8.1), vì vậy a.thistrong ví dụ của bạn không được định nghĩa. Tôi không biết liệu ràng buộc này có đúng với bytecode hay không. Có thể không.
aioobe

56

Nó có nghĩa là thisthể hiện của lớp bên ngoài LocalScreen.

Việc ghi thismà không có định nghĩa sẽ trả về thể hiện của lớp bên trong mà lệnh gọi nằm bên trong.


4
Vẫn chưa hiểu lắm. Sự khác biệt khi tôi đặt mã là "LocalScreen.this" so với "this" là gì? Tôi đã thử nghiệm cả hai và trình biên dịch chỉ chấp nhận "LocalScreen.this". Tham số đầu tiên của aFuncCall mong đợi lớp aParent là lớp cha của "Somethig".
Johnny Jazz

1
Tôi cũng tò mò về điều này. Bạn có thể cung cấp một số chi tiết về điều này có nghĩa là gì? Tôi không thấy bất kỳ lớp bên trong nào được định nghĩa trong đoạn mã trên; có phải mọi hàm Java đều có một lớp ẩn danh được liên kết tách biệt với lớp mà nó là thành viên không?
poundifdef

4
@rascher: Có các lớp bên trong đang được sử dụng; OP đã không đưa chúng vào đoạn mã. Cú pháp này chỉ được hỗ trợ trong một lớp bên trong không tĩnh.
SLaks

Rất vui vì bạn đã cung cấp một liên kết đến tài liệu Java chính thức.
Krzysztof Tomaszewski

14

Trình biên dịch lấy mã và làm điều gì đó như thế này với nó:

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

Như bạn có thể thấy, khi trình biên dịch lấy một lớp bên trong, nó sẽ chuyển đổi nó thành lớp bên ngoài (đây là một quyết định thiết kế được đưa ra cách đây rất lâu để các máy ảo không cần phải thay đổi để hiểu các lớp bên trong).

Khi một lớp bên trong không tĩnh được tạo, nó cần một tham chiếu đến lớp cha để nó có thể gọi các phương thức / biến truy cập của lớp bên ngoài.

Phần bên trong của lớp bên trong không phải là kiểu thích hợp, bạn cần có quyền truy cập vào lớp bên ngoài để có được kiểu phù hợp để gọi phương thức onMake.


không new LocalScreen$1().run;nên new LocalScreen$1(this).run;?
Diskutant

Đây là một câu trả lời được đánh giá thấp cho câu hỏi. Công cụ thú vị.
Pinkerton

12

Class.thischo phép truy cập vào thể hiện của lớp bên ngoài. Xem ví dụ sau.

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

Sau đó, bạn sẽ nhận được.

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

Câu trả lời duy nhất được giải thích rõ ràng cho đến nay ... Nó thực sự là "Class.this cho phép truy cập vào cá thể của lớp bên ngoài" chứ không phải những thứ như "Class.this cho phép truy cập vào lớp bên ngoài của cái này". Một lớp không có bất kỳ "cái này" nào, chỉ có các trường hợp để tự tham chiếu ...
Żabojad

-2

Tôi biết sự nhầm lẫn của bạn là gì. Tôi gặp phải vấn đề vừa rồi, nó phải có cảnh đặc biệt để phân biệt chúng.

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

Bạn có thể thấy sự khác biệt giữa THIS.thisthistrong hoạt động NÀY mới bằng mã băm (. ##)

kiểm tra trong bảng điều khiển 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.thisluôn trỏ đến bên ngoài lớp NÀY được tham chiếu bởi val x, nhưng thiskhông phải là hoạt động mới ẩn danh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.