Java: Class นี้


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

โพสต์นี้ได้รับการเขียนใหม่เป็นบทความที่นี่


จะเป็นอย่างไรถ้าคุณมีบางอย่างเช่นpublic class a { private class a { public void run() { System.out.println(a.this.toString()); } } ฉันคิดว่ามันเป็นเรื่องเดียวกัน a.thisภายในrun()ต้องดูที่การปิดล้อม 'sa thisฉันถูกไหม? (นี่คือวิธีที่โค้ดย่อขนาดใน.jarไฟล์ของแอพ OSX Kindle Previewer ฉันแค่พยายามเข้าใจสิ่งที่ฉันกำลังดูอยู่)
Matt Mc

ใน Java คลาสภายในอาจไม่มีชื่อเดียวกับคลาสที่ปิดล้อม (JLS 8.1) ดังนั้นa.thisในตัวอย่างของคุณไม่ได้กำหนดไว้ ฉันไม่รู้ว่าข้อ จำกัด นี้เป็นจริงสำหรับ bytecode หรือไม่ อาจจะไม่.
aioobe

56

มันหมายถึงthisอินสแตนซ์ของLocalScreenคลาสนอก

การเขียนthisโดยไม่มีคุณสมบัติจะส่งคืนอินสแตนซ์ของคลาสภายในที่การเรียกอยู่ภายใน


4
ยังไม่ค่อยเข้าใจ อะไรคือความแตกต่างเมื่อฉันตั้งรหัสเป็น "LocalScreen.this" เมื่อเทียบกับ "this"? ฉันทดสอบทั้งสองและคอมไพเลอร์ยอมรับเฉพาะ "LocalScreen.this" พารามิเตอร์แรกของ aFuncCall คาดหวังคลาส aParent ซึ่งเป็นคลาสแม่ของ "Somethig"
Johnny Jazz

1
ฉันก็อยากรู้เรื่องนี้เหมือนกัน คุณช่วยให้รายละเอียดเกี่ยวกับความหมายนี้ได้หรือไม่? ฉันไม่เห็นคลาสภายในใด ๆ ที่กำหนดไว้ในโค้ดด้านบน ทุกฟังก์ชัน Java มีคลาสที่ไม่ระบุชื่อที่เกี่ยวข้องแยกจากคลาสที่เป็นสมาชิกหรือไม่
poundifdef

4
@rascher: มีคลาสภายในที่ใช้งานอยู่ OP ไม่ได้รวมไว้ในข้อมูลโค้ด ไวยากรณ์นี้รองรับเฉพาะในคลาสภายในที่ไม่คงที่
SLaks

ยินดีที่คุณได้ให้ลิงค์ไปยังเอกสาร Java อย่างเป็นทางการ
Krzysztof Tomaszewski

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

อย่างที่คุณเห็นเมื่อคอมไพเลอร์ใช้คลาสภายในมันจะแปลงเป็นคลาสภายนอก (นี่เป็นการตัดสินใจออกแบบเมื่อนานมาแล้วดังนั้น VMs จึงไม่จำเป็นต้องเปลี่ยนเพื่อทำความเข้าใจคลาสภายใน)

เมื่อสร้างคลาสภายในที่ไม่คงที่จำเป็นต้องมีการอ้างอิงถึงพาเรนต์เพื่อให้สามารถเรียกใช้วิธีการ / เข้าถึงตัวแปรของคลาสภายนอกได้

ภายในของสิ่งที่เป็นคลาสภายในไม่ใช่ประเภทที่เหมาะสมคุณต้องเข้าถึงคลาสด้านนอกเพื่อให้ได้ประเภทที่เหมาะสมสำหรับการเรียกใช้เมธอด onMake


ไม่ควรnew LocalScreen$1().run;จะเป็นnew LocalScreen$1(this).run;?
Diskutant

นี่คือคำตอบที่ไม่ได้ประเมินไว้สำหรับคำถามนี้ สิ่งที่น่าสนใจ
Pinkerton

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

คำตอบเดียวที่อธิบายได้ดีจนถึงตอนนี้ ... มันคือ "คลาสซึ่งอนุญาตให้เข้าถึงอินสแตนซ์ของคลาสชั้นนอก" และไม่ใช่สิ่งต่างๆเช่น "คลาสนี่อนุญาตให้เข้าถึงคลาสชั้นนอกของสิ่งนี้" ชั้นเรียนไม่มี "สิ่งนี้" มีเพียงอินสแตนซ์เพื่ออ้างอิงตัวเอง ...
Ż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> 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อยู่นอกเหนือการดำเนินการใหม่ที่ไม่ระบุชื่อ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.