
“สวัสดี อามีโก้!”
"แต่เราได้กล่าวสวัสดีแล้ว Ellie!"
“เฮ้ อย่าเถียงกับป้าของคุณ ในศตวรรษที่ 31 ถ้าคุณไม่ได้เจอใครนานกว่าครึ่งชั่วโมง มันเป็นธรรมเนียมที่จะต้องทักทายอีกครั้ง ดังนั้นอย่าบอกทัศนคติของคุณกับฉัน!”
"อย่างไรก็ตาม ถึงเวลาสำหรับหัวข้อที่น่าสนใจอื่น: การสืบพันธุ์ของหุ่นยนต์!"
"O_O"
"ล้อเล่น หัวข้อใหม่คือคลาสภายในนิรนาม "
"ใน Java บางครั้งมีบางสถานการณ์ที่คุณต้องใช้คลาสเพื่อสืบทอดหลายคลาส เนื่องจาก Java ไม่รองรับการสืบทอดหลายรายการ พวกเขาได้แก้ปัญหานี้โดยใช้คลาสภายใน: ในคลาสของเรา เราประกาศคลาสภายในและสร้าง มันสืบทอดคลาสที่เราต้องการให้สืบทอด นี่คือตัวอย่าง:"
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
TigerThread thread = new TigerThread();
thread.start();
}
class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
"ลองมาดูตัวอย่างอื่น:"
เราต้องการคลาสย่อยของคลาสเธรดเพื่อแทนที่เมธอดรันของมัน"
"นั่นคือเหตุผลที่ในคลาส Tiger เราประกาศ คลาสภายใน TigerThreadซึ่งสืบทอด Thread และแทนที่เมธอดการรัน
"เพื่อความสะดวก เราได้กำหนดสองเมธอดในคลาส Tiger: tigerRun และ startTiger (ซึ่งคล้ายกับเมธอด run และ start ของ Thread"
"ในเมธอด tigerStart เราสร้าง ออบเจกต์ TigerThreadและเรียกใช้เมธอด start()"
"JVM จะสร้างเธรดใหม่ที่จะเริ่มทำงานเมื่อมีการเรียกใช้เมธอดของ TigerThread "
"เมธอดนี้เรียก เมธอด run ของเรา : tigerRun "
"ฉันเคยทำงานกับเธรดมาก่อน ดังนั้นสิ่งนี้จึงดูตรงไปตรงมา"
"เราต้องตั้งชื่อเมธอด tigerRun และ tigerStart หรือไม่"
"ไม่ เราอาจเรียกมันว่า run and start แต่ฉันก็อยากแสดงให้เห็นว่าเราไม่ได้สืบทอด Thread คำอธิบายอาจทำให้สับสนมากกว่านี้"
"ตกลง ถ้าอย่างนั้นฉันคิดว่าฉันเข้าใจแล้ว แต่ถ้ามีการเรียก tigerStart เป็นครั้งที่สอง เราจะสร้างและเริ่มวัตถุเธรดที่สอง นั่นไม่ได้หมายความว่าเราจะมี «เสือตัวหนึ่งทำงานบนเธรดที่แตกต่างกันสองเธรด» "
"คุณไม่เฉียบแหลมเหรอ! คุณพูดถูกและนั่นไม่ดี มาเขียนโค้ดใหม่ดังนี้:"
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
thread.start();
}
private TigerThread thread = new TigerThread();
private class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
"มันยังไม่สมบูรณ์แบบ คุณยังไม่สามารถเรียกใช้เมธอดแบบนั้นซ้ำได้ แต่ครั้งนี้ อย่างน้อยเราจะไม่สร้างเธรดที่สองและทำให้ดูเหมือนว่าทุกอย่างเรียบร้อยดี"
"ถูกต้อง ครั้งที่สองที่เสือออกสตาร์ท คุณจะได้รับข้อยกเว้น"
"ฉันจับผิดได้ดีกว่าเธอแล้ว เอลลี่!"
"ใช่ คุณทำได้ดีมาก ถ้าอย่างนั้นเรามาเข้าคลาสภายในที่ไม่ระบุตัวตนกันเถอะ"
"หมายเหตุหลาย ๆ แง่มุมของโค้ดด้านบน:"
1)เราสืบทอดคลาสเธรด แต่ไม่มีการนำโค้ดไปใช้จริง "มันเป็น «เราต้องสืบทอดคลาสเธรด» มากกว่า «เราสืบทอดมาเพื่อขยาย»
2)จะมีการสร้างวัตถุ TigerThread เพียงรายการเดียวเท่านั้น
กล่าวอีกนัยหนึ่ง เราเขียนโค้ดทั้งหมดเพื่อแทนที่เมธอดหนึ่งและสร้างออบเจกต์หนึ่ง
คุณจำได้ไหมว่าฉันพูดถึงการประดิษฐ์คอนสตรัคเตอร์ได้อย่างไร?
ก่อนที่ตัวสร้าง | หลังจากตัวสร้าง |
---|---|
|
|
"ฉันเห็นว่าโค้ดกระชับขึ้น แต่ฉันไม่ค่อยเข้าใจว่าเกิดอะไรขึ้น"
"เราสามารถรวมสี่สิ่งเป็นหนึ่งเดียว:"
1) การประกาศคลาสที่ได้รับ
2) การเอาชนะวิธีการ
3) การประกาศตัวแปร
4) การสร้างอินสแตนซ์ของคลาสที่ได้รับ
"อันที่จริง สิ่งที่เรากำลังทำคือการรวมการดำเนินการสองอย่างเข้าด้วยกัน: การประกาศคลาสที่ได้รับมา และสร้างอินสแตนซ์ของคลาสนั้น"
ไม่มีคลาสนิรนาม | ด้วยคลาสที่ไม่ระบุชื่อ |
---|---|
|
|
"มาสำรวจไวยากรณ์กันอีกครั้ง:"
Thread thread = new Thread();
Thread thread = new Thread()
{
};
"โปรดทราบว่าเราไม่ได้แค่กำหนดคลาสใหม่เท่านั้น เรากำลังสร้างตัวแปร—มีเครื่องหมายอัฒภาคต่อท้าย!"
"และหากเราต้องการแทนที่เมธอดการรัน เราต้องเขียนสิ่งนี้:"
Thread thread = new Thread()
{
public void run()
{
System.out.println("new run-method");
}
};
“คุณตามไปเร็ว ทำได้ดีมาก!”
"ขอบคุณ ถ้าเราต้องการเมธอดอื่นที่ไม่ได้เป็นส่วนหนึ่งของคลาสเธรดล่ะ"
"คุณสามารถเขียนได้"
"แม้ว่าจะไม่เปิดเผยตัวตน แต่นี่คือชนชั้นภายในที่เต็มเปี่ยม:"
รหัสจาวา | คำอธิบาย |
---|---|
|
สีแดง: รหัสสำหรับสร้างตัวแปร
สีเขียว: รหัสสำหรับสร้างวัตถุ สีน้ำเงิน: รหัสสำหรับคลาสที่ได้มาแบบไม่ระบุชื่อ |
"ชั้นในเต็มเปี่ยม?"
"ฉันสามารถใช้ตัวแปรของชั้นนอกได้หรือไม่"
"อย่างแน่นอน."
"และฉันสามารถส่งบางอย่างให้กับตัวสร้างได้หรือไม่"
"ใช่ แต่เฉพาะอาร์กิวเมนต์สำหรับคอนสตรัคเตอร์ของซูเปอร์คลาสเท่านั้น:"
ระดับ | ตัวอย่างของคลาสภายในที่ไม่ระบุชื่อ |
---|---|
|
|
"เราไม่สามารถเพิ่มพารามิเตอร์ของเราเองให้กับคอนสตรัคเตอร์ของคนอื่นได้ แต่เราสามารถใช้ตัวแปรของคลาสภายนอกได้ ซึ่งจะชดเชยข้อบกพร่องนี้ได้อย่างดี"
"จะเกิดอะไรขึ้นถ้าฉันยังต้องการเพิ่มพารามิเตอร์อื่นๆ ให้กับตัวสร้าง"
"จากนั้นประกาศคลาสภายในธรรมดา (ไม่ระบุชื่อ) และใช้สิ่งนั้น"
“ใช่ ฉันเกือบลืมเรื่องนั้นไปแล้ว”
"จะเกิดอะไรขึ้นถ้าฉันประกาศตัวแปรสแตติก นั่นจะทำให้คลาสนิรนามกลายเป็นคลาสซ้อนแบบสแตติกแทนที่จะเป็นคลาสภายในหรือไม่ กล่าวอีกนัยหนึ่ง มันจะไม่มีการอ้างอิงถึงคลาสภายนอก"
"ไม่ มันจะเป็นชนชั้นในนิรนาม ดูตัวอย่างเหล่านี้"
ด้วยคลาสที่ไม่ระบุชื่อ | ไม่มีคลาสนิรนาม |
---|---|
|
|
|
|
"ฉันเข้าใจแล้ว ตัวแปรสแตติกเท่านั้นที่จะเป็นแบบสแตติก ไม่ใช่คลาส"
"ใช่."
"ในความเป็นจริง คอมไพเลอร์สร้างคลาสภายในสำหรับคลาสภายในที่ไม่ระบุชื่อทั้งหมด คลาสเหล่านี้มักมีชื่อว่า «1», «2», «3» และอื่นๆ"
GO TO FULL VERSION