คลาสภายใน Java และคลาสที่ซ้อนกันแบบคงที่


1766

อะไรคือความแตกต่างที่สำคัญระหว่างคลาสภายในและคลาสที่ซ้อนกันแบบคงที่ใน Java การออกแบบ / การนำไปใช้มีบทบาทในการเลือกหนึ่งในสิ่งเหล่านี้หรือไม่?


65
คำตอบของ Joshua Bloch อยู่ใน การ อ่าน Java ที่มีประสิทธิภาพitem 22 : Favor static member classes over non static
Raymond Chenon

4
สำหรับบันทึกเป็นรายการที่ 24 ในหนังสือฉบับเดียวกันรุ่นที่ 3
ZeroCool

คำตอบ:


1696

จากการสอน Java :

คลาสที่ซ้อนกันแบ่งออกเป็นสองหมวดหมู่: แบบคงที่และไม่คงที่ คลาสที่ซ้อนกันที่ประกาศสแตติกเรียกง่ายๆว่าคลาสที่ซ้อนกันแบบสแตติก คลาสแบบซ้อนไม่คงที่เรียกว่าคลาสภายใน

คลาสที่ซ้อนแบบคงที่จะเข้าถึงได้โดยใช้ชื่อคลาสที่ล้อมรอบ:

OuterClass.StaticNestedClass

ตัวอย่างเช่นในการสร้างวัตถุสำหรับคลาสที่ซ้อนกันคงใช้ไวยากรณ์นี้:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

วัตถุที่เป็นอินสแตนซ์ของคลาสภายในมีอยู่ภายในอินสแตนซ์ของคลาสภายนอก พิจารณาคลาสต่อไปนี้:

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

อินสแตนซ์ของ InnerClass สามารถมีได้เฉพาะภายในอินสแตนซ์ของ OuterClass และมีการเข้าถึงโดยตรงไปยังเมธอดและฟิลด์ของอินสแตนซ์ที่ล้อมรอบ

ในการสร้างอินสแตนซ์ของคลาสภายในคุณต้องสร้างอินสแตนซ์ของคลาสภายนอก จากนั้นสร้างวัตถุภายในภายในวัตถุภายนอกด้วยไวยากรณ์นี้:

OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

ดู: บทช่วยสอน Java - คลาสที่ซ้อนกัน

เพื่อความสมบูรณ์ทราบว่ายังมีสิ่งเช่นนี้เป็นชั้นในโดยไม่ต้องยกตัวอย่างเช่น :

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

นี่new A() { ... }คือคลาสภายในที่กำหนดในบริบทแบบสแตติกและไม่มีอินสแตนซ์ล้อมรอบ


130
ทราบว่าคุณยังสามารถนำเข้าชั้นซ้อนกันคงโดยตรงคือคุณสามารถทำ (ที่ด้านบนของไฟล์): import OuterClass.StaticNestedClass; แล้วอ้างอิงชั้นเพียงแค่เป็น OuterClass
Camilo Díaz Repka

4
@Martin มีชื่อทางเทคนิคเฉพาะสำหรับสำนวนนี้ในการสร้างชั้นในOuterClass.InnerClass innerObject = outerObject.new InnerClass();หรือไม่?
Geek

7
ดังนั้นการใช้คลาสที่ซ้อนกันแบบคงที่ส่วนตัวคืออะไร? ฉันคิดว่าเราไม่สามารถยกตัวอย่างจากด้านนอกอย่าง OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass ();
RoboAlex

1
@ Ilya Kogan: ฉันหมายความว่าฉันรู้ว่าเราสามารถเข้าถึงเขตข้อมูลระดับผู้ปกครองแบบคงที่หรือไม่คงที่ (ถ้าระดับเด็กเป็นแบบไม่คงที่) ฉันได้ใช้คุณสมบัติของพวกเขาสองครั้ง แต่ฉันสงสัยว่าแบบจำลองหน่วยความจำชนิดใด พวกเขาทำตาม? แนวคิดของ OOP ครอบคลุมแนวคิดเหล่านั้นเป็นแนวคิดแยกกันอย่างไร ถ้าไม่ใช่ตำแหน่งที่พวกเขาเหมาะสมใน OOP ดูเหมือนว่าจะเป็นเพื่อนร่วมชั้นกับฉัน :)
Mubashar

4
@ มาร์ตินฉันรู้ว่าฉันมาที่หัวข้อนี้ช้าไปอย่างไม่น่าเชื่อ แต่: มันเป็นตัวแปรของคุณ a ซึ่งเป็นฟิลด์แบบคงที่ของคลาส A. นั่นไม่ได้หมายความว่าคลาสนิรนามที่สร้างโดย 'new A () {int t () {กลับ 2; }} 'เป็นแบบสแตติกมากกว่าถ้าฉันเพียงแค่มอบหมายวัตถุอื่นใดให้กับฟิลด์แบบสแตติก, a, ใน: คลาส B {โมฆะหลักแบบคงที่ (สตริง s) {Aa = new A ()}} (A & B เหมือนกัน แพ็คเกจ) สิ่งนี้ไม่ทำให้คลาส A คงที่ วลี "บริบทแบบคงที่" ในการอ้างอิงที่อ้างถึงในเธรดที่คุณเชื่อมโยงไปนั้นคลุมเครืออย่างไม่น่าเชื่อ อันที่จริงแล้วสิ่งนี้ได้ถูกบันทึกไว้ในข้อคิดเห็นจำนวนมากในเธรดนั้น
GrantRobertson

599

Java กวดวิชากล่าวว่า :

คำศัพท์: คลาสที่ซ้อนกันแบ่งออกเป็นสองประเภท: แบบคงที่และไม่คงที่ คลาสที่ซ้อนกันที่ประกาศสแตติกเรียกง่ายๆว่าคลาสที่ซ้อนกันแบบสแตติก คลาสแบบซ้อนไม่คงที่เรียกว่าคลาสภายใน

ในการพูดจาทั่วไปคำว่า "ซ้อน" และ "ภายใน" ถูกใช้แทนกันโดยโปรแกรมเมอร์ส่วนใหญ่ แต่ฉันจะใช้คำที่ถูกต้อง "ชั้นซ้อน" ซึ่งครอบคลุมทั้งภายในและคงที่

คลาสสามารถเป็นinfinitum โฆษณาที่ซ้อนกันได้เช่นคลาส A สามารถมีคลาส B ซึ่งมีคลาส C ซึ่งมีคลาส D เป็นต้นอย่างไรก็ตามการซ้อนคลาสมากกว่าหนึ่งคลาสนั้นหายากเนื่องจากเป็นการออกแบบที่ไม่ดี

มีสามเหตุผลที่คุณอาจสร้างคลาสที่ซ้อนกัน:

  • การจัดระเบียบ: บางครั้งดูเหมือนว่าเหมาะสมที่สุดในการจัดเรียงคลาสในเนมสเปซของคลาสอื่นโดยเฉพาะเมื่อไม่ใช้ในบริบทอื่น
  • การเข้าถึง: คลาสที่ซ้อนกันมีการเข้าถึงตัวแปร / ฟิลด์ของคลาสที่มีอยู่เป็นพิเศษ (ซึ่งตัวแปร / ฟิลด์ขึ้นอยู่กับชนิดของคลาสที่ซ้อนกันอย่างถูกต้องไม่ว่าจะเป็นด้านในหรือคงที่)
  • ความสะดวกสบาย: ต้องสร้างไฟล์ใหม่สำหรับทุกประเภทใหม่ที่น่ารำคาญอีกครั้งโดยเฉพาะเมื่อประเภทจะถูกใช้ในบริบทเดียว

มีสี่ชนิดของชั้นที่ซ้อนกันในชวา กล่าวโดยย่อคือ:

  • คลาสแบบคงที่ : ประกาศเป็นสมาชิกแบบสแตติกของคลาสอื่น
  • คลาสภายใน : ประกาศเป็นสมาชิกอินสแตนซ์ของคลาสอื่น
  • ชั้นในท้องถิ่น : ประกาศในวิธีการอินสแตนซ์ของคลาสอื่น
  • คลาสภายในที่ไม่ระบุชื่อ : เหมือนคลาสภายใน แต่เขียนเป็นนิพจน์ที่ส่งคืนออบเจ็กต์แบบครั้งเดียว

ให้ฉันทำอย่างละเอียดในรายละเอียดเพิ่มเติม


คลาสแบบคงที่

คลาสสแตติกเป็นชนิดที่เข้าใจง่ายที่สุดเนื่องจากไม่มีส่วนเกี่ยวข้องกับอินสแตนซ์ของคลาสที่มีอยู่

คลาสแบบสแตติกเป็นคลาสที่ประกาศเป็นสมาชิกแบบสแตติกของคลาสอื่น เช่นเดียวกับสมาชิกแบบคงที่อื่น ๆ เช่นชั้นเรียนเป็นจริงเพียงแขวนเกี่ยวกับการใช้ว่าชนชั้นที่มีเป็น namespace ของตนเช่นชั้นแพะประกาศเป็นสมาชิกคงของชั้นแรดในแพคเกจพิซซ่าเป็นที่รู้จักกันในชื่อpizza.Rhino.Goat .

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

คลาสที่คงที่นั้นเป็นคุณสมบัติที่ไร้ค่าเพราะคลาสนั้นแบ่งออกเป็นเนมสเปซแล้วโดยแพ็กเกจ เหตุผลที่เป็นไปได้เพียงอย่างเดียวในการสร้างคลาสแบบสแตติกคือคลาสนั้นมีการเข้าถึงสมาชิกแบบสแตติกส่วนตัวของคลาสที่มีอยู่ แต่ฉันพบว่านี่เป็นเหตุผลที่ค่อนข้างแย่สำหรับคุณลักษณะคลาสแบบสแตติก


ชั้นใน

คลาสภายในเป็นคลาสที่ประกาศเป็นสมาชิกแบบไม่คงที่ของคลาสอื่น:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

เช่นเดียวกับคลาสแบบสแตติกคลาสภายในเรียกว่าคุณสมบัติโดยมีชื่อคลาสที่ประกอบด้วยpizza.Rhino.Goatแต่ในคลาสที่มีอยู่นั้นสามารถรู้จักได้โดยใช้ชื่อแบบง่าย แต่ตัวอย่างของระดับชั้นทุกคนจะผูกติดอยู่กับอินสแตนซ์โดยเฉพาะอย่างยิ่งของชั้นที่มีของ: ข้างต้นแพะสร้างขึ้นในjerryถูกผูกติดอยู่โดยปริยายไปแรดเช่นนี้ในjerry มิฉะนั้นเราจะทำอินสแตนซ์Rhino ที่เกี่ยวข้องอย่างชัดเจนเมื่อเรายกตัวอย่างแพะ :

Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

(โปรดสังเกตว่าคุณอ้างถึงประเภท Inner เป็นเพียงแค่Goatในไวยากรณ์ใหม่แปลก: Java infers ประเภทที่มีจากส่วนแรดและใช่ใหม่ rhino.Goat ()จะทำให้ฉันมีความรู้สึกมากขึ้นด้วย)

ดังนั้นสิ่งนี้ทำให้เราได้รับ? อินสแตนซ์ของคลาสภายในมีการเข้าถึงสมาชิกอินสแตนซ์ของอินสแตนซ์ของคลาสที่ประกอบด้วย สมาชิกอินสแตนซ์ที่ล้อมรอบเหล่านี้ถูกอ้างถึงภายในชั้นในโดยใช้ชื่อแบบง่ายไม่ใช่ผ่าน สิ่งนี้ ( สิ่งนี้ในคลาสชั้นในอ้างอิงถึงอินสแตนซ์ของชั้นในไม่ใช่คลาสที่มีอินสแตนซ์ที่เกี่ยวข้อง):

public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

ในระดับชั้นที่คุณสามารถดูนี้ของชั้นที่มีเป็นRhino.thisและคุณสามารถใช้นี้เพื่ออ้างถึงสมาชิกเช่น Rhino.this.barry


ชั้นในท้องถิ่น

คลาสภายในของคลาสคือคลาสที่ประกาศในเนื้อความของเมธอด ชั้นเรียนดังกล่าวเป็นที่รู้จักกันเฉพาะในวิธีการที่มีของมันดังนั้นมันสามารถเป็นอินสแตนซ์เท่านั้นและมีสมาชิกเข้าถึงได้ภายในวิธีการที่มี กำไรคืออินสแตนซ์ของคลาสภายในที่เชื่อมโยงกับและสามารถเข้าถึงตัวแปรโลคัลสุดท้ายของเมธอดที่มี เมื่ออินสแตนซ์ใช้โลคัลสุดท้ายของเมธอดที่บรรจุตัวแปรจะเก็บค่าที่เก็บไว้ ณ เวลาที่สร้างอินสแตนซ์แม้ว่าตัวแปรจะออกจากขอบเขตแล้ว

เนื่องจากคลาสภายในของโลคัลไม่ใช่สมาชิกของคลาสหรือแพ็กเกจจึงไม่ถูกประกาศด้วยระดับการเข้าถึงข้อมูล (ชัดเจนว่าสมาชิกของตนเองมีระดับการเข้าถึงเหมือนในชั้นเรียนปกติ)

หากมีการประกาศคลาสภายในของท้องถิ่นในวิธีการอินสแตนซ์การสร้างอินสแตนซ์ของคลาสภายในจะเชื่อมโยงกับอินสแตนซ์ที่เก็บไว้โดยวิธีการที่มีนี้ในเวลาของการสร้างอินสแตนซ์และสมาชิกอินสแตนซ์ของ ชั้นใน คลาสภายในของอินสแตนซ์ได้รับการยกตัวอย่างง่ายๆโดยใช้ชื่อของมันเช่นคลาสภายในของแคทนั้นได้รับการยกระดับเป็นCat ใหม่ ()ไม่ใช่สิ่งใหม่นี้ Cat () ตามที่คุณคาดหวัง


ชั้นในที่ไม่ระบุชื่อ

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

new *ParentClassName*(*constructorArgs*) {*members*}

นี้คือการแสดงออกกลับตัวอย่างใหม่ของชั้นไม่มีชื่อซึ่งทอดตัวParentClassName คุณไม่สามารถจัดหาคอนสตรัคเตอร์ของคุณเอง ค่อนข้างหนึ่งคือการจัดหาโดยปริยายซึ่งเรียกว่า super constructor ดังนั้นข้อโต้แย้งที่ให้มาจะต้องพอดีกับตัวสร้าง super (ถ้าผู้ปกครองมีหลาย constructors หนึ่งที่ "ง่ายที่สุด" ถูกเรียกว่า "ง่ายที่สุด" ตามที่กำหนดโดยชุดของกฎที่ค่อนข้างซับซ้อนไม่คุ้มค่าที่จะรบกวนการเรียนรู้ในรายละเอียด - เพียงสนใจสิ่งที่ NetBeans หรือ Eclipse บอกคุณ)

หรือคุณสามารถระบุอินเทอร์เฟซที่จะใช้:

new *InterfaceName*() {*members*}

การประกาศดังกล่าวจะสร้างตัวอย่างใหม่ของชั้นไม่มีชื่อซึ่งทอดตัววัตถุและการดำเนินการInterfaceName อีกครั้งคุณไม่สามารถจัดหาคอนสตรัคเตอร์ของคุณเอง ในกรณีนี้ Java ให้ค่าคอนสตรัคเตอร์ no-arg, do-nothing (ดังนั้นจะไม่มีอาร์กิวเมนต์ตัวสร้างในกรณีนี้)

แม้ว่าคุณจะไม่สามารถให้นวกรรมิกภายในคลาสที่ไม่ระบุชื่อคุณยังสามารถทำการตั้งค่าใด ๆ ที่คุณต้องการโดยใช้บล็อก initializer (บล็อก {} วางอยู่นอกวิธีใด ๆ )

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


39
เรื่องราวที่ยอดเยี่ยมขอบคุณ มันมีหนึ่งข้อผิดพลาด คุณสามารถเข้าถึงฟิลด์ของคลาสภายนอกจากอินสแตนซ์คลาสภายในโดย Rhino.this.variableName
Thirler

2
ในขณะที่คุณไม่สามารถจัดทำคอนสตรัคเตอร์ของคุณเองสำหรับคลาสภายในที่ไม่ระบุชื่อคุณสามารถใช้การเริ่มต้นวงเล็บปีกกาคู่ c2.com/cgi/wiki?DoubleBraceInitialization
Casebash

30
คำอธิบายที่ดี แต่ฉันไม่เห็นด้วยกับการเรียนในชั้นเรียนแบบคงที่ไร้ค่า ดูrwhansen.blogspot.com/2007/07/…สำหรับรูปแบบที่ดีของรูปแบบตัวสร้างที่ขึ้นอยู่กับการใช้คลาสภายในแบบคงที่
Mansoor Siddiqui

9
ฉันยังไม่เห็นด้วยว่าชั้นในแบบคงที่ไม่มีราคาถ้าคุณต้องการ enum ในชั้นในคุณจะต้องทำให้ชั้นในคงที่
คนอยู่ที่ไหนสักแห่ง

9
คลาสที่ซ้อนกันแบบสแตติกส่วนตัวนั้นมีประโยชน์เช่นกัน: คุณต้องการให้มี แต่คุณไม่ต้องการให้ปรากฏ ชอบรายการ <T> ใน LinkedList <T> หรือ AsyncTasks ภายในกิจกรรม (Android) และอื่น ๆ ...
Lorenzo Dematté

150

ฉันไม่คิดว่าความแตกต่างที่แท้จริงนั้นชัดเจนในคำตอบข้างต้น

ก่อนอื่นจะได้รับเงื่อนไขที่ถูกต้อง:

  • คลาสที่ซ้อนกันเป็นคลาสที่มีอยู่ในคลาสอื่นที่ระดับซอร์สโค้ด
  • มันเป็นแบบคงที่ถ้าคุณประกาศด้วยตัวแก้ไขแบบคงที่
  • คลาสที่ซ้อนกันไม่คงที่เรียกว่าคลาสภายใน (ฉันอยู่กับคลาสที่ไม่คงที่)

คำตอบของ Martin นั้นถูกต้องแล้ว อย่างไรก็ตามคำถามที่แท้จริงคือ: อะไรคือวัตถุประสงค์ของการประกาศคลาสที่ซ้อนกันคงที่หรือไม่?

คุณใช้คลาสที่ซ้อนกันแบบคงที่ถ้าคุณเพียงต้องการให้คลาสของคุณอยู่ด้วยกันหากพวกเขาอยู่ในกลุ่มเดียวกันหรือถ้ามีการใช้คลาสแบบซ้อนในคลาสที่ล้อมรอบ ไม่มีความแตกต่างทางความหมายระหว่างคลาสที่ซ้อนกันคงที่และคลาสอื่นทุกคลาส

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

public class Container {
    public class Item{
        Object data;
        public Container getContainer(){
            return Container.this;
        }
        public Item(Object data) {
            super();
            this.data = data;
        }

    }

    public static Item create(Object data){
        // does not compile since no instance of Container is available
        return new Item(data);
    }
    public Item createSubItem(Object data){
        // compiles, since 'this' Container is available
        return new Item(data);
    }
}

ในกรณีนี้คุณต้องการมีการอ้างอิงจากรายการย่อยไปยังคอนเทนเนอร์หลัก การใช้คลาสที่ไม่คงที่แบบซ้อนทำงานได้โดยไม่ต้องทำงานบางอย่าง Container.thisคุณสามารถเข้าถึงเช่นการปิดล้อมของตู้คอนเทนเนอร์ที่มีไวยากรณ์

คำอธิบายที่ไม่ยอมใครง่ายๆเพิ่มเติมต่อไปนี้:

ถ้าคุณดู Java bytecode คอมไพเลอร์จะสร้างคลาสที่ซ้อนกัน (ไม่คงที่) มันอาจจะชัดเจนยิ่งขึ้น:

// class version 49.0 (49)
// access flags 33
public class Container$Item {

  // compiled from: Container.java
  // access flags 1
  public INNERCLASS Container$Item Container Item

  // access flags 0
  Object data

  // access flags 4112
  final Container this$0

  // access flags 1
  public getContainer() : Container
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    GETFIELD Container$Item.this$0 : Container
    ARETURN
   L1
    LOCALVARIABLE this Container$Item L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 1
  public <init>(Container,Object) : void
   L0
    LINENUMBER 12 L0
    ALOAD 0: this
    ALOAD 1
    PUTFIELD Container$Item.this$0 : Container
   L1
    LINENUMBER 10 L1
    ALOAD 0: this
    INVOKESPECIAL Object.<init>() : void
   L2
    LINENUMBER 11 L2
    ALOAD 0: this
    ALOAD 2: data
    PUTFIELD Container$Item.data : Object
    RETURN
   L3
    LOCALVARIABLE this Container$Item L0 L3 0
    LOCALVARIABLE data Object L0 L3 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

Container this$0ที่คุณสามารถดูคอมไพเลอร์สร้างสนามซ่อน นี้ถูกตั้งค่าในตัวสร้างซึ่งมีพารามิเตอร์เพิ่มเติมประเภทคอนเทนเนอร์เพื่อระบุอินสแตนซ์ล้อมรอบ คุณไม่เห็นพารามิเตอร์นี้ในแหล่งที่มา แต่คอมไพเลอร์สร้างโดยปริยายสำหรับชั้นซ้อน

ตัวอย่างของมาร์ติน

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

จะได้รับการคอมไพล์เพื่อเรียกสิ่งที่ต้องการ (เป็นไบต์)

new InnerClass(outerObject)

เพื่อความสมบูรณ์:

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


17
"ไม่มีความแตกต่างทางความหมายระหว่างคลาสที่ซ้อนกันคงที่และคลาสอื่นทุกคลาส" ยกเว้นคลาสที่ซ้อนกันสามารถดูฟิลด์ / เมธอดส่วนตัวของพาเรนต์และคลาสพาเรนต์สามารถดูฟิลด์ / เมธอดส่วนตัวของซ้อนได้
แบรด Cupit

คลาสภายในที่ไม่คงที่อาจทำให้หน่วยความจำขนาดใหญ่รั่วหรือไม่ เช่นเดียวกับในทุกครั้งที่คุณสร้างผู้ฟังคุณสร้างการรั่วไหลหรือไม่?
G_V

3
@G_V มีโอกาสรั่วไหลของหน่วยความจำได้อย่างแน่นอนเนื่องจากอินสแตนซ์ของคลาสภายในเก็บการอ้างอิงกับคลาสภายนอก ปัญหานี้เกิดขึ้นจริงหรือไม่ขึ้นอยู่กับสถานที่และวิธีการอ้างอิงถึงอินสแตนซ์ของคลาสภายนอกและคลาสภายใน
jrudolph

94

ฉันคิดว่าคำตอบข้างต้นไม่สามารถอธิบายความแตกต่างที่แท้จริงระหว่างคลาสที่ซ้อนกันและคลาสที่ซ้อนกันแบบคงที่ในแง่ของการออกแบบแอปพลิเคชัน:

ภาพรวม

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

ข้อแตกต่าง

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

คลาสที่ซ้อนกันแบบคงที่ : ไม่สามารถเข้าถึงอินสแตนซ์ของคลาสที่ล้อมรอบและเรียกใช้เมธอดบนคลาสนั้นได้ดังนั้นควรใช้เมื่อคลาสที่ซ้อนกันไม่ต้องการการเข้าถึงอินสแตนซ์ของคลาสที่ล้อมรอบ การใช้คลาสที่ซ้อนกันแบบสแตติกทั่วไปคือการใช้ส่วนประกอบของวัตถุภายนอก

ข้อสรุป

ดังนั้นความแตกต่างที่สำคัญระหว่างสองจากมุมมองการออกแบบคือชั้นที่ซ้อนกัน nonstatic สามารถเข้าถึงตัวอย่างของการเรียนภาชนะในขณะที่คงไม่สามารถ


: จากบทสรุปของคุณ "ในขณะที่คงที่ไม่สามารถ", ไม่ได้แม้แต่กรณีคงที่ของภาชนะ? แน่ใจหรือไม่?
VdeX

การใช้คลาสที่ซ้อนกันแบบคงที่ทั่วไปคือรูปแบบการออกแบบ ViewHolder ใน RecyclerView และ ListView
Hamzeh Soboh

1
ในหลายกรณีคำตอบสั้น ๆ ชัดเจนกว่าและดีกว่า นี่คือตัวอย่างดังกล่าว
Eric Wang

32

ในแง่ง่ายเราต้องการคลาสที่ซ้อนกันเป็นหลักเนื่องจาก Java ไม่ได้จัดเตรียมการปิด

คลาสที่ซ้อนกันคือคลาสที่กำหนดไว้ภายในเนื้อความของคลาสที่ล้อมรอบอื่น มีสองประเภท - แบบคงที่และไม่คงที่

พวกเขาจะได้รับการปฏิบัติในฐานะสมาชิกของชั้นล้อมรอบด้วยเหตุนี้คุณสามารถระบุใด ๆ ของสี่ specifiers การเข้า private, package, protected, public- เราไม่มีความหรูหรานี้ด้วยคลาสระดับบนสุดซึ่งสามารถประกาศได้publicหรือเป็นแพคเกจส่วนตัวเท่านั้น

คลาสภายใน aka คลาสที่ไม่ใช่สแต็กมีสิทธิ์เข้าถึงสมาชิกรายอื่นของคลาสบนสุดแม้ว่าจะถูกประกาศเป็นส่วนตัวในขณะที่คลาสที่ซ้อนกันแบบสแตติกไม่สามารถเข้าถึงสมาชิกรายอื่นของชั้นบนสุดได้

public class OuterClass {
    public static class Inner1 {
    }
    public class Inner2 {
    }
}

Inner1เป็นชั้นในของเราคงที่และInner2เป็นชั้นในของเราซึ่งไม่คงที่ ความแตกต่างที่สำคัญระหว่างสิ่งเหล่านี้คุณไม่สามารถสร้างInner2อินสแตนซ์โดยไม่มีตัวนอกซึ่งคุณสามารถสร้างInner1วัตถุได้อย่างอิสระ

เมื่อไหร่ที่คุณจะใช้ระดับชั้นใน?

คิดว่าสถานการณ์ที่Class AและClass Bมีความสัมพันธ์Class Bกับความต้องการในการเข้าถึงClass Aสมาชิกและเป็นเรื่องที่เกี่ยวข้องเท่านั้นที่จะClass B Class Aชั้นในเข้ามาในภาพ

สำหรับการสร้างอินสแตนซ์ของคลาสภายในคุณต้องสร้างอินสแตนซ์ของคลาสภายนอกของคุณ

OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();

หรือ

OuterClass.Inner2 inner = new OuterClass().new Inner2();

เมื่อใดที่คุณจะใช้คลาส Inner คงที่?

คุณจะกำหนดคลาสภายในแบบคงที่เมื่อคุณรู้ว่ามันไม่มีความสัมพันธ์ใด ๆ กับอินสแตนซ์ของคลาสที่ปิดล้อม / ชั้นบนสุด หากคลาสภายในของคุณไม่ได้ใช้วิธีการหรือฟิลด์ของคลาสนอกนั่นเป็นเพียงการเสียพื้นที่ดังนั้นให้คงที่

ตัวอย่างเช่นในการสร้างวัตถุสำหรับคลาสที่ซ้อนกันคงใช้ไวยากรณ์นี้:

OuterClass.Inner1 nestedObject = new OuterClass.Inner1();

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


3
คุณหมายถึงOuterClass.Inner2 inner = outer.new Inner2();อะไร
Erik Kaplun

4
static innerเป็นข้อขัดแย้งในแง่
user207421

และคลาสภายในยังไม่เป็นที่รู้จักในชื่อ 'non-stack classes' อย่าใช้การจัดรูปแบบรหัสสำหรับข้อความที่ไม่ใช่รหัสและใช้สำหรับการจัดรูปแบบข้อความ
user207421

30

นี่คือความแตกต่างที่สำคัญและความคล้ายคลึงกันระหว่างคลาสภายใน Java และคลาสที่ซ้อนกันแบบคงที่

หวังว่ามันจะช่วย!

ชั้นใน

  • สามารถเข้าถึงคลาสภายนอกทั้งอินสแตนซ์และเมธอดและฟิลด์แบบสแตติก
  • เชื่อมโยงกับอินสแตนซ์ของคลาสที่ปิดล้อมเพื่อให้อินสแตนซ์ของคลาสแรกต้องใช้อินสแตนซ์ของคลาสภายนอก (หมายเหตุตำแหน่งคำหลักใหม่ ):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
  • ไม่สามารถกำหนดสมาชิกแบบคงที่ใด ๆเอง

  • ไม่สามารถมีชั้นหรือการเชื่อมต่อของการประกาศ

คลาสที่ซ้อนกันแบบคงที่

  • ไม่สามารถเข้าถึงวิธีหรือฟิลด์อินสแตนซ์ของคลาสภายนอก

  • ไม่เกี่ยวข้องกับอินสแตนซ์ใด ๆ ของการปิดคลาสดังนั้นเพื่อยกตัวอย่าง:

    OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

ความคล้ายคลึงกัน

  • ทั้งชั้นในสามารถเข้าถึงได้แม้กระทั่งเขตข้อมูลส่วนตัวและวิธีการของชั้นนอก
  • นอกจากนี้คลาสภายนอกยังมีการเข้าถึงฟิลด์ส่วนตัวและวิธีการของคลาสภายในด้วย
  • ทั้งสองคลาสสามารถมีตัวดัดแปลงการเข้าถึงส่วนตัวการป้องกันหรือการเข้าถึงสาธารณะ

เหตุใดจึงใช้คลาสที่ซ้อนกัน

ตามเอกสารของ Oracle มีสาเหตุหลายประการ ( เอกสารฉบับเต็ม ):

  • มันเป็นวิธีของการจัดกลุ่มคลาสทางตรรกะที่ใช้ในที่เดียวเท่านั้น:ถ้าคลาสมีประโยชน์กับคลาสอื่นเพียงคลาสเดียวมันก็มีเหตุผลที่จะฝังไว้ในคลาสนั้นและเก็บทั้งสองไว้ด้วยกัน การซ้อน "คลาสผู้ช่วยเหลือ" ดังกล่าวทำให้แพ็คเกจของพวกเขาคล่องตัวขึ้น

  • มันเพิ่มการห่อหุ้ม:พิจารณาคลาสระดับบนสุดสองคลาสคือ A และ B โดยที่ B ต้องการเข้าถึงสมาชิกของ A ที่จะถูกประกาศเป็นส่วนตัว โดยการซ่อนคลาส B ภายในคลาส A สมาชิกของ A สามารถถูกประกาศเป็นส่วนตัวและ B สามารถเข้าถึงพวกเขาได้ นอกจากนี้ B สามารถซ่อนตัวจากโลกภายนอกได้

  • มันสามารถนำไปสู่รหัสที่อ่านได้และบำรุงรักษาได้มากกว่า: การซ้อนคลาสย่อยภายในคลาสระดับบนสุดจะวางโค้ดให้ใกล้กับตำแหน่งที่ใช้มากขึ้น


26

ฉันคิดว่าการประชุมที่ปฏิบัติตามโดยทั่วไปคือ:

  • คลาสแบบสแตติกภายในคลาสระดับบนสุดเป็นคลาสแบบซ้อน
  • คลาสที่ไม่คงที่ภายในคลาสระดับบนสุดเป็นคลาสชั้นในซึ่งจะมีรูปแบบอีกสองแบบ:
    • local class - คลาสที่มีชื่อซึ่งประกาศอยู่ภายในบล็อกเช่นเมธอดหรือตัวสร้าง
    • คลาสที่ไม่ระบุชื่อ - คลาสที่ไม่มีชื่อซึ่งอินสแตนซ์ถูกสร้างขึ้นในนิพจน์และข้อความสั่ง

อย่างไรก็ตามจุดอื่น ๆ ที่ควรจดจำคือ:

  • คลาสระดับบนสุดและคลาสที่ซ้อนกันแบบคงที่จะมีความหมายเหมือนกันยกเว้นว่าในกรณีของคลาสที่ซ้อนกันแบบคงที่สามารถทำการอ้างอิงแบบคงที่ไปยังฟิลด์ / เมธอดส่วนตัวแบบคงที่ของคลาส [parent] ด้านนอกและในทางกลับกัน

  • คลาสภายในมีการเข้าถึงตัวแปรอินสแตนซ์ของอินสแตนซ์ที่ล้อมรอบของคลาส Outer [parent] อย่างไรก็ตามคลาสภายในทั้งหมดไม่ได้มีอินสแตนซ์ล้อมรอบตัวอย่างเช่นคลาสภายในในบริบทสแตติกเช่นคลาสนิรนามที่ใช้ในบล็อก initializer แบบสแตติกไม่

  • คลาสนิรนามโดยดีฟอลต์จะขยายคลาสพาเรนต์หรือใช้อินเตอร์เฟสพาเรนต์และไม่มีส่วนคำสั่งเพิ่มเติมเพื่อขยายคลาสอื่นหรือใช้อินเตอร์เฟสเพิ่มเติมใด ๆ ดังนั้น,

    • new YourClass(){}; วิธี class [Anonymous] extends YourClass {}
    • new YourInterface(){}; วิธี class [Anonymous] implements YourInterface {}

ฉันรู้สึกว่าคำถามที่ใหญ่กว่าที่ยังคงเปิดซึ่งเป็นที่หนึ่งที่จะใช้และเมื่อใด ส่วนใหญ่ขึ้นอยู่กับสถานการณ์ที่คุณกำลังเผชิญอยู่ แต่การอ่านคำตอบที่ได้รับจาก @jrudolph อาจช่วยให้คุณตัดสินใจได้


15

คลาสแบบซ้อน: คลาสภายในคลาส

ประเภท:

  1. คลาสที่ซ้อนกันแบบคงที่
  2. คลาสที่ซ้อนกันไม่คงที่ [คลาสภายใน]

ความแตกต่าง:

คลาสที่ซ้อนกันไม่คงที่ [คลาสภายใน]

ในวัตถุคลาสที่ซ้อนกันคงที่ของชั้นในมีอยู่ภายในวัตถุของชั้นนอก เพื่อให้สมาชิกข้อมูลของคลาสภายนอกสามารถเข้าถึงคลาสภายในได้ ดังนั้นในการสร้างวัตถุของชั้นในเราต้องสร้างวัตถุของชั้นนอกก่อน

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

คลาสที่ซ้อนกันแบบคงที่

ในวัตถุคลาสที่ซ้อนแบบคงที่ของคลาสภายในไม่ต้องการวัตถุของคลาสภายนอกเนื่องจากคำว่า "คงที่" ระบุว่าไม่จำเป็นต้องสร้างวัตถุ

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

หากคุณต้องการเข้าถึง x ให้เขียนวิธีการด้านในต่อไปนี้

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);

13

อินสแตนซ์ของคลาสภายในถูกสร้างขึ้นเมื่ออินสแตนซ์ของคลาสภายนอกถูกสร้างขึ้น ดังนั้นสมาชิกและวิธีการของชั้นในมีการเข้าถึงสมาชิกและวิธีการของอินสแตนซ์ (วัตถุ) ของชั้นนอก เมื่ออินสแตนซ์ของคลาสภายนอกออกนอกขอบเขตอินสแตนซ์ของคลาสภายในจะหยุดอยู่

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

คลาสที่ซ้อนกันแบบสแตติกไม่ได้เชื่อมโยงกับวัตถุภายนอกพวกมันเร็วกว่าและไม่ใช้หน่วยความจำฮีป / สแต็กเพราะไม่จำเป็นต้องสร้างอินสแตนซ์ของคลาสดังกล่าว ดังนั้นกฎของหัวแม่มือคือพยายามกำหนดคลาสที่ซ้อนกันแบบคงที่โดยมีขอบเขต จำกัด เท่าที่จะเป็นไปได้ (ส่วนตัว> = คลาส> = ป้องกัน> = สาธารณะ) จากนั้นแปลงเป็นคลาสภายใน (โดยลบตัวระบุ "คงที่") ออก ขอบเขตถ้าจำเป็นจริงๆ


2
ประโยคแรกไม่ถูกต้อง ไม่มีสิ่งเช่น 'เป็นตัวอย่างของการเรียนภายใน' และกรณีของมันสามารถสร้างขึ้นได้ตลอดเวลาหลังจากที่ชั้นนอกได้รับการยกตัวอย่าง ประโยคที่สองไม่เป็นไปตามประโยคแรก
user207421

11

มีความละเอียดอ่อนเกี่ยวกับการใช้คลาสสแตติกที่ซ้อนอยู่ซึ่งอาจมีประโยชน์ในบางสถานการณ์

ในขณะที่สแตติกแอ็ตทริบิวต์รับอินสแตนซ์ก่อนที่คลาสจะถูกสร้างอินสแตนซ์ผ่านทางคอนสตรัคเตอร์ของสแตติกแอ็ตทริบิวต์ภายในของคลาสแบบคงที่ซ้อนกันดูเหมือนจะไม่เริ่มอินสแตนซ์จนกว่าจะ พวกเขาถูกทำเครื่องหมายเป็น 'ขั้นสุดท้าย'

ลองพิจารณาตัวอย่างนี้:

public class C0 {

    static C0 instance = null;

    // Uncomment the following line and a null pointer exception will be
    // generated before anything gets printed.
    //public static final String outerItem = instance.makeString(98.6);

    public C0() {
        instance = this;
    }

    public String makeString(int i) {
        return ((new Integer(i)).toString());
    }

    public String makeString(double d) {
        return ((new Double(d)).toString());
    }

    public static final class nested {
        public static final String innerItem = instance.makeString(42);
    }

    static public void main(String[] argv) {
        System.out.println("start");
        // Comment out this line and a null pointer exception will be
        // generated after "start" prints and before the following
        // try/catch block even gets entered.
        new C0();
        try {
            System.out.println("retrieve item: " + nested.innerItem);
        }
        catch (Exception e) {
            System.out.println("failed to retrieve item: " + e.toString());
        }
        System.out.println("finish");
    }
}

แม้ว่า 'ซ้อนกัน' และ 'InnerItem' ทั้งคู่จะประกาศเป็น 'คงสุดท้าย' การตั้งค่าของ nested.innerItem จะไม่เกิดขึ้นจนกว่าจะมีการสร้างอินสแตนซ์ของคลาส (หรืออย่างน้อยไม่จนกว่าหลังจากที่มีการอ้างอิงรายการสแตติกที่ซ้อนกันครั้งแรก) อย่างที่คุณเห็นด้วยตนเองโดยการแสดงความคิดเห็นและไม่แสดงความคิดเห็น ข้างบน. สิ่งเดียวกันไม่ถือเป็นจริงสำหรับ 'outerItem'

อย่างน้อยนี่คือสิ่งที่ฉันเห็นใน Java 6.0


10

ข้อกำหนดนี้ใช้แทนกันได้ หากคุณต้องการพูดพล่อยๆเกี่ยวกับเรื่องนี้คุณสามารถกำหนด "คลาสที่ซ้อนกัน" เพื่ออ้างถึงคลาสภายในแบบสแตติกซึ่งไม่มีอินสแตนซ์ล้อมรอบ ในรหัสคุณอาจมีสิ่งนี้:

public class Outer {
    public class Inner {}

    public static class Nested {}
}

นั่นไม่ใช่คำจำกัดความที่ได้รับการยอมรับอย่างกว้างขวาง


2
'static Inner' เป็นข้อขัดแย้งในแง่
user207421

5
ไม่ใช่แบบแผนที่กำหนดคลาสภายในเป็นคลาสที่ซ้อนกันแบบไม่คงที่ แต่เป็น JLS docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Lew Bloch

1
และข้อกำหนดไม่ได้ถูกใช้แทนกันได้
user207421

ทำไมสถิตในตัวอย่างข้างต้นให้ข้อผิดพลาดใน IDE
DeV

10

ในกรณีของการสร้างอินสแตนซ์อินสแตนซ์ของคลาสภายในที่ไม่คงที่จะถูกสร้างขึ้นด้วยการอ้างอิงของวัตถุของคลาสภายนอกที่ถูกกำหนดไว้ ซึ่งหมายความว่ามันมีอินสแตนซ์ที่ปิดสนิท แต่อินสแตนซ์ของคลาสภายในแบบคงที่ถูกสร้างขึ้นด้วยการอ้างอิงของคลาสภายนอกไม่ใช่กับการอ้างอิงของวัตถุของคลาสภายนอก ซึ่งหมายความว่ามันไม่มีอินสแตนซ์ปิดบัง

ตัวอย่างเช่น:

class A
{
  class B
  {
    // static int x; not allowed here…..    
  }
  static class C
  {
    static int x; // allowed here
  }
}

class Test
{
  public static void main(String str)
  {
    A o=new A();
    A.B obj1 =o.new B();//need of inclosing instance

    A.C obj2 =new A.C();

    // not need of reference of object of outer class….
  }
}

1
'static Inner' เป็นข้อขัดแย้งในแง่ คลาสที่ซ้อนกันอาจเป็นแบบสแตติกหรือด้านใน
user207421

9

ฉันไม่คิดว่ามีอะไรเพิ่มที่นี่คำตอบส่วนใหญ่อธิบายความแตกต่างระหว่างคลาสที่ซ้อนกันแบบคงที่และคลาสภายในได้อย่างสมบูรณ์แบบ อย่างไรก็ตามพิจารณาปัญหาต่อไปนี้เมื่อใช้คลาสที่ซ้อนกันกับคลาสภายใน ตามที่ได้กล่าวในสองสามคำตอบเรียนภายในไม่สามารถ instantiated โดยไม่ต้องและตัวอย่างของการเรียนการปิดล้อมของพวกเขาซึ่งหมายความว่าพวกเขาถือชี้ไปที่ตัวอย่างของการเรียนการปิดล้อมของพวกเขาซึ่งสามารถนำไปสู่หน่วยความจำล้นหรือข้อยกเว้นแตกล้นเนื่องจากข้อเท็จจริงที่ประชาคมโลก จะไม่สามารถเก็บรวบรวมขยะในคลาสที่ปิดล้อมได้แม้ว่าจะไม่ได้ใช้อีกต่อไป เพื่อให้ชัดเจนตรวจสอบรหัสต่อไปนี้ออก:

public class Outer {


    public  class Inner {

    }


    public Inner inner(){
        return new Inner();
    }

    @Override
    protected void finalize() throws Throwable {
    // as you know finalize is called by the garbage collector due to destroying an object instance
        System.out.println("I am destroyed !");
    }
}


public static void main(String arg[]) {

    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();

    // out instance is no more used and should be garbage collected !!!
    // However this will not happen as inner instance is still alive i.e used, not null !
    // and outer will be kept in memory until inner is destroyed
    outer = null;

    //
    // inner = null;

    //kick out garbage collector
    System.gc();

}

หากคุณลบความคิดเห็นใน// inner = null;โปรแกรมจะออก " ฉันถูกทำลาย! " แต่การรักษาความคิดเห็นนี้จะไม่
เหตุผลก็คืออินสแตนซ์สีขาวด้านในยังคงอ้างอิง GC ไม่สามารถรวบรวมได้และเนื่องจากมีการอ้างอิง มีวัตถุเหล่านี้เพียงพอในโครงการของคุณและอาจมีหน่วยความจำไม่เพียงพอ
เปรียบเทียบกับคลาสภายในแบบสแตติกซึ่งไม่ถือเป็นอินสแตนซ์ของคลาสภายในเนื่องจากไม่มีความเกี่ยวข้อง แต่เป็นคลาสที่เกี่ยวข้อง โปรแกรมด้านบนสามารถพิมพ์ " I am ทำลาย! " ถ้าคุณทำให้ชั้นในคงที่และอินสแตนซ์ด้วยOuter.Inner i = new Outer.Inner();



8

ชั้นซ้อนเป็นคำทั่วไปมาก: ทุกชั้นเรียนที่ไม่ได้อยู่ในระดับบนสุดเป็นชั้นซ้อนกัน คลาสภายในเป็นคลาสที่ไม่ซ้อนกันแบบคงที่ โจเซฟดาร์ซีเขียนคำอธิบายที่ดีมากเกี่ยวกับการซ้อนกันภายในสมาชิกและเรียนระดับบนสุด


8

อืมมม ... ชั้นในเป็นคลาสซ้อนกัน ... คุณหมายถึงคลาสนิรนามและคลาสภายในหรือไม่

แก้ไข: ถ้าคุณหมายถึง Inner vs Anonymous แบบไม่ระบุ ... คลาสภายในเป็นเพียงคลาสที่กำหนดภายในคลาสเช่น:

public class A {
    public class B {
    }
}

ในขณะที่คลาสที่ไม่ระบุชื่อเป็นส่วนขยายของคลาสที่กำหนดโดยไม่ระบุชื่อดังนั้นจึงไม่มีการกำหนดคลาส "ที่แท้จริงดังใน:

public class A {
}

A anon = new A() { /* you could change behavior of A here */ };

แก้ไขเพิ่มเติม:

Wikipedia อ้างว่ามีความแตกต่างใน Java แต่ฉันได้ทำงานกับ Java เป็นเวลา 8 ปีและเป็นครั้งแรกที่ฉันได้ยินความแตกต่างดังกล่าว ... ไม่ต้องพูดถึงไม่มีการอ้างอิงที่นั่นเพื่อสำรองข้อเรียกร้อง ... ด้านล่าง บรรทัดคลาสภายในเป็นคลาสที่กำหนดภายในคลาส (สแตติกหรือไม่) และซ้อนเป็นเพียงคำอื่นที่หมายถึงสิ่งเดียวกัน

มีความแตกต่างเล็กน้อยระหว่างคลาสแบบคงที่และแบบไม่คงที่ ... โดยทั่วไปคลาสภายในแบบคงที่มีการเข้าถึงโดยปริยายไปยังฟิลด์อินสแตนซ์และวิธีการของคลาสที่ปิดล้อม (ดังนั้นพวกเขาจึงไม่สามารถสร้างในบริบทแบบคงที่ได้ ข้อผิดพลาด) คลาสที่ซ้อนแบบคงที่ในทางกลับกันไม่มีการเข้าถึงฟิลด์อินสแตนซ์และวิธีการโดยนัยและสามารถสร้างในบริบทแบบสแตติก


3
ตามเอกสาร Java มีความแตกต่างระหว่างคลาสภายในและคลาสที่ซ้อนกัน - คลาสที่ซ้อนกันแบบสแตติกไม่มีการอ้างอิงถึงคลาสที่ปิดล้อมของพวกเขาและถูกใช้เป็นหลักเพื่อวัตถุประสงค์ขององค์กร คุณควรเห็นคำตอบของ Jegschemesch สำหรับคำอธิบายเชิงลึกเพิ่มเติม
mipadi

1
ฉันคิดว่าความแตกต่างทางความหมายเป็นประวัติศาสตร์ส่วนใหญ่ เมื่อฉันเขียนคอมไพเลอร์ C # -> Java 1.1 การอ้างอิงภาษา Java นั้นชัดเจนมาก: คลาสที่ซ้อนกันเป็นแบบสแตติกคลาสภายในไม่ได้ (และมี $ 0 นี้) ไม่ว่าด้วยอัตราใดก็ตามจะทำให้เกิดความสับสนและฉันก็ดีใจที่ไม่มีปัญหาอีกต่อไป
Tomer Gabel

2
JLS กำหนด "inner class" ในdocs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3และนั่นคือสาเหตุที่เป็นไปไม่ได้ที่จะมี "static" คลาส "ใน Java "ซ้อนกัน" ไม่ใช่ "แค่อีกคำหนึ่งที่หมายถึงสิ่งเดียวกัน" และไม่ใช่ความจริงที่ว่า "คลาสภายในเป็นคลาสที่กำหนดภายในคลาส (คงที่หรือไม่)" นั่นคือข้อมูลที่ไม่ถูกต้อง
Lew Bloch

6

การกำหนดเป้าหมายผู้เรียนซึ่งเป็นสามเณรไปยัง Java และ / หรือ Nested Classes

คลาสที่ซ้อนกันสามารถเป็นได้:
1. คลาสที่ซ้อนกันแบบคงที่
2. คลาสที่ไม่ซ้อนแบบคงที่ (เรียกอีกอย่างว่าคลาสภายใน ) => โปรดจดจำสิ่งนี้



1. ตัวอย่างชั้นเรียนภายใน :

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


คลาสภายในเป็นชุดย่อยของคลาสที่ซ้อนกัน:

  • คลาสภายในเป็นชนิดของคลาสที่ซ้อนกัน
  • คลาสภายในเป็นชุดย่อยของคลาสที่ซ้อนกัน
  • คุณสามารถพูดได้ว่าคลาสภายในเป็นคลาสที่ซ้อนกัน แต่คุณไม่สามารถพูดได้ว่าคลาสที่ซ้อนอยู่นั้นเป็นคลาสภายในด้วย

ความชำนาญพิเศษของชั้นใน:

  • อินสแตนซ์ของคลาสภายในมีการเข้าถึงสมาชิกทั้งหมดของคลาสภายนอกแม้แต่ผู้ที่ถูกทำเครื่องหมาย "ส่วนตัว"


2.Static Nested Classes:
ตัวอย่าง:

class EnclosingClass {
  static class Nested {
    void someMethod() { System.out.println("hello SO"); }
  }
}

กรณีที่ 1: การสร้างคลาสที่ซ้อนแบบคงที่จากคลาสที่ไม่ใช่การปิดล้อม

class NonEnclosingClass {

  public static void main(String[] args) {
    /*instantiate the Nested class that is a static
      member of the EnclosingClass class:
    */

    EnclosingClass.Nested n = new EnclosingClass.Nested(); 
    n.someMethod();  //prints out "hello"
  }
}

กรณีที่ 2: การสร้างคลาสที่ซ้อนแบบคงที่จากคลาสที่ล้อมรอบ

class EnclosingClass {

  static class Nested {
    void anotherMethod() { System.out.println("hi again"); } 
  }

  public static void main(String[] args) {
    //access enclosed class:

    Nested n = new Nested(); 
    n.anotherMethod();  //prints out "hi again"
  }

}

พิเศษเรียนคงที่:

  • คลาสภายในแบบสแตติกจะมีการเข้าถึงสมาชิกแบบคงที่ของคลาสภายนอกเท่านั้นและไม่สามารถเข้าถึงสมาชิกแบบคงที่ได้

สรุป:
คำถาม:อะไรคือความแตกต่างที่สำคัญระหว่างคลาสภายในและคลาสที่ซ้อนกันแบบคงที่ใน Java
คำตอบ:เพียงแค่ผ่านรายละเอียดเฉพาะของแต่ละชั้นเรียนที่กล่าวมา



6

คลาสภายในและคลาสสแตติกแบบซ้อนใน Java ทั้งคู่เป็นคลาสที่ประกาศภายในคลาสอื่นหรือที่เรียกว่าคลาสระดับบนสุดใน Java ในคำศัพท์ Java หากคุณประกาศคลาสที่ซ้อนกันแบบคงที่มันจะเรียกว่าคลาสแบบคงที่ซ้อนกันใน Java ในขณะที่คลาสที่ไม่ซ้อนแบบคงที่จะเรียกง่ายๆว่า Inner Class

Inner Class ใน Java คืออะไร

คลาสใด ๆ ที่ไม่ได้อยู่ในระดับบนสุดหรือถูกประกาศภายในคลาสอื่นจะเรียกว่าคลาสที่ซ้อนกันและคลาสที่ซ้อนกันเหล่านั้นคลาสที่ถูกประกาศว่าไม่ใช่สแตติกเรียกว่า Inner class ใน Java คลาสภายในมีสามชนิดใน Java:

1) Local class class - มีการประกาศในโค้ดบล็อกหรือเมธอด
2) Anonymous inner class - เป็นคลาสที่ไม่มีชื่อในการอ้างอิงและเริ่มต้นในที่เดียวกับที่มันถูกสร้างขึ้น
3) Member class class - ถูกประกาศว่าเป็นสมาชิกที่ไม่เปลี่ยนแปลงของคลาสภายนอก

public class InnerClassTest {
    public static void main(String args[]) {      
        //creating local inner class inside method i.e. main() 
        class Local {
            public void name() {
                System.out.println("Example of Local class in Java");

            }
        }      
        //creating instance of local inner class
        Local local = new Local();
        local.name(); //calling method from local inner class

        //Creating anonymous inner class in Java for implementing thread
        Thread anonymous = new Thread(){
            @Override
            public void run(){
                System.out.println("Anonymous class example in java");
            }
        };
        anonymous.start();

        //example of creating instance of inner class
        InnerClassTest test = new InnerClassTest();
        InnerClassTest.Inner inner = test.new Inner();
        inner.name(); //calling method of inner class
    }

     //Creating Inner class in Java
    private class Inner{
        public void name(){
            System.out.println("Inner class example in java");
        }
    }
}

คลาสแบบคงที่ซ้อนกันใน Java คืออะไร?

คลาสแบบคงที่ซ้อนกันเป็นคลาสอื่นซึ่งถูกประกาศภายในคลาสเป็นสมาชิกและสร้างเป็นแบบสแตติก คลาสแบบคงที่ซ้อนกันยังประกาศเป็นสมาชิกของคลาสภายนอกและสามารถทำให้เป็นส่วนตัวสาธารณะหรือได้รับการป้องกันเหมือนกับสมาชิกคนอื่น ๆ ประโยชน์หลักอย่างหนึ่งของคลาสสแตติกที่ซ้อนทับคลาสภายในคืออินสแตนซ์ของคลาสสแตติกที่ซ้อนกันไม่ได้ถูกแนบกับอินสแตนซ์ที่ล้อมรอบของคลาสภายนอก นอกจากนี้คุณยังไม่จำเป็นต้องมีตัวอย่างของการเรียนนอกใด ๆ ที่จะสร้างตัวอย่างของระดับคงที่ซ้อนกันในชวา

1) สามารถเข้าถึงสมาชิกข้อมูลคงที่ของคลาสภายนอกรวมถึงส่วนตัว
2) คลาสที่ซ้อนกันแบบคงที่ไม่สามารถเข้าถึงข้อมูลสมาชิกหรือวิธีการที่ไม่คงที่ (ตัวอย่าง)วิธีการ

public class NestedStaticExample {
    public static void main(String args[]){  
        StaticNested nested = new StaticNested();
        nested.name();
    }  
    //static nested class in java
    private static class StaticNested{
        public void name(){
            System.out.println("static nested class example in java");
        }
    }
}

Ref: Inner class และ Static Class ที่ซ้อนกันใน Java พร้อมตัวอย่าง


2
"คลาสที่ซ้อนกันแบบคงที่ไม่สามารถเข้าถึงสมาชิกหรือวิธีการข้อมูลที่ไม่คงที่ (ตัวอย่าง)" ไม่ถูกต้องและทำให้เกิดความสับสน พวกเขามีสิทธิ์เข้าถึงข้อมูลอินสแตนซ์ส่วนตัวอย่างแน่นอน - หากพวกเขาสร้างอินสแตนซ์เพื่อเข้าถึงข้อมูลอินสแตนซ์นั้น พวกเขาไม่มีอินสแตนซ์ที่ล้อมรอบเช่นคลาสภายใน แต่พวกเขามีสิทธิ์เข้าถึงสมาชิกส่วนตัวของอินสแตนซ์ของคลาสที่ล้อมรอบ
TJ Crowder

5

ฉันคิดว่าคนที่นี่ควรสังเกตกับ Poster ว่า: Static Nest Class เป็นเพียงแค่คลาสภายในเท่านั้น ตัวอย่างเช่น:

 public static class A {} //ERROR

 public class A {
     public class B {
         public static class C {} //ERROR
     }
 }

 public class A {
     public static class B {} //COMPILE !!!

 }

ดังนั้นสรุปชั้นคงที่ไม่ได้ขึ้นอยู่กับชั้นเรียนที่มี ดังนั้นพวกเขาไม่สามารถอยู่ในชั้นเรียนปกติได้ (เพราะคลาสปกติต้องการอินสแตนซ์)


2
ทั้งหมดนี้เป็นสิ่งที่ไม่ถูกต้อง ทั้งหมดนี้แสดงให้เห็นว่าชั้นในไม่สามารถมีระดับคงที่ ส่วนที่เกี่ยวกับ 'ไม่ขึ้นอยู่กับคลาสที่มีอยู่' นั้นไม่มีความหมายเช่นเดียวกับประโยคต่อไปนี้
user207421

5

เมื่อเราประกาศคลาสสมาชิกแบบสแตติกภายในคลาสนั้นจะเรียกว่าคลาสระดับซ้อนแบบบนสุดหรือคลาสแบบซ้อนแบบคงที่ มันสามารถแสดงให้เห็นดังต่อไปนี้:

class Test{
    private static int x = 1;
        static class A{
        private static int y = 2;
        public static int getZ(){
            return B.z+x;
        }
    }
    static class B{
        private static int z = 3;
        public static int getY(){
            return A.y;
        }
    }
}

class TestDemo{
     public static void main(String[] args){
        Test t = new Test();
        System.out.println(Test.A.getZ());
        System.out.println(Test.B.getY());
    }
}

เมื่อเราประกาศคลาสสมาชิกไม่คงที่ภายในคลาสนั้นจะเรียกว่าคลาสภายใน ชั้นในสามารถแสดงได้ดังต่อไปนี้:

    class Test{
        private int i = 10;
        class A{
            private int i =20;
            void display(){
            int i = 30;
            System.out.println(i);
            System.out.println(this.i);
            System.out.println(Test.this.i);
        }
    }
}

"เมื่อเราประกาศคลาสสมาชิกแบบสแตติกภายในคลาสนั้นเรียกว่าคลาสซ้อนระดับบนสุด"ที่ไม่สมเหตุสมผล " คลาสระดับบนสุดเป็นคลาสที่ไม่ใช่คลาสซ้อนกัน" ไม่มีสิ่งเช่น "ชั้นซ้อนระดับสูงสุด"
Radiodef

3

ต่อไปนี้เป็นตัวอย่างของstatic nested classและinner class :

OuterClass.java

public class OuterClass {
     private String someVariable = "Non Static";

     private static String anotherStaticVariable = "Static";  

     OuterClass(){

     }

     //Nested classes are static
     static class StaticNestedClass{
        private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable"; 

        //can access private variables declared in the outer class
        public static void getPrivateVariableofOuterClass(){
            System.out.println(anotherStaticVariable);
        }
     }

     //non static
     class InnerClass{

         //can access private variables of outer class
         public String getPrivateNonStaticVariableOfOuterClass(){
             return someVariable;
         }
     }

     public static void accessStaticClass(){
         //can access any variable declared inside the Static Nested Class 
         //even if it private
         String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable; 
         System.out.println(var);
     }

}

OuterClassTest:

public class OuterClassTest {
    public static void main(String[] args) {

        //access the Static Nested Class
        OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();

        //test the private variable declared inside the static nested class
        OuterClass.accessStaticClass();
        /*
         * Inner Class Test
         * */

        //Declaration

        //first instantiate the outer class
        OuterClass outerClass = new OuterClass();

        //then instantiate the inner class
        OuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();

        //test the non static private variable
        System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass()); 

    }

}

3

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

ให้เราดูที่ทั้งสองตัวอย่างต่อไปนี้

คลาสรังแบบสแตติก: ตัวอย่างที่ดีของการใช้คลาสที่ซ้อนแบบคงที่คือรูปแบบตัวสร้าง ( https://dzone.com/articles/design-patterns-the-builder-pattern )

สำหรับ BankAccount เราใช้คลาสที่ซ้อนกันคงที่ส่วนใหญ่เป็นเพราะ

  1. อินสแตนซ์คลาสรังแบบคงที่สามารถสร้างขึ้นก่อนที่ชั้นนอก

  2. ในรูปแบบตัวสร้างตัวสร้างเป็นคลาสตัวช่วยซึ่งใช้เพื่อสร้าง BankAccount

  3. BankAccount.Builder เชื่อมโยงกับ BankAccount เท่านั้น ไม่มีคลาสอื่น ๆ ที่เกี่ยวข้องกับ BankAccount.Builder ดังนั้นจึงเป็นการดีกว่าที่จะจัดระเบียบพวกเขาเข้าด้วยกันโดยไม่ใช้ชื่อแบบแผน
public class BankAccount {

    private long accountNumber;
    private String owner;
    ...

    public static class Builder {

    private long accountNumber;
    private String owner;
    ...

    static public Builder(long accountNumber) {
        this.accountNumber = accountNumber;
    }

    public Builder withOwner(String owner){
        this.owner = owner;
        return this; 
    }

    ...
    public BankAccount build(){
            BankAccount account = new BankAccount(); 
            account.accountNumber = this.accountNumber;
            account.owner = this.owner;
            ...
            return account;
        }
    }
}

คลาสภายใน: การใช้คลาสภายในทั่วไปเพื่อกำหนดตัวจัดการเหตุการณ์ https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html

สำหรับ MyClass เราใช้คลาสภายในเป็นหลักเนื่องจาก:

  1. คลาส Inner MyAdapter จำเป็นต้องเข้าถึงสมาชิกคลาสภายนอก

  2. ในตัวอย่าง MyAdapter จะเชื่อมโยงกับ MyClass เท่านั้น ไม่มีคลาสอื่น ๆ ที่เกี่ยวข้องกับ MyAdapter ดังนั้นจึงเป็นการดีกว่าที่จะจัดระเบียบพวกเขาเข้าด้วยกันโดยไม่ใช้ชื่อแบบแผน

public class MyClass extends Applet {
    ...
        someObject.addMouseListener(new MyAdapter());
    ...
    class MyAdapter extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            ...// Event listener implementation goes here...
            ...// change some outer class instance property depend on the event
        }
    }
}

2

แผนภาพ

ป้อนคำอธิบายรูปภาพที่นี่

ความแตกต่างที่สำคัญระหว่างstatic nestedและnon-static nestedคลาสคือstatic nested ไม่มีการเข้าถึงสมาชิกของคลาสภายนอกที่ไม่คงที่


0

ก่อนอื่นไม่มีคลาสดังกล่าวที่เรียกว่าคลาสคงที่ตัวดัดแปลงแบบคงที่ใช้กับคลาสภายใน (เรียกว่าคลาสที่ซ้อนกัน) บอกว่ามันเป็นสมาชิกแบบคงที่ของคลาสภายนอกซึ่งหมายความว่าเราสามารถเข้าถึงได้เช่นเดียวกับสมาชิกแบบคงที่อื่น ๆ ตัวอย่างของชั้นนอก (ซึ่งเป็นประโยชน์ของสแตติกเดิม)

ความแตกต่างระหว่างการใช้คลาสที่ซ้อนกันและคลาสภายในปกติคือ:

OuterClass.InnerClass inner = new OuterClass().new InnerClass();

ก่อนอื่นเราสามารถยกตัวอย่าง Outerclass จากนั้นเราสามารถเข้าถึง Inner

แต่ถ้า Class Nested แล้วไวยากรณ์คือ:

OuterClass.InnerClass inner = new OuterClass.InnerClass();

ซึ่งใช้ไวยากรณ์คงที่เป็นการใช้งานปกติของคำหลักคงที่


1
"... บอกว่ามันเป็นสมาชิกแบบคงที่ของ Outer Class ซึ่งหมายถึง .... ": มันไม่ถูกต้องที่จะคิดว่าระดับซ้อนแบบคงที่ในฐานะ "สมาชิกระดับ" ของ Outer Class แต่ความคล้ายคลึงกับเขตข้อมูลแบบคงที่และ วิธีการสิ้นสุดที่นั่น คลาสที่ซ้อนแบบคงที่ไม่ได้ "เป็น" ของคลาสภายนอก ในเกือบทุกด้านที่มีความสำคัญคลาสที่ซ้อนกันแบบคงที่เป็นคลาสระดับบนสุดที่ยืนซึ่งคำจำกัดความของคลาสได้ถูกซ้อนอยู่ในคลาสภายนอกเพื่อความสะดวกในการบรรจุภัณฑ์ (และหวังว่าเนื่องจากมีความสัมพันธ์เชิงตรรกะระหว่างคลาสที่ซ้อนกัน ... แม้ว่าจะไม่จำเป็นต้องมี)
กอ

1
'static Inner' เป็นข้อขัดแย้งในแง่ คลาสแบบสแตติกมีอยู่ที่ระดับการซ้อนแรกและไม่ใช่คลาสภายในโดยนิยาม สับสนมาก
user207421

0

ภาษาการเขียนโปรแกรม Java อนุญาตให้คุณกำหนดคลาสภายในคลาสอื่น คลาสดังกล่าวเรียกว่าคลาสซ้อนและแสดงไว้ที่นี่:

class OuterClass {
...
class NestedClass {
    ...
    }
}

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

OuterClass.StaticNestedClass nestedObject =
 new OuterClass.StaticNestedClass(); 

ในการสร้างอินสแตนซ์ของคลาสภายในคุณต้องสร้างอินสแตนซ์ของคลาสภายนอก จากนั้นสร้างวัตถุภายในภายในวัตถุภายนอกด้วยไวยากรณ์นี้:

OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();

ทำไมเราใช้คลาสที่ซ้อนกัน

  1. มันเป็นวิธีการจัดกลุ่มคลาสตรรกะที่ใช้ในที่เดียวเท่านั้น
  2. มันเพิ่มการห่อหุ้ม
  3. มันสามารถนำไปสู่รหัสที่อ่านได้และบำรุงรักษาได้มากกว่า

แหล่งที่มา: บทเรียน Java ™ - คลาสที่ซ้อนกัน


-1

ความแตกต่างคือการประกาศคลาสที่ซ้อนกันที่ยังคงสามารถยกตัวอย่างนอกคลาสที่ล้อมรอบ

เมื่อคุณมีการประกาศคลาสแบบซ้อนที่ไม่คงที่หรือที่เรียกว่าคลาสภายใน Java จะไม่อนุญาตให้คุณยกตัวอย่างยกเว้นผ่านคลาสที่ล้อมรอบ วัตถุที่สร้างจากคลาสภายในเชื่อมโยงกับวัตถุที่สร้างจากคลาสภายนอกดังนั้นคลาสภายในสามารถอ้างอิงฟิลด์ของภายนอก

แต่ถ้าเป็นแบบสแตติกลิงก์จะไม่มีอยู่ฟิลด์ด้านนอกไม่สามารถเข้าถึงได้ (ยกเว้นผ่านการอ้างอิงทั่วไปเช่นวัตถุอื่น ๆ ) และคุณสามารถสร้างอินสแตนซ์ของคลาสที่ซ้อนได้ด้วยตัวเอง


1
นี่เป็นเรื่องจริง มีไวยากรณ์พิเศษสำหรับการสร้างคลาสภายในภายนอกขอบเขตของคลาสที่ล้อมรอบ
user207421

-1

มันค่อนข้างง่าย, การเปรียบเทียบคลาสโลคัลสแตติกและคลาสภายในสแตติกไม่
ต่างกัน:
คลาสโลคัลสแตติก:
สามารถเข้าถึงสมาชิกแบบคงที่ของคลาสภายนอกเท่านั้น
ไม่สามารถมี initializers คงที่
ไม่สามารถเข้าถึงได้โดยตรงจากภายนอกฟังก์ชั่นที่ประกาศไว้


-2

ฉันได้แสดงสถานการณ์ที่ถูกต้องและผิดพลาดที่อาจเกิดขึ้นในโค้ดจาวา

    class Outter1 {

        String OutStr;

        Outter1(String str) {
            OutStr = str;
        }

        public void NonStaticMethod(String st)  {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            //  below static attribute not permitted
            // static String tempStatic1 = "static";    

            //  below static with final attribute not permitted         
            // static final String  tempStatic1 = "ashish";  

            // synchronized keyword is not permitted below          
            class localInnerNonStatic1 {            

                synchronized    public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /* 
        //  static method with final not permitted
          public static void innerStaticMethod(String str11) { 

                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }                            

        }

        public static  void StaticMethod(String st)     {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            // static attribute not permitted below
            //static String tempStatic1 = "static";     

            //  static with final attribute not permitted below
            // static final String  tempStatic1 = "ashish";                         

            class localInnerNonStatic1 {
                public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /*
    // static method with final not permitted
    public static void innerStaticMethod(String str11) {  
                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }    

        }

        // synchronized keyword is not permitted
        static  class inner1 {          

            static String  temp1 = "ashish";
            String  tempNonStatic = "ashish";
            // class localInner1 {

            public void innerMethod(String str11) {
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            public static void innerStaticMethod(String str11) {
                //  error in below step
                str11 = temp1 +" india";    
                //str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }
            //}
        }

        //synchronized keyword is not permitted below
        class innerNonStatic1 {             

//This is important we have to keep final with static modifier in non
// static innerclass below
            static final String  temp1 = "ashish";  
            String  tempNonStatic = "ashish";
            // class localInner1 {

            synchronized    public void innerMethod(String str11) {
                tempNonStatic = tempNonStatic +" ...";
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            /*
            //  error in below step
            public static void innerStaticMethod(String str11) {   
                            //  error in below step
                            // str11 = tempNonStatic +" india";                     
                            str11 = temp1 +" india";
                            System.out.println("innerMethod ===> "+str11);
                        }*/
                    //}
                }
    }

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