อะไรคือความแตกต่างที่สำคัญระหว่างคลาสภายในและคลาสที่ซ้อนกันแบบคงที่ใน Java การออกแบบ / การนำไปใช้มีบทบาทในการเลือกหนึ่งในสิ่งเหล่านี้หรือไม่?
อะไรคือความแตกต่างที่สำคัญระหว่างคลาสภายในและคลาสที่ซ้อนกันแบบคงที่ใน Java การออกแบบ / การนำไปใช้มีบทบาทในการเลือกหนึ่งในสิ่งเหล่านี้หรือไม่?
คำตอบ:
จากการสอน 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() { ... }
คือคลาสภายในที่กำหนดในบริบทแบบสแตติกและไม่มีอินสแตนซ์ล้อมรอบ
import OuterClass.StaticNestedClass;
แล้วอ้างอิงชั้นเพียงแค่เป็น OuterClass
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
หรือไม่?
คำศัพท์: คลาสที่ซ้อนกันแบ่งออกเป็นสองประเภท: แบบคงที่และไม่คงที่ คลาสที่ซ้อนกันที่ประกาศสแตติกเรียกง่ายๆว่าคลาสที่ซ้อนกันแบบสแตติก คลาสแบบซ้อนไม่คงที่เรียกว่าคลาสภายใน
ในการพูดจาทั่วไปคำว่า "ซ้อน" และ "ภายใน" ถูกใช้แทนกันโดยโปรแกรมเมอร์ส่วนใหญ่ แต่ฉันจะใช้คำที่ถูกต้อง "ชั้นซ้อน" ซึ่งครอบคลุมทั้งภายในและคงที่
คลาสสามารถเป็น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หรือระบุคอนสตรัคเตอร์ของตัวเองคุณจะติดกับการสร้างคลาสภายในชื่อปกติภายใน
ฉันไม่คิดว่าความแตกต่างที่แท้จริงนั้นชัดเจนในคำตอบข้างต้น
ก่อนอื่นจะได้รับเงื่อนไขที่ถูกต้อง:
คำตอบของ 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)
เพื่อความสมบูรณ์:
คลาสที่ไม่ระบุชื่อเป็นตัวอย่างที่สมบูรณ์แบบของคลาสที่ไม่ซ้อนแบบคงที่ซึ่งไม่มีชื่อเกี่ยวข้องและไม่สามารถอ้างอิงได้ในภายหลัง
ฉันคิดว่าคำตอบข้างต้นไม่สามารถอธิบายความแตกต่างที่แท้จริงระหว่างคลาสที่ซ้อนกันและคลาสที่ซ้อนกันแบบคงที่ในแง่ของการออกแบบแอปพลิเคชัน:
ชั้นซ้อนกันอาจจะ nonstatic หรือคงที่และในแต่ละกรณีเป็นชั้นเรียนที่กำหนดไว้ในชั้นอื่น คลาสที่ซ้อนกันควรมีอยู่เพื่อให้บริการเท่านั้นคือการปิดคลาสหากคลาสที่ซ้อนกันมีประโยชน์โดยคลาสอื่น (ไม่เพียง แต่การปิดล้อม) ควรประกาศเป็นคลาสระดับบนสุด
คลาส Nonstatic Nested : มีความสัมพันธ์โดยนัยกับอินสแตนซ์ที่ปิดล้อมของคลาสที่มีซึ่งหมายความว่าเป็นไปได้ที่จะเรียกใช้เมธอดและตัวแปรการเข้าถึงของอินสแตนซ์ที่ล้อมรอบ การใช้งานทั่วไปของคลาสที่ซ้อนกันแบบไม่คงที่คือการกำหนดคลาสอะแด็ปเตอร์
คลาสที่ซ้อนกันแบบคงที่ : ไม่สามารถเข้าถึงอินสแตนซ์ของคลาสที่ล้อมรอบและเรียกใช้เมธอดบนคลาสนั้นได้ดังนั้นควรใช้เมื่อคลาสที่ซ้อนกันไม่ต้องการการเข้าถึงอินสแตนซ์ของคลาสที่ล้อมรอบ การใช้คลาสที่ซ้อนกันแบบสแตติกทั่วไปคือการใช้ส่วนประกอบของวัตถุภายนอก
ดังนั้นความแตกต่างที่สำคัญระหว่างสองจากมุมมองการออกแบบคือชั้นที่ซ้อนกัน nonstatic สามารถเข้าถึงตัวอย่างของการเรียนภาชนะในขณะที่คงไม่สามารถ
ในแง่ง่ายเราต้องการคลาสที่ซ้อนกันเป็นหลักเนื่องจาก 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();
ข้อดีของคลาสที่ซ้อนกันแบบสแตติกก็คือมันไม่จำเป็นต้องมีวัตถุของคลาสที่มี / ชั้นบนเพื่อทำงาน สิ่งนี้สามารถช่วยคุณลดจำนวนวัตถุที่แอปพลิเคชันของคุณสร้างขึ้นขณะใช้งานจริง
OuterClass.Inner2 inner = outer.new Inner2();
อะไร
static inner
เป็นข้อขัดแย้งในแง่
นี่คือความแตกต่างที่สำคัญและความคล้ายคลึงกันระหว่างคลาสภายใน Java และคลาสที่ซ้อนกันแบบคงที่
หวังว่ามันจะช่วย!
เชื่อมโยงกับอินสแตนซ์ของคลาสที่ปิดล้อมเพื่อให้อินสแตนซ์ของคลาสแรกต้องใช้อินสแตนซ์ของคลาสภายนอก (หมายเหตุตำแหน่งคำหลักใหม่ ):
Outerclass.InnerClass innerObject = outerObject.new Innerclass();
ไม่สามารถกำหนดสมาชิกแบบคงที่ใด ๆเอง
ไม่สามารถเข้าถึงวิธีหรือฟิลด์อินสแตนซ์ของคลาสภายนอก
ไม่เกี่ยวข้องกับอินสแตนซ์ใด ๆ ของการปิดคลาสดังนั้นเพื่อยกตัวอย่าง:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
ตามเอกสารของ Oracle มีสาเหตุหลายประการ ( เอกสารฉบับเต็ม ):
มันเป็นวิธีของการจัดกลุ่มคลาสทางตรรกะที่ใช้ในที่เดียวเท่านั้น:ถ้าคลาสมีประโยชน์กับคลาสอื่นเพียงคลาสเดียวมันก็มีเหตุผลที่จะฝังไว้ในคลาสนั้นและเก็บทั้งสองไว้ด้วยกัน การซ้อน "คลาสผู้ช่วยเหลือ" ดังกล่าวทำให้แพ็คเกจของพวกเขาคล่องตัวขึ้น
มันเพิ่มการห่อหุ้ม:พิจารณาคลาสระดับบนสุดสองคลาสคือ A และ B โดยที่ B ต้องการเข้าถึงสมาชิกของ A ที่จะถูกประกาศเป็นส่วนตัว โดยการซ่อนคลาส B ภายในคลาส A สมาชิกของ A สามารถถูกประกาศเป็นส่วนตัวและ B สามารถเข้าถึงพวกเขาได้ นอกจากนี้ B สามารถซ่อนตัวจากโลกภายนอกได้
มันสามารถนำไปสู่รหัสที่อ่านได้และบำรุงรักษาได้มากกว่า: การซ้อนคลาสย่อยภายในคลาสระดับบนสุดจะวางโค้ดให้ใกล้กับตำแหน่งที่ใช้มากขึ้น
ฉันคิดว่าการประชุมที่ปฏิบัติตามโดยทั่วไปคือ:
อย่างไรก็ตามจุดอื่น ๆ ที่ควรจดจำคือ:
คลาสระดับบนสุดและคลาสที่ซ้อนกันแบบคงที่จะมีความหมายเหมือนกันยกเว้นว่าในกรณีของคลาสที่ซ้อนกันแบบคงที่สามารถทำการอ้างอิงแบบคงที่ไปยังฟิลด์ / เมธอดส่วนตัวแบบคงที่ของคลาส [parent] ด้านนอกและในทางกลับกัน
คลาสภายในมีการเข้าถึงตัวแปรอินสแตนซ์ของอินสแตนซ์ที่ล้อมรอบของคลาส Outer [parent] อย่างไรก็ตามคลาสภายในทั้งหมดไม่ได้มีอินสแตนซ์ล้อมรอบตัวอย่างเช่นคลาสภายในในบริบทสแตติกเช่นคลาสนิรนามที่ใช้ในบล็อก initializer แบบสแตติกไม่
คลาสนิรนามโดยดีฟอลต์จะขยายคลาสพาเรนต์หรือใช้อินเตอร์เฟสพาเรนต์และไม่มีส่วนคำสั่งเพิ่มเติมเพื่อขยายคลาสอื่นหรือใช้อินเตอร์เฟสเพิ่มเติมใด ๆ ดังนั้น,
new YourClass(){};
วิธี class [Anonymous] extends YourClass {}
new YourInterface(){};
วิธี class [Anonymous] implements YourInterface {}
ฉันรู้สึกว่าคำถามที่ใหญ่กว่าที่ยังคงเปิดซึ่งเป็นที่หนึ่งที่จะใช้และเมื่อใด ส่วนใหญ่ขึ้นอยู่กับสถานการณ์ที่คุณกำลังเผชิญอยู่ แต่การอ่านคำตอบที่ได้รับจาก @jrudolph อาจช่วยให้คุณตัดสินใจได้
คลาสแบบซ้อน: คลาสภายในคลาส
ประเภท:
ความแตกต่าง:
คลาสที่ซ้อนกันไม่คงที่ [คลาสภายใน]
ในวัตถุคลาสที่ซ้อนกันคงที่ของชั้นในมีอยู่ภายในวัตถุของชั้นนอก เพื่อให้สมาชิกข้อมูลของคลาสภายนอกสามารถเข้าถึงคลาสภายในได้ ดังนั้นในการสร้างวัตถุของชั้นในเราต้องสร้างวัตถุของชั้นนอกก่อน
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);
อินสแตนซ์ของคลาสภายในถูกสร้างขึ้นเมื่ออินสแตนซ์ของคลาสภายนอกถูกสร้างขึ้น ดังนั้นสมาชิกและวิธีการของชั้นในมีการเข้าถึงสมาชิกและวิธีการของอินสแตนซ์ (วัตถุ) ของชั้นนอก เมื่ออินสแตนซ์ของคลาสภายนอกออกนอกขอบเขตอินสแตนซ์ของคลาสภายในจะหยุดอยู่
คลาสซ้อนแบบคงที่ไม่มีอินสแตนซ์ที่เป็นรูปธรรม มันเพิ่งโหลดเมื่อใช้ครั้งแรก (เช่นเดียวกับวิธีการคงที่) มันเป็นเอนทิตี้อิสระอย่างสมบูรณ์ซึ่งวิธีการและตัวแปรไม่สามารถเข้าถึงอินสแตนซ์ของคลาสภายนอกได้
คลาสที่ซ้อนกันแบบสแตติกไม่ได้เชื่อมโยงกับวัตถุภายนอกพวกมันเร็วกว่าและไม่ใช้หน่วยความจำฮีป / สแต็กเพราะไม่จำเป็นต้องสร้างอินสแตนซ์ของคลาสดังกล่าว ดังนั้นกฎของหัวแม่มือคือพยายามกำหนดคลาสที่ซ้อนกันแบบคงที่โดยมีขอบเขต จำกัด เท่าที่จะเป็นไปได้ (ส่วนตัว> = คลาส> = ป้องกัน> = สาธารณะ) จากนั้นแปลงเป็นคลาสภายใน (โดยลบตัวระบุ "คงที่") ออก ขอบเขตถ้าจำเป็นจริงๆ
มีความละเอียดอ่อนเกี่ยวกับการใช้คลาสสแตติกที่ซ้อนอยู่ซึ่งอาจมีประโยชน์ในบางสถานการณ์
ในขณะที่สแตติกแอ็ตทริบิวต์รับอินสแตนซ์ก่อนที่คลาสจะถูกสร้างอินสแตนซ์ผ่านทางคอนสตรัคเตอร์ของสแตติกแอ็ตทริบิวต์ภายในของคลาสแบบคงที่ซ้อนกันดูเหมือนจะไม่เริ่มอินสแตนซ์จนกว่าจะ พวกเขาถูกทำเครื่องหมายเป็น 'ขั้นสุดท้าย'
ลองพิจารณาตัวอย่างนี้:
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
ข้อกำหนดนี้ใช้แทนกันได้ หากคุณต้องการพูดพล่อยๆเกี่ยวกับเรื่องนี้คุณสามารถกำหนด "คลาสที่ซ้อนกัน" เพื่ออ้างถึงคลาสภายในแบบสแตติกซึ่งไม่มีอินสแตนซ์ล้อมรอบ ในรหัสคุณอาจมีสิ่งนี้:
public class Outer {
public class Inner {}
public static class Nested {}
}
นั่นไม่ใช่คำจำกัดความที่ได้รับการยอมรับอย่างกว้างขวาง
ในกรณีของการสร้างอินสแตนซ์อินสแตนซ์ของคลาสภายในที่ไม่คงที่จะถูกสร้างขึ้นด้วยการอ้างอิงของวัตถุของคลาสภายนอกที่ถูกกำหนดไว้ ซึ่งหมายความว่ามันมีอินสแตนซ์ที่ปิดสนิท แต่อินสแตนซ์ของคลาสภายในแบบคงที่ถูกสร้างขึ้นด้วยการอ้างอิงของคลาสภายนอกไม่ใช่กับการอ้างอิงของวัตถุของคลาสภายนอก ซึ่งหมายความว่ามันไม่มีอินสแตนซ์ปิดบัง
ตัวอย่างเช่น:
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….
}
}
ฉันไม่คิดว่ามีอะไรเพิ่มที่นี่คำตอบส่วนใหญ่อธิบายความแตกต่างระหว่างคลาสที่ซ้อนกันแบบคงที่และคลาสภายในได้อย่างสมบูรณ์แบบ อย่างไรก็ตามพิจารณาปัญหาต่อไปนี้เมื่อใช้คลาสที่ซ้อนกันกับคลาสภายใน ตามที่ได้กล่าวในสองสามคำตอบเรียนภายในไม่สามารถ 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();
อืมมม ... ชั้นในเป็นคลาสซ้อนกัน ... คุณหมายถึงคลาสนิรนามและคลาสภายในหรือไม่
แก้ไข: ถ้าคุณหมายถึง 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 ปีและเป็นครั้งแรกที่ฉันได้ยินความแตกต่างดังกล่าว ... ไม่ต้องพูดถึงไม่มีการอ้างอิงที่นั่นเพื่อสำรองข้อเรียกร้อง ... ด้านล่าง บรรทัดคลาสภายในเป็นคลาสที่กำหนดภายในคลาส (สแตติกหรือไม่) และซ้อนเป็นเพียงคำอื่นที่หมายถึงสิ่งเดียวกัน
มีความแตกต่างเล็กน้อยระหว่างคลาสแบบคงที่และแบบไม่คงที่ ... โดยทั่วไปคลาสภายในแบบคงที่มีการเข้าถึงโดยปริยายไปยังฟิลด์อินสแตนซ์และวิธีการของคลาสที่ปิดล้อม (ดังนั้นพวกเขาจึงไม่สามารถสร้างในบริบทแบบคงที่ได้ ข้อผิดพลาด) คลาสที่ซ้อนแบบคงที่ในทางกลับกันไม่มีการเข้าถึงฟิลด์อินสแตนซ์และวิธีการโดยนัยและสามารถสร้างในบริบทแบบสแตติก
การกำหนดเป้าหมายผู้เรียนซึ่งเป็นสามเณรไปยัง 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
คำตอบ:เพียงแค่ผ่านรายละเอียดเฉพาะของแต่ละชั้นเรียนที่กล่าวมา
คลาสภายในและคลาสสแตติกแบบซ้อนใน 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 พร้อมตัวอย่าง
ฉันคิดว่าคนที่นี่ควรสังเกตกับ 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 !!!
}
ดังนั้นสรุปชั้นคงที่ไม่ได้ขึ้นอยู่กับชั้นเรียนที่มี ดังนั้นพวกเขาไม่สามารถอยู่ในชั้นเรียนปกติได้ (เพราะคลาสปกติต้องการอินสแตนซ์)
เมื่อเราประกาศคลาสสมาชิกแบบสแตติกภายในคลาสนั้นจะเรียกว่าคลาสระดับซ้อนแบบบนสุดหรือคลาสแบบซ้อนแบบคงที่ มันสามารถแสดงให้เห็นดังต่อไปนี้:
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);
}
}
}
ต่อไปนี้เป็นตัวอย่างของ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());
}
}
ฉันคิดว่าคำตอบข้างต้นไม่ได้ให้ตัวอย่างจริงแก่คุณถึงความแตกต่างระหว่างคลาสที่ซ้อนกันและคลาสที่ซ้อนกันแบบคงที่ในแง่ของการออกแบบแอปพลิเคชัน และความแตกต่างหลักระหว่างคลาสที่ซ้อนกันแบบคงที่และคลาสภายในคือความสามารถในการเข้าถึงฟิลด์อินสแตนซ์ของคลาสภายนอก
ให้เราดูที่ทั้งสองตัวอย่างต่อไปนี้
คลาสรังแบบสแตติก: ตัวอย่างที่ดีของการใช้คลาสที่ซ้อนแบบคงที่คือรูปแบบตัวสร้าง ( https://dzone.com/articles/design-patterns-the-builder-pattern )
สำหรับ BankAccount เราใช้คลาสที่ซ้อนกันคงที่ส่วนใหญ่เป็นเพราะ
อินสแตนซ์คลาสรังแบบคงที่สามารถสร้างขึ้นก่อนที่ชั้นนอก
ในรูปแบบตัวสร้างตัวสร้างเป็นคลาสตัวช่วยซึ่งใช้เพื่อสร้าง BankAccount
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 เราใช้คลาสภายในเป็นหลักเนื่องจาก:
คลาส Inner MyAdapter จำเป็นต้องเข้าถึงสมาชิกคลาสภายนอก
ในตัวอย่าง 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
}
}
}
แผนภาพ
ความแตกต่างที่สำคัญระหว่างstatic nested
และnon-static nested
คลาสคือstatic nested
ไม่มีการเข้าถึงสมาชิกของคลาสภายนอกที่ไม่คงที่
ก่อนอื่นไม่มีคลาสดังกล่าวที่เรียกว่าคลาสคงที่ตัวดัดแปลงแบบคงที่ใช้กับคลาสภายใน (เรียกว่าคลาสที่ซ้อนกัน) บอกว่ามันเป็นสมาชิกแบบคงที่ของคลาสภายนอกซึ่งหมายความว่าเราสามารถเข้าถึงได้เช่นเดียวกับสมาชิกแบบคงที่อื่น ๆ ตัวอย่างของชั้นนอก (ซึ่งเป็นประโยชน์ของสแตติกเดิม)
ความแตกต่างระหว่างการใช้คลาสที่ซ้อนกันและคลาสภายในปกติคือ:
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
ก่อนอื่นเราสามารถยกตัวอย่าง Outerclass จากนั้นเราสามารถเข้าถึง Inner
แต่ถ้า Class Nested แล้วไวยากรณ์คือ:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
ซึ่งใช้ไวยากรณ์คงที่เป็นการใช้งานปกติของคำหลักคงที่
ภาษาการเขียนโปรแกรม Java อนุญาตให้คุณกำหนดคลาสภายในคลาสอื่น คลาสดังกล่าวเรียกว่าคลาสซ้อนและแสดงไว้ที่นี่:
class OuterClass {
...
class NestedClass {
...
}
}
คลาสที่ซ้อนกันแบ่งออกเป็นสองหมวดหมู่: แบบคงที่และไม่คงที่ คลาสที่ซ้อนกันที่ถูกประกาศสแตติกเรียกว่าคลาสที่ซ้อนกันแบบสแตติก คลาสแบบซ้อนไม่คงที่เรียกว่าคลาสภายใน สิ่งหนึ่งที่เราควรจำไว้คือคลาสที่ซ้อนกันแบบไม่คงที่ (คลาสภายใน) สามารถเข้าถึงสมาชิกรายอื่นของคลาสที่ปิดล้อมแม้ว่าพวกเขาจะถูกประกาศเป็นส่วนตัว คลาสที่ซ้อนกันแบบสแตติกมีการเข้าถึงสมาชิกอื่นของคลาสที่ปิดล้อมเท่านั้น ไม่สามารถเข้าถึงสมาชิกที่ไม่ใช่สมาชิกของคลาสภายนอก เช่นเดียวกับวิธีการเรียนและตัวแปรระดับที่ซ้อนกันคงที่มีความเกี่ยวข้องกับชั้นนอกของมัน ตัวอย่างเช่นในการสร้างวัตถุสำหรับคลาสที่ซ้อนกันคงใช้ไวยากรณ์นี้:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
ในการสร้างอินสแตนซ์ของคลาสภายในคุณต้องสร้างอินสแตนซ์ของคลาสภายนอก จากนั้นสร้างวัตถุภายในภายในวัตถุภายนอกด้วยไวยากรณ์นี้:
OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
ทำไมเราใช้คลาสที่ซ้อนกัน
แหล่งที่มา: บทเรียน Java ™ - คลาสที่ซ้อนกัน
ความแตกต่างคือการประกาศคลาสที่ซ้อนกันที่ยังคงสามารถยกตัวอย่างนอกคลาสที่ล้อมรอบ
เมื่อคุณมีการประกาศคลาสแบบซ้อนที่ไม่คงที่หรือที่เรียกว่าคลาสภายใน Java จะไม่อนุญาตให้คุณยกตัวอย่างยกเว้นผ่านคลาสที่ล้อมรอบ วัตถุที่สร้างจากคลาสภายในเชื่อมโยงกับวัตถุที่สร้างจากคลาสภายนอกดังนั้นคลาสภายในสามารถอ้างอิงฟิลด์ของภายนอก
แต่ถ้าเป็นแบบสแตติกลิงก์จะไม่มีอยู่ฟิลด์ด้านนอกไม่สามารถเข้าถึงได้ (ยกเว้นผ่านการอ้างอิงทั่วไปเช่นวัตถุอื่น ๆ ) และคุณสามารถสร้างอินสแตนซ์ของคลาสที่ซ้อนได้ด้วยตัวเอง
มันค่อนข้างง่าย, การเปรียบเทียบคลาสโลคัลสแตติกและคลาสภายในสแตติกไม่
ต่างกัน:
คลาสโลคัลสแตติก:
สามารถเข้าถึงสมาชิกแบบคงที่ของคลาสภายนอกเท่านั้น
ไม่สามารถมี initializers คงที่
ไม่สามารถเข้าถึงได้โดยตรงจากภายนอกฟังก์ชั่นที่ประกาศไว้
ฉันได้แสดงสถานการณ์ที่ถูกต้องและผิดพลาดที่อาจเกิดขึ้นในโค้ดจาวา
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);
}*/
//}
}
}
item 22 : Favor static member classes over non static