ใน Java บางคลาสสามารถมีคลาสอื่นอยู่ภายในได้ คลาสดังกล่าวเรียกว่าคลาสที่ซ้อนกัน คลาสที่กำหนดภายในคลาสอื่นโดยทั่วไปจะแบ่งออกเป็นสองประเภท — แบบคงที่และไม่คงที่ คลาสที่ไม่คงที่แบบซ้อนกันเรียกว่าภายใน คลาสที่ซ้อนกันที่ถูกประกาศแบบคงที่เรียกว่าคลาสที่ซ้อนกันแบบคงที่ ในความเป็นจริงไม่มีอะไรซับซ้อนที่นี่แม้ว่าคำศัพท์จะดูค่อนข้างคลุมเครือและบางครั้งอาจทำให้นักพัฒนาซอฟต์แวร์มืออาชีพสับสนได้
คลาสที่ซ้อนกันและคลาสภายใน
ดังนั้นคลาสทั้งหมดที่อยู่ในคลาสอื่นจึงเรียกว่าคลาสที่ซ้อนกันclass OuterClass {
...
class NestedClass {
...
}
}
Nested Classes ที่ไม่คงที่เรียกว่าInner Classesและคลาสคงที่เรียกว่าNested Classes แบบคง ที่
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
ดังนั้น คลาสภายในทั้งหมดจึงซ้อนกัน แต่ไม่ใช่คลาสที่ซ้อนกันทั้งหมดจะเป็นคลาสภายใน นี่คือคำจำกัดความหลัก คลาสภายในเป็นกลไกการรักษาความปลอดภัยชนิดหนึ่งใน Java เรารู้ว่าคลาสธรรมดาไม่สามารถเชื่อมโยงกับตัวดัดแปลงการเข้าถึงส่วนตัวได้ อย่างไรก็ตาม หากคลาสของเราเป็นสมาชิกของคลาสอื่น คลาสภายในก็สามารถทำให้เป็นคลาสส่วนตัวได้ คุณลักษณะนี้ยังใช้เพื่อเข้าถึงสมาชิกชั้นเรียนส่วนตัวด้วย
ตัวอย่างชั้นภายใน
ดังนั้น เรามาลองสร้างคลาสขึ้นมาและภายในคลาสนั้นก็เป็นอีกคลาสหนึ่งกัน ลองนึกภาพคอนโซลเกมแบบโมดูลาร์บางประเภท มี "กล่อง" ในตัวและสามารถเชื่อมต่อโมดูลบางตัวเข้ากับมันได้ ตัวอย่างเช่นตัวควบคุมเกม, พวงมาลัย, หมวก VR ซึ่งตามกฎแล้วจะไม่ทำงานหากไม่มีคอนโซล ที่นี่เรามีคลาส GameConsole มี 2 ฟิลด์และ 1 วิธี — start( ) ความแตกต่างระหว่างGameCosoleและคลาสที่เราคุ้นเคยก็คือมันมีคลาส GameController ภายในpublic class GameConsole {
private String model;
private int weight;
public void run() {
System.out.println("Game console is on");
}
public class GameController {
private String color;
public void start() {
System.out.println("start button is pressed");
}
public void x() {
System.out.println("x button is pressed");
}
public void y() {
System.out.println("y button is pressed");
}
public void a() {
System.out.println("a button is pressed");
}
public void b() {
System.out.println("b button is pressed");
}
public void mover() {
System.out.println("mover button is pressed");
}
}
}
ณ จุดนี้ คุณอาจสงสัยว่า: ทำไมไม่ทำให้คลาสเหล่านี้ "แยกจากกัน"? ไม่จำเป็นต้องทำให้มันซ้อนกัน แท้จริงแล้วมันเป็นไปได้ แต่เป็นเรื่องเกี่ยวกับการออกแบบคลาสที่ถูกต้องในแง่ของการใช้งาน คลาสภายในถูกสร้างขึ้นเพื่อเน้นในโปรแกรมถึงเอนทิตีที่เชื่อมโยงกับเอนทิตีอื่นอย่างแยกไม่ออก ตัวควบคุมหรือหมวกกันน็อค VR เป็นต้น เป็นส่วนประกอบของคอนโซล ใช่ สามารถซื้อแยกต่างหากจากคอนโซลได้ แต่จะไม่สามารถใช้งานได้หากไม่มีคอนโซล ถ้าเราแยกคลาสเหล่านี้ออกจากคลาสสาธารณะ โปรแกรมของเราอาจมีโค้ดต่อไปนี้:
public class Main {
public static void main(String[] args) {
GameController controller = new GameController();
controller.x();
}
}
สิ่งที่เกิดขึ้นในกรณีนี้ยังไม่ชัดเจน เนื่องจากตัวควบคุมจะไม่ทำงานหากไม่มีคอนโซล เราได้สร้างวัตถุคอนโซลเกม เราได้สร้างวัตถุย่อยขึ้นมา — ตัวควบคุมเกม และตอนนี้เราก็เล่นได้แล้วเพียงกดปุ่มที่ถูกต้อง วิธีการที่เราต้องการถูกเรียกบนวัตถุที่ถูกต้อง ทุกอย่างเรียบง่ายและสะดวกสบาย ในตัวอย่างนี้ การแยกตัวควบคุมเกมจะช่วยเพิ่มการห่อหุ้ม (เราซ่อนรายละเอียดของส่วนคอนโซลภายในคลาสที่เกี่ยวข้อง) และช่วยให้สามารถสรุปรายละเอียดได้มากขึ้น แต่หากเราสร้างโปรแกรมจำลองร้านค้าที่คุณสามารถซื้อหมวกกันน็อคหรือคอนโทรลเลอร์ VR แยกต่างหาก ตัวอย่างนี้จะล้มเหลว จะดีกว่าถ้าสร้างตัวควบคุมเกมแยกกัน ลองมาอีกตัวอย่างหนึ่ง เราได้กล่าวไว้ข้างต้นว่าเราสามารถทำให้คลาสภายในเป็นส่วนตัวและยังคงเรียกมันจากคลาสภายนอกได้ ด้านล่างนี้เป็นตัวอย่างของคลาสดังกล่าว
class OuterClass {
// inner class
private class InnerClass {
public void print() {
System.out.println("We are in the inner class...");
}
}
// method of outer class. We are create an inner class from the method of outer one
void display() {
InnerClass inner = new InnerClass();
inner.print();
}
}
ในที่นี้OuterClassคือคลาสภายนอกInnerClassคือคลาสภายในdisplay()เป็นวิธีการภายในที่เรากำลังสร้างอ็อบเจ็กต์ของคลาสภายใน ตอนนี้เรามาเขียนคลาสสาธิตด้วยวิธีการหลักที่เราจะเรียกใช้เมธอดdisplay ()
public class OuterDemoMain {
public static void main(String args[]) {
// create an object of the outer class
OuterDemo outer = new OuterDemo();
outer.display();
}
}
หากคุณรันโปรแกรมนี้ คุณจะได้รับผลลัพธ์ดังต่อไปนี้:
เราอยู่ในชั้นเรียนชั้นใน...
การจำแนกชั้นเรียนภายใน
คลาสภายในนั้นเองหรือคลาสที่ไม่คงที่ที่ซ้อนกันแบ่งออกเป็นสามกลุ่ม- ชั้นในเหมือนเดิม มีเพียงคลาสที่ไม่คงที่เพียงคลาสเดียวภายในอีกคลาสหนึ่งดังที่เราสาธิตข้างต้นด้วยตัวอย่างGameConsoleและGameController
- คลาสภายในเมธอดท้องถิ่นเป็นคลาสภายในเมธอด
- คลาสภายในที่ไม่เปิดเผยตัวตน
วิธีการเรียนภายในท้องถิ่น
ใน Java คุณสามารถเขียนคลาสภายในเมธอดและเป็นประเภทในเครื่องได้ เช่นเดียวกับตัวแปรท้องถิ่น ขอบเขตของคลาสภายในถูกจำกัดภายในวิธีการ คลาสภายในของเมธอดท้องถิ่นสามารถสร้างขึ้นได้ภายในวิธีการที่กำหนดคลาสภายในเท่านั้น เรามาสาธิตวิธีการใช้เมธอดภายในคลาสกันpublic class OuterDemo2 {
//instance method of the outer class OuterDemo2
void myMethod() {
String str = "and it's a value from OuterDemo2 class' myMethod ";
// method-local inner class
class methodInnerDemo {
public void print() {
System.out.println("Here we've got a method inner class... " );
System.out.println(str);
}
}
// Access to the inner class
methodInnerDemo inn = new methodInnerDemo();
inn.print();
}
}
ตอนนี้เรากำลังจะเขียนคลาสสาธิตด้วย วิธี การหลักที่เราจะเรียกใช้เมธอดexternal()
public class OuterDemoMain {
public static void main(String args[]) {
OuterDemo2 outer = new OuterDemo2();
outer.myMethod();
}
}
ผลลัพธ์คือ:
ที่นี่เรามีเมธอดคลาสภายใน... และมันคือค่าจากคลาส OuterDemo2 'myMethod
ชนชั้นภายในที่ไม่เปิดเผยตัวตน
คลาสภายในที่ประกาศโดยไม่มีชื่อคลาสเรียกว่าคลาสภายในที่ไม่ระบุชื่อ เมื่อเราประกาศชนชั้นภายในที่ไม่เปิดเผยตัวตน เราจะยกตัวอย่างทันที โดยทั่วไปแล้ว คลาสดังกล่าวจะใช้เมื่อใดก็ตามที่คุณต้องการแทนที่คลาสหรือวิธีอินเทอร์เฟซabstract class OuterDemo3 {
public abstract void method();
}
class outerClass {
public static void main(String args[]) {
OuterDemo3 inner = new OuterDemo3() {
public void method() {
System.out.println("Here we've got an example of an anonymous inner class");
}
};
inner.method();
}
}
ผลลัพธ์อยู่ที่นี่:
เรามีตัวอย่างของชนชั้นภายในที่ไม่เปิดเผยตัวตน...
คลาสภายในที่ไม่เปิดเผยตัวตนเป็นข้อโต้แย้ง
คุณยังสามารถส่งคลาสภายในที่ไม่ระบุชื่อเป็นอาร์กิวเมนต์ไปยังเมธอดได้ นี่คือตัวอย่างinterface OuterDemo4 {
String hello();
}
class NewClass {
// accepts the object of interface
public void displayMessage(OuterDemo4 myMessage) {
System.out.println(myMessage.hello());
System.out.println("example of anonymous inner class as an argument");
}
public static void main(String args[]) {
NewClass newClass = new NewClass();
//here we pass an anonymous inner class as an argument
newClass.displayMessage(new OuterDemo4() {
public String hello() {
return "Hello!";
}
});
}
}
ผลลัพธ์อยู่ที่นี่:
สวัสดี! ตัวอย่างของชนชั้นภายในที่ไม่เปิดเผยตัวตนเป็นข้อโต้แย้ง
เพื่อเสริมสิ่งที่คุณเรียนรู้ เราขอแนะนำให้คุณชมบทเรียนวิดีโอจากหลักสูตร Java ของเรา
GO TO FULL VERSION