เมื่อคลาสภายในถูกเพิ่มลงใน Java ในเวอร์ชัน 1.1 ของภาษาเดิมพวกเขาถูกกำหนดให้เป็นการแปลงเป็นโค้ดที่เข้ากันได้ 1.0 ถ้าคุณดูตัวอย่างของการเปลี่ยนแปลงนี้ฉันคิดว่ามันจะทำให้ชัดเจนขึ้นมากว่าคลาสชั้นในทำงานอย่างไร
พิจารณารหัสจากคำตอบของ Ian Roberts:
public class Foo {
int val;
public Foo(int v) { val = v; }
class Bar {
public void printVal() {
System.out.println(val);
}
}
public Bar createBar() {
return new Bar();
}
}
เมื่อเปลี่ยนเป็นโค้ดที่เข้ากันได้ 1.0 คลาสภายในBarนั้นจะกลายเป็นดังนี้:
class Foo$Bar {
private Foo this$0;
Foo$Bar(Foo outerThis) {
this.this$0 = outerThis;
}
public void printVal() {
System.out.println(this$0.val);
}
}
ชื่อคลาสด้านในถูกนำหน้าด้วยชื่อคลาสภายนอกเพื่อให้ไม่ซ้ำกัน มีการthis$0เพิ่มสมาชิกส่วนตัวที่ซ่อนอยู่ซึ่งเก็บสำเนาของด้านนอกthisสมาชิกจะมีการเพิ่มที่เก็บสำเนาของด้านนอกได้และตัวสร้างที่ซ่อนอยู่จะถูกสร้างขึ้นเพื่อเริ่มต้นสมาชิกนั้น
และถ้าคุณดูcreateBarวิธีการมันจะถูกเปลี่ยนเป็นแบบนี้:
public Foo$Bar createBar() {
return new Foo$Bar(this);
}
ลองดูว่าจะเกิดอะไรขึ้นเมื่อคุณรันโค้ดต่อไปนี้
Foo f = new Foo(5);
Foo.Bar b = f.createBar();
b.printVal();
อันดับแรกเราสร้างอินสแตนซ์ของอินสแตนซ์Fooและเริ่มต้นvalสมาชิกเป็น 5 (เช่นf.val = 5)
ต่อไปเราจะเรียกf.createBar()ว่าอินสแตนซ์ของอินสแตนซ์Foo$Barและเริ่มต้นthis$0สมาชิกเป็นค่าของการthisส่งผ่านจากcreateBar(เช่นb.this$0 = f)
ในที่สุดเราเรียกb.printVal()ซึ่งพยายามที่จะพิมพ์b.this$0.valซึ่งเป็นf.valซึ่งเป็น 5
ตอนนี้เป็นอินสแตนซ์ปกติของคลาสชั้นใน ดู Let 's สิ่งที่เกิดขึ้นเมื่อ instantiating จากภายนอกBarFoo
Foo f = new Foo(5);
Foo.Bar b = f.new Bar();
b.printVal();
ใช้การแปลง 1.0 ของเราอีกครั้งบรรทัดที่สองจะกลายเป็นดังนี้:
Foo$Bar b = new Foo$Bar(f);
นี่แทบจะเหมือนกับการf.createBar()โทร อีกครั้งเรากำลังสร้างอินสแตนซ์Foo$Barและเริ่มต้นthis$0สมาชิกเป็น f อีกครั้งb.this$0 = fดังนั้นอีกครั้ง
และอีกครั้งเมื่อคุณโทรb.printVal()คุณกำลังพิมพ์b.thi$0.valซึ่งก็f.valคือ 5
สิ่งสำคัญที่ต้องจำไว้คือชั้นในมีสมาชิกที่ซ่อนอยู่ซึ่งถือสำเนาthisจากชั้นนอก เมื่อคุณยกตัวอย่างระดับชั้นจากภายในชั้นนอกมัน initialised thisโดยปริยายด้วยมูลค่าปัจจุบันของ เมื่อคุณสร้างอินสแตนซ์คลาสภายในจากภายนอกคลาสภายนอกคุณต้องระบุอินสแตนซ์ของคลาสภายนอกที่จะใช้อย่างชัดเจนผ่านคำนำหน้าของnewคีย์เวิร์ด