สวัสดีทุกคน. ในหัวข้อนี้ ฉันต้องการพูดโดยละเอียดเกี่ยวกับคลาส Java และประเภทของคลาสเหล่านั้น เพื่อช่วยให้ผู้เริ่มต้นเข้าใจหัวข้อนี้ และบางทีผู้ที่ไม่ใช่มือใหม่อาจเรียนรู้สิ่งใหม่ หากเป็นไปได้ ทุกอย่างจะแสดงโดยใช้ตัวอย่างในชีวิตจริงพร้อมตัวอย่างโค้ดประกอบ มาเริ่มกันเลย. และฉันต้องการทราบว่าสิ่งสำคัญคือการเข้าใจคลาสสองประเภทแรกและคลาสท้องถิ่นและไม่ระบุชื่อเป็นเพียงประเภทย่อยของคลาสภายใน
ชั้นเรียนคืออะไร?
คลาสคือคำอธิบายเชิงตรรกะของบางสิ่ง ซึ่งเป็นเทมเพลตที่คุณสามารถสร้างอินสแตนซ์ที่แท้จริงของสิ่งนั้นได้ กล่าวอีกนัยหนึ่ง มันเป็นเพียงคำอธิบายว่าเอนทิตีที่สร้างขึ้นควรเป็นอย่างไร: คุณสมบัติและวิธีการที่พวกเขาควรมี คุณสมบัติเป็นคุณลักษณะของเอนทิตีวิธีการคือการกระทำที่สามารถทำได้ ตัวอย่างที่ดีของคลาสจากชีวิตจริง ซึ่งช่วยให้เข้าใจว่าคลาสคืออะไร ถือได้ว่าเป็นภาพวาด: ภาพวาดใช้เพื่ออธิบายโครงสร้าง (หนังสติ๊ก, ไขควง) แต่ภาพวาดไม่ใช่การออกแบบ เช่นเดียวกับที่วิศวกรใช้พิมพ์เขียวเพื่อสร้างการออกแบบ การเขียนโปรแกรมใช้คลาสเพื่อสร้างวัตถุที่อธิบายคุณสมบัติและวิธีการpublic class Student {
private String name, group, specialty;
public Student(String name, String group, String specialty) {
this.name = name;
this.group = group;
this.specialty = specialty;
}
// getters/setters
}
ในตัวอย่างนี้ เราสร้างคลาส Java ที่อธิบายเอนทิตี "นักเรียน": นักเรียนแต่ละคนมีชื่อ กลุ่ม และความเชี่ยวชาญพิเศษ ตอนนี้ ที่อื่นๆ ในโปรแกรม เราสามารถสร้างตัวอย่างที่แท้จริงของคลาสนี้ได้ กล่าวอีกนัยหนึ่ง: ถ้าชั้นเรียนStudent
เป็นภาพที่นักเรียนควรจะเป็นอย่างไร ตัวอย่างที่สร้างขึ้นก็คือตัวนักเรียนจริงๆ ตัวอย่างการสร้างนักเรียนใหม่: new Student("Ivan", "KI-17-2", "Computer Engineering");
ตัวดำเนินการnew
ค้นหาชั้นเรียนStudent
แล้วเรียกเมธอดพิเศษ (ตัวสร้าง) ของคลาสนี้ ตัวสร้างส่งคืนวัตถุคลาสสำเร็จรูปStudent
- นักเรียนที่รักและหิวโหยของเราโดยไม่มีทุน :))
ประเภทของคลาสใน Java
ใน Java มีคลาสอยู่ 4 ประเภทภายในคลาสอื่น:-
คลาสภายในที่ซ้อนกันเป็นคลาสที่ไม่คงที่ภายในคลาสภายนอก
-
คลาสสแตติกที่ซ้อนกันเป็นคลาสสแตติกภายในคลาสภายนอก
-
คลาสท้องถิ่น Javaเป็นคลาสภายในวิธีการ
-
คลาส Java ที่ไม่ระบุชื่อเป็นคลาสที่สร้างขึ้นทันที
คลาสที่ไม่คงที่ภายในคลาสภายนอก
ก่อนอื่น ฉันอยากให้คุณเข้าใจว่าสิ่งนี้คืออะไรพร้อมตัวอย่างจริง เพราะมันทำให้เข้าใจได้ง่ายขึ้นมาก ตอนนี้เราจะแยกย่อยสิ่งที่ยิ่งใหญ่จริงๆ ออกเป็นส่วนประกอบเล็กๆ และเราจะแยกชิ้นส่วนเครื่องบิน! อย่างไรก็ตาม เพื่อเป็นตัวอย่าง ก็เพียงพอที่จะแสดงให้เห็นเพียงเล็กน้อย เราจะไม่แยกย่อยให้หมด เพื่อให้เห็นภาพกระบวนการนี้ เราจะใช้แผนภาพเครื่องบิน ขั้นแรก เราต้องสร้างคลาสAirplane
ที่เราสามารถเพิ่มคำอธิบายเล็กๆ น้อยๆ ได้: ชื่อเครื่องบิน รหัสประจำตัว เที่ยวบิน
public class Airplane {
private String name, id, flight;
public Airplane(String name, String id, String flight) {
this.name = name;
this.id = id;
this.flight = flight;
}
// getters/setters
}
ตอนนี้เราต้องการเพิ่มปีก สร้างคลาสแยกกันเหรอ? บางทีนี่อาจเป็นตรรกะถ้าเรามีโปรแกรมที่ซับซ้อนสำหรับการออกแบบเครื่องบินและที่ที่เราจำเป็นต้องสร้างคลาสที่ได้รับมาจำนวนมาก (คลาสที่มีตรรกะเหมือนกับคลาสพาเรนต์นั่นคือคลาสที่สืบทอดมา แต่ ดังนั้นพวกเขาจึงขยายคลาสพาเรนต์โดยการเพิ่มตรรกะหรือคุณลักษณะที่มีรายละเอียดมากขึ้น) แต่จะเกิดอะไรขึ้นถ้าเรามีเกมที่มีเครื่องบินเพียงลำเดียว? จากนั้นจะมีเหตุผลมากขึ้นสำหรับเราที่จะทำโครงสร้างทั้งหมดให้เสร็จสิ้นในที่เดียว (ในคลาสเดียว) นี่คือจุดที่คลาสที่ซ้อนกันแบบไม่คงที่เข้ามามีบทบาท โดยพื้นฐานแล้ว นี่เป็นคำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับรายละเอียดบางส่วนของคลาสภายนอกของเรา ในตัวอย่างนี้ เราต้องสร้างปีกสำหรับเครื่องบินทั้งซ้ายและขวา มาสร้างกันเถอะ!
public class Airplane {
private String name, id, flight;
private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");
public Airplane(String name, String id, String flight) {
this.name = name;
this.id = id;
this.flight = flight;
}
private class Wing {
private String color, model;
private Wing(String color, String model) {
this.color = color;
this.model = model;
}
// getters/setters
}
// getters/setters
}
ดังนั้นเราจึงสร้างคลาส (ปีก) ที่ไม่คงที่Wing
ภายในคลาสAirplane
(เครื่องบิน) และเพิ่มตัวแปรสองตัว - ปีกซ้ายและปีกขวา และแต่ละปีกก็มีคุณสมบัติของตัวเอง (สี, รุ่น) ที่เราสามารถเปลี่ยนได้ วิธีนี้ทำให้คุณสามารถจัดวางโครงสร้างได้มากเท่าที่คุณต้องการ และหมายเหตุ: ก่อนหน้านี้บนแผนภาพมีชิ้นส่วนของเครื่องบินค่อนข้างมาก และในความเป็นจริง เราสามารถแบ่งชิ้นส่วนทั้งหมดออกเป็นคลาสภายในได้ แต่กระบวนการดังกล่าวไม่แนะนำให้เลือกเสมอไป จำเป็นต้องติดตามช่วงเวลาดังกล่าวขึ้นอยู่กับงาน คุณอาจไม่จำเป็นต้องใช้ปีกเลยในการแก้ปัญหา จากนั้นก็ไม่จำเป็นต้องทำ มันเหมือนกับการตัดคนเป็นขา แขน ลำตัว และศีรษะ เป็นไปได้ แต่ทำไมถ้าคลาสนี้ใช้เพื่อเก็บข้อมูลเกี่ยวกับผู้คนเท่านั้น คุณลักษณะของคลาส Java ที่ซ้อนกันแบบไม่คงที่:
- พวกมันมีอยู่ในวัตถุเท่านั้น ดังนั้นเพื่อสร้างพวกมันคุณต้องมีวัตถุ กล่าวอีกนัยหนึ่ง: เราออกแบบปีกของเราให้เป็นส่วนหนึ่งของเครื่องบิน ดังนั้นเพื่อสร้างปีกเราจำเป็นต้องมีเครื่องบิน ไม่เช่นนั้นเราก็ไม่ต้องการมัน
- ไม่สามารถมีตัวแปรคงที่ภายในคลาส Java หากคุณต้องการค่าคงที่หรือค่าคงที่ คุณจะต้องย้ายพวกมันไปยังคลาสภายนอก นี่เป็นเพราะการเชื่อมต่อที่ใกล้ชิดของคลาสที่ซ้อนกันแบบไม่คงที่กับคลาสภายนอก
- คลาสมีสิทธิ์เข้าถึงฟิลด์ส่วนตัวทั้งหมดของคลาสภายนอกได้อย่างเต็มที่ คุณลักษณะนี้ทำงานได้สองวิธี
- คุณสามารถรับการอ้างอิงถึงอินสแตนซ์ของคลาสภายนอกได้ ตัวอย่าง: เครื่องบิน นี่คือลิงก์ไปยังเครื่องบิน นี่คือลิงก์ไปยังปีก
คลาสแบบคงที่ภายในคลาสภายนอก
คลาสประเภทนี้ไม่แตกต่างจากคลาสภายนอกทั่วไป ยกเว้นสิ่งหนึ่ง: เพื่อสร้างอินสแตนซ์ของคลาสดังกล่าว คุณจะต้องแสดงรายการเส้นทางทั้งหมดจากคลาสภายนอกไปยังคลาสที่ต้องการ โดยคั่นด้วยจุด ตัวอย่างเช่น:Building.Plaftorm platform = new Building.Platform();
คลาสแบบคงที่ใช้เพื่อวางคลาสที่เกี่ยวข้องไว้เคียงข้างกัน เพื่อให้โครงสร้างเชิงตรรกะทำงานได้ง่ายขึ้น ตัวอย่างเช่น: เราสามารถสร้างคลาสภายนอกBuilding
โดยที่จะมีรายการคลาสเฉพาะที่จะแสดงถึงสิ่งปลูกสร้างเฉพาะ
public abstract class Building {
private String name, address, type;
Building(String name, String address) {
this.name = name;
this.address = address;
}
public static class Platform extends Building {
public Platform(String name, String address) {
super(name, address);
setType("Platform");
}
// some additional logic
}
public static class House extends Building {
public House(String name, String address) {
super(name, address);
setType("House");
}
// some additional logic
}
public static class Shop extends Building {
public Shop(String name, String address) {
super(name, address);
setType("Shop");
}
// some additional logic
}
// getters/setters
}
ตัวอย่างนี้แสดงให้เห็นว่าคลาสแบบสแตติกช่วยให้คุณสามารถจัดทำโครงสร้างเชิงตรรกะในรูปแบบที่สะดวกยิ่งขึ้นได้อย่างไร หากไม่มีอยู่ เราจะต้องสร้าง 4 คลาสที่แตกต่างกันโดยสิ้นเชิง ข้อดีของแนวทางนี้:
- จำนวนชั้นเรียนลดลง
- ชั้นเรียนทั้งหมดอยู่ภายในชั้นเรียนหลัก เราสามารถติดตามลำดับชั้นทั้งหมดได้โดยไม่ต้องเปิดแต่ละคลาสแยกกัน
- เราสามารถอ้างถึงคลาส Building และ IDE จะแจ้งรายการคลาสย่อยทั้งหมดของคลาสนี้แล้ว ซึ่งจะทำให้ค้นหาชั้นเรียนที่คุณต้องการได้ง่ายขึ้นและแสดงภาพรวมแบบองค์รวมมากขึ้น
Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”);
ฉันอยากจะทราบด้วยว่ากลยุทธ์นี้ใช้ในคลาส AWT 2D เพื่ออธิบายรูปร่าง เช่น Line2D, Arc2D, Ellipse2D และอื่นๆ
ชั้นเรียนในท้องถิ่น
คลาสเหล่านี้ถูกประกาศภายในวิธีอื่น ในความเป็นจริง พวกเขามีคุณสมบัติทั้งหมดของคลาสที่ซ้อนกันแบบไม่คงที่ มีเพียงคุณเท่านั้นที่สามารถสร้างอินสแตนซ์ของพวกเขาในเมธอดเท่านั้น และวิธีการนั้นไม่สามารถคงที่ได้ (ในการสร้างคลาสเหล่านั้น คุณต้องมีอินสแตนซ์ของคลาสภายนอก การอ้างอิงถึง อินสแตนซ์ของออบเจ็กต์ที่เรียกจะถูกส่งผ่านไปยังวิธีที่ไม่คงที่โดยปริยาย และในวิธีคงที่จะไม่มีวิธีการสำหรับลิงก์นี้) แต่พวกเขามีลักษณะเฉพาะของตัวเอง:- คลาสท้องถิ่นสามารถทำงานได้กับตัวแปรเมธอดสุดท้ายเท่านั้น ประเด็นก็คืออินสแตนซ์ของคลาสโลคัลสามารถเก็บไว้ในฮีปได้หลังจากที่เมธอดเสร็จสิ้น และสามารถลบตัวแปรได้ หากตัวแปรถูกประกาศเป็นขั้นสุดท้าย คอมไพลเลอร์สามารถบันทึกสำเนาของตัวแปรเพื่อใช้ในภายหลังโดยอ็อบเจ็กต์ได้ และอีกอย่างหนึ่ง: เนื่องจาก Java เวอร์ชัน 8+ ขึ้นไป คุณสามารถใช้ตัวแปรที่ไม่ใช่ตัวแปรสุดท้ายในคลาสโลคัลได้ แต่จะมีเงื่อนไขว่าจะไม่เปลี่ยนแปลง
- ไม่สามารถประกาศคลาสท้องถิ่นด้วยตัวดัดแปลงการเข้าถึง
- คลาสท้องถิ่นสามารถเข้าถึงตัวแปรเมธอดได้
Person
(จะถือว่านี่คือบุคคล) ที่มีคุณสมบัติstreet
(ถนน) house
(บ้าน) เราต้องการคืนวัตถุบางอย่างเพื่อเข้าถึงเฉพาะตำแหน่งของบุคคลนั้น ในการดำเนินการนี้ เราได้สร้างอินเทอร์เฟซ AddressContainer ซึ่งหมายถึงการจัดเก็บข้อมูลเกี่ยวกับตำแหน่งของบุคคล
public class Person {
private String name, street, house;
public Person(String name, String street, String house) {
this.name = name;
this.street = street;
this.house = house;
}
private interface AddressContainer {
String getStreet();
String getHouse();
}
public AddressContainer getAddressContainer() {
class PersonAddressContainer implements AddressContainer {
final String street = Person.this.street, house = Person.this.house;
@Override
public String getStreet() {
return this.street;
}
@Override
public String getHouse() {
return this.house;
}
}
return new PersonAddressContainer();
}
public static void main(String[] args) {
Person person = new Person("Nikita", "Sholohova", "17");
AddressContainer address = person.getAddressContainer();
System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
}
// getters/setters
}
อย่างที่คุณเห็น ภายในวิธีการที่เราสร้างคลาสที่ใช้การจัดเก็บตำแหน่งของบุคคล สร้างตัวแปรคงที่ที่นั่น (เพื่อที่ว่าหลังจากออกจากวิธีการแล้ว ตัวแปรจะถูกเก็บไว้ในวัตถุ) และใช้วิธีในการรับที่อยู่และ บ้าน. ตอนนี้เราสามารถใช้วัตถุนี้ในตำแหน่งอื่นในโปรแกรมเพื่อรับตำแหน่งของบุคคลได้ ฉันเข้าใจว่าตัวอย่างนี้ไม่เหมาะและมันจะถูกต้องมากกว่าหากทำเพียงแค่ปล่อย getters ไว้ในคลาสPerson
อย่างไรก็ตาม มีการแสดงการสร้างคลาสนี้และการใช้งานที่เป็นไปได้ และจากนั้นก็ขึ้นอยู่กับคุณ
ชั้นเรียนที่ไม่ระบุชื่อ
ภายใต้ประทุน คลาสที่ไม่ระบุตัวตนเป็นเพียงคลาสที่ซ้อนกันแบบไม่คงที่ทั่วไป ลักษณะเฉพาะของพวกเขาคือใช้งานง่าย คุณสามารถเขียนชั้นเรียนของคุณได้โดยตรงเมื่อสร้างอินสแตนซ์ของชั้นเรียนอื่นpublic class Animal {
public void meow() {
System.out.println("Meow!");
}
public static void main(String[] args) {
Animal anonTiger = new Animal() {
@Override
public void meow() {
System.out.println("Raaar!");
}
};
Animal notAnonTiger = new Animal().new Tiger();
anonTiger.meow(); // будет выведено Raaar!
notAnonTiger.meow(); // будет выведено Raaar!
}
private class Tiger extends Animal {
@Override
public void meow() {
System.out.println("Raaar!");
}
}
}
โดยพื้นฐานแล้ว เราเพียงแค่รวมสองสิ่งไว้ในที่เดียว: การสร้างอินสแตนซ์ของคลาสเดียว ( Animal
) และการสร้างอินสแตนซ์ของคลาสภายในที่สืบทอด ( Tiger
) มิฉะนั้น เราจำเป็นต้องสร้างคลาสแยกกัน และใช้โครงสร้างที่ยาวกว่าเพื่อให้ได้ผลลัพธ์เดียวกัน การใช้คลาสที่ไม่เปิดเผยตัวตนเป็นสิ่งที่สมเหตุสมผลในหลายกรณี โดยเฉพาะอย่างยิ่งเมื่อ:
- เนื้อหาของชั้นเรียนสั้นมาก
- จำเป็นต้องมีอินสแตนซ์เดียวของคลาสเท่านั้น
- คลาสถูกใช้ ณ สถานที่ที่สร้างขึ้นหรือหลังจากนั้นทันที
- ชื่อคลาสไม่สำคัญและไม่ทำให้โค้ดเข้าใจง่ายขึ้น
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Кнопка нажата!");
}
});
อย่างไรก็ตาม หลังจาก Java 8 พวกเขาเริ่มใช้นิพจน์แลมบ์ดา แต่ยังคงมีการเขียนโค้ดจำนวนมากก่อนเวอร์ชัน 8 และคุณอาจพบคำจารึกดังกล่าว (และจะพบระหว่างการฝึกของคุณใน JavaRush)\ อะนาล็อก กับแลมบ์ดา:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
ท้ายบทความ ขอขอบคุณทุกท่านที่ให้ความสนใจและหวังว่าคุณจะได้เรียนรู้สิ่งใหม่ ๆ หรือเข้าใจสิ่งที่คุณไม่เคยเข้าใจมาก่อน ฉันขอชี้แจงด้วยว่าบทความนี้อยู่ใน หมวดหมู่ "ความ ใส่ใจในรายละเอียด" นี่เป็นงานแรกของฉันดังนั้นฉันหวังว่าจะเป็นประโยชน์กับใครบางคน ในอนาคตอันใกล้นี้เมื่อมีไอเดียใหม่ๆ เกิดขึ้น ฉันจะพยายามเขียนอย่างอื่น ฉันมีไอเดียเดียว... ขอให้ทุกคนโชคดีและประสบความสำเร็จในการเขียนโปรแกรม :)
GO TO FULL VERSION