
103. มีกฎอะไรบ้างที่ใช้กับการตรวจสอบข้อยกเว้นระหว่างการรับมรดก?
ถ้าฉันเข้าใจคำถามถูกต้อง พวกเขากำลังถามเกี่ยวกับกฎการทำงานโดยมีข้อยกเว้นในระหว่างการสืบทอด กฎที่เกี่ยวข้องมีดังนี้:- วิธีการแทนที่หรือนำไปใช้ในการสืบทอด/การใช้งานไม่สามารถโยนข้อยกเว้นที่ถูกตรวจสอบซึ่งอยู่ในลำดับชั้นที่สูงกว่าข้อยกเว้นในวิธีซูเปอร์คลาส/อินเทอร์เฟซ
public interface Animal {
void speak() throws IOException;
}
เมื่อใช้อินเทอร์เฟซนี้ เราไม่สามารถเปิดเผยข้อยกเว้นแบบ Throwable ทั่วไปได้ (เช่นException , Throwable ) แต่เราสามารถแทนที่ข้อยกเว้นที่มีอยู่ด้วยคลาสย่อย เช่นFileNotFoundException :
public class Cat implements Animal {
@Override
public void speak() throws FileNotFoundException {
// Some implementation
}
}
- ส่วน คำสั่ง การพ่นของตัวสร้างคลาสย่อยจะต้องรวมคลาสข้อยกเว้นทั้งหมดที่ถูกโยนโดยตัวสร้างคลาสระดับสูงที่ถูกเรียกเพื่อสร้างวัตถุ
public class Animal {
public Animal() throws ArithmeticException, NullPointerException, IOException {
}
จากนั้นตัวสร้างคลาสย่อยจะต้องโยนมันด้วย:
public class Cat extends Animal {
public Cat() throws ArithmeticException, NullPointerException, IOException {
super();
}
หรือเช่นเดียวกับวิธีการ คุณสามารถระบุข้อยกเว้นทั่วไปที่แตกต่างออกไปได้ ในกรณีของเรา เราสามารถระบุExceptionได้ เนื่องจากเป็นเรื่องทั่วไปมากกว่าและเป็นบรรพบุรุษร่วมกันของข้อยกเว้นทั้งสามข้อที่ระบุในซูเปอร์คลาส:
public class Cat extends Animal {
public Cat() throws Exception {
super();
}
104. คุณสามารถเขียนโค้ดบางส่วนที่ไม่ได้ดำเนินการบล็อกสุดท้ายได้หรือไม่?
ก่อนอื่นมาจำไว้ว่าสุดท้ายคือ อะไร ก่อนหน้านี้ เราได้ตรวจสอบกลไกการตรวจจับข้อยกเว้น: บล็อก tryกำหนดตำแหน่งที่จะตรวจจับข้อยกเว้น และบล็อก catch คือโค้ดที่จะถูกเรียกใช้เมื่อตรวจพบข้อยกเว้นที่เกี่ยวข้อง บล็อกที่สามของโค้ดที่ทำเครื่องหมายโดย คีย์เวิร์ด สุดท้ายสามารถแทนที่หรืออยู่หลังบล็อก catch ได้ แนวคิดเบื้องหลังบล็อกนี้คือโค้ดจะถูกดำเนินการเสมอไม่ว่าจะเกิดอะไรขึ้นใน บล็อก tryหรือcatch (ไม่ว่าจะมีข้อยกเว้นหรือไม่ก็ตาม) อินสแตนซ์ที่บล็อกนี้ไม่ถูกดำเนินการเกิดขึ้นไม่บ่อยนักและผิดปกติ ตัวอย่างที่ง่ายที่สุดคือเมื่อSystem.exit(0)ถูกเรียกก่อนบล็อกสุดท้าย ซึ่งจะเป็นการยุติโปรแกรม:try {
throw new IOException();
} catch (IOException e) {
System.exit(0);
} finally {
System.out.println("This message will not be printed on the console");
}
นอกจากนี้ยังมีบางสถานการณ์ที่ การบล็อก สุดท้ายไม่ทำงาน:
-
ตัวอย่างเช่น การหยุดโปรแกรมอย่างผิดปกติที่เกิดจากข้อผิดพลาดของระบบร้ายแรง หรือข้อผิดพลาดบางอย่างที่ทำให้แอปพลิเคชันหยุดทำงาน (เช่น StackOverflowError ซึ่งเกิดขึ้นเมื่อสแต็กแอปพลิเคชันล้น)
-
อีกสถานการณ์หนึ่งคือเมื่อ เธรด daemonเข้าสู่ บล็อก try-finallyแต่แล้วเธรดหลักของโปรแกรมก็ยุติลง ท้ายที่สุดแล้ว เธรด daemon นั้นมีไว้สำหรับงานในพื้นหลังที่ไม่มีลำดับความสำคัญสูงหรือจำเป็น ดังนั้นแอปพลิเคชันจะไม่รอให้ทำงานเสร็จ
-
ตัวอย่างที่ไร้เหตุผลที่สุดคือการวนซ้ำไม่รู้จบภายใน บล็อก tryหรือcatchเมื่อเข้าไปข้างใน เธรดจะติดอยู่ที่นั่นตลอดไป:
try { while (true) { } } finally { System.out.println("This message will not be printed on the console"); }

105. เขียนตัวอย่างที่คุณจัดการกับข้อยกเว้นหลายรายการใน catch block เดียว
1) ฉันไม่แน่ใจว่าคำถามนี้ถูกถามอย่างถูกต้อง เท่าที่ฉันเข้าใจ คำถามนี้หมายถึงcatch หลาย บล็อกและtry เพียงครั้งเดียว :try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
System.out.print("Oops! There was an exception: " + e);
} catch (IOException e) {
System.out.print("Oops! There was an exception: " + e);
} catch (Exception e) {
System.out.print("Oops! There was an exception: " + e);
}
หากมีข้อยกเว้นเกิดขึ้นใน บล็อก tryดังนั้น บล็อก catch ที่เกี่ยวข้อง จะพยายามตรวจจับตามลำดับจากบนลงล่าง เมื่อข้อยกเว้นตรงกับหนึ่งใน บล็อก catchบล็อกที่เหลือจะไม่สามารถจับและจัดการได้อีกต่อไป ทั้งหมดนี้หมายความว่ามีการจัดเรียงข้อยกเว้นที่แคบกว่าไว้เหนือข้อยกเว้นทั่วไปในชุดcatch block ตัวอย่างเช่น หากcatch block แรกของเราจับ คลาส Exceptionแล้ว บล็อกต่อ ๆ ไปจะไม่จับข้อยกเว้นที่ถูกตรวจสอบ (นั่นคือ บล็อกที่เหลือที่มีคลาสย่อยของExceptionจะไม่มีประโยชน์โดยสิ้นเชิง) 2) หรือบางทีคำถามก็ถูกถามอย่างถูกต้อง ในกรณีนั้น เราสามารถจัดการกับข้อยกเว้นได้ดังต่อไปนี้:
try {
throw new NullPointerException();
} catch (Exception e) {
if (e instanceof FileNotFoundException) {
// Some handling that involves a narrowing type conversion: (FileNotFoundException)e
} else if (e instanceof ArithmeticException) {
// Some handling that involves a narrowing type conversion: (ArithmeticException)e
} else if(e instanceof NullPointerException) {
// Some handling that involves a narrowing type conversion: (NullPointerException)e
}
หลังจากใช้catchเพื่อตรวจจับข้อยกเว้น เราจะพยายามค้นหาประเภทเฉพาะของมันโดยใช้ ตัวดำเนินการ instanceofซึ่งจะตรวจสอบว่าวัตถุอยู่ในประเภทใดประเภทหนึ่งหรือไม่ สิ่งนี้ช่วยให้เราดำเนินการแปลงประเภทให้แคบลงได้อย่างมั่นใจโดยไม่ต้องกลัวผลเสีย เราสามารถใช้วิธีใดวิธีหนึ่งในสถานการณ์เดียวกันได้ ฉันแสดงความสงสัยเกี่ยวกับคำถามเพียงเพราะฉันจะไม่เรียกตัวเลือกที่สองว่าเป็นแนวทางที่ดี จากประสบการณ์ของฉัน ฉันไม่เคยพบมันมาก่อน และวิธีแรกที่เกี่ยวข้องกับ catch block หลายอันก็แพร่หลาย
106. โอเปอเรเตอร์ใดที่อนุญาตให้คุณบังคับให้มีข้อยกเว้นที่จะถูกโยนทิ้ง? เขียนตัวอย่าง
ฉันได้ใช้มันหลายครั้งในตัวอย่างข้างต้น แต่ฉันจะทำซ้ำอีกครั้ง: คีย์เวิร์ดThrow ตัวอย่างของการโยนข้อยกเว้นด้วยตนเอง:throw new NullPointerException();
107. วิธีการหลักสามารถส่งข้อยกเว้นได้หรือไม่? ถ้าเป็นเช่นนั้นจะไปที่ไหน?
ก่อนอื่น ฉันต้องการทราบว่า วิธีการ หลักนั้นไม่มีอะไรมากไปกว่าวิธีธรรมดา ใช่ เครื่องเสมือนถูกเรียกเพื่อเริ่มการทำงานของโปรแกรม แต่นอกเหนือจากนั้น ยังสามารถเรียกจากโค้ดอื่นได้ นั่นหมายความว่ายังอยู่ภายใต้กฎปกติเกี่ยวกับการระบุข้อยกเว้นที่ถูกตรวจสอบหลัง คีย์เวิร์ด Throws :public static void main(String[] args) throws IOException {
ดังนั้นจึงสามารถส่งข้อยกเว้นได้ เมื่อmain ถูกเรียก ว่าเป็นจุดเริ่มต้นของโปรแกรม (แทนที่จะเป็นวิธีอื่น) UncaughtExceptionHandler ข้อยกเว้นใดๆ ที่เกิดขึ้นจะถูกจัดการโดยUncaughtExceptionHandler
แต่ละเธรดมีตัวจัดการดังกล่าวหนึ่งตัว (นั่นคือ มีตัวจัดการดังกล่าวหนึ่งตัวในแต่ละเธรด) หากจำเป็น คุณสามารถสร้างตัวจัดการของคุณเองและตั้งค่าได้โดยการเรียก public static void main(String[] args) พ่นวิธี IOException {setDefaultUncaughtExceptionHandler บน public static void main(String[] args) พ่น IOException {Thread object.
มัลติเธรด

108. คุณรู้กลไกอะไรบ้างในการทำงานในสภาพแวดล้อมแบบมัลติเธรด?
กลไกพื้นฐานสำหรับมัลติเธรดใน Java คือ:-
คีย์เวิร์ดที่ซิงโครไนซ์ซึ่งเป็นวิธีที่เธรดจะล็อกวิธีการ/บล็อกเมื่อเข้ามา ป้องกันไม่ให้เธรดอื่นๆ เข้ามา
-
คีย์เวิร์ดระเหยช่วยให้เข้าถึงตัวแปรที่เข้าถึงได้โดยเธรดต่างๆ อย่างสม่ำเสมอ นั่นคือ เมื่อมีการใช้ตัวแก้ไขนี้กับตัวแปร การดำเนินการทั้งหมดเพื่อกำหนดและอ่านตัวแปรนั้นจะกลายเป็นอะตอมมิก กล่าวอีกนัยหนึ่ง เธรดจะไม่คัดลอกตัวแปรไปยังหน่วยความจำภายในเครื่องและทำการเปลี่ยนแปลง พวกเขาจะเปลี่ยนค่าเดิม
-
Runnable — เราสามารถใช้อินเทอร์เฟซนี้ (ซึ่งประกอบด้วยเมธอดrun() เดียว ) ในบางคลาส:
public class CustomRunnable implements Runnable { @Override public void run() { // Some logic } }
และเมื่อเราสร้างอ็อบเจ็กต์ของคลาสนั้นแล้ว เราก็สามารถเริ่มเธรดใหม่ได้โดยการส่งอ็อบเจ็กต์ของเราไปยัง ตัวสร้าง เธรดจากนั้นจึงเรียกใช้ เมธอด start() :
Runnable runnable = new CustomRunnable(); new Thread(runnable).start();
เมธอดstartรันเมธอดrun() ที่นำไปใช้งาน บนเธรดที่แยกจากกัน
-
Thread — เราสามารถสืบทอดคลาสนี้และแทนที่ วิธี การรัน ของมันได้ :
public class CustomThread extends Thread { @Override public void run() { // Some logic } }
เราสามารถเริ่มเธรดใหม่ได้โดยสร้างอ็อบเจ็กต์ของคลาสนี้แล้วเรียกเมธอดstart() :
new CustomThread().start();
- การทำงานพร้อมกัน — นี่คือชุดเครื่องมือสำหรับการทำงานในสภาพแวดล้อมแบบมัลติเธรด
มันประกอบด้วย:
-
คอลเลกชันที่เกิดขึ้นพร้อมกัน — นี่คือคอลเลกชันของคอลเลกชันที่สร้างขึ้นอย่างชัดเจนสำหรับการทำงานในสภาพแวดล้อมแบบมัลติเธรด
-
คิว — คิวพิเศษสำหรับสภาพแวดล้อมแบบมัลติเธรด (การบล็อกและการไม่บล็อก)
-
Synchronizers — เป็นยูทิลิตี้เฉพาะสำหรับการทำงานในสภาพแวดล้อมแบบมัลติเธรด
-
ผู้ดำเนินการ — กลไกสำหรับการสร้างเธรดพูล
-
ล็อค — กลไกการซิงโครไนซ์เธรดที่ยืดหยุ่นกว่ากลไกมาตรฐาน (ซิงโครไนซ์ รอ แจ้งเตือน แจ้งเตือนทั้งหมด)
- Atomics — คลาสที่ปรับให้เหมาะสมสำหรับมัลติเธรด การดำเนินการแต่ละครั้งเป็นแบบอะตอม
-
109. บอกเราเกี่ยวกับการซิงโครไนซ์ระหว่างเธรด wait(), notify(), notifyAll() และ join() วิธีการมีไว้ทำอะไร?
การซิงโครไนซ์ระหว่างเธรดเป็นเรื่องเกี่ยวกับคีย์เวิร์ดที่ซิงโคร ไนซ์ ตัวแก้ไขนี้สามารถวางบนบล็อกได้โดยตรง:synchronized (Main.class) {
// Some logic
}
หรือโดยตรงในลายเซ็นวิธีการ:
public synchronized void move() {
// Some logic }
ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้การซิงโครไนซ์เป็นกลไกในการล็อคบล็อก/เมธอดไปยังเธรดอื่นเมื่อมีเธรดหนึ่งเข้ามา ลองนึกถึงบล็อก/เมธอดโค้ดเป็นห้องหนึ่ง ด้ายบางเส้นเข้ามาใกล้ห้อง เข้าไป และล็อคประตูด้วยกุญแจ เมื่อมีสายใยอื่นเข้ามาใกล้ห้องก็พบว่าประตูล็อคอยู่และรออยู่ใกล้ๆ จนกว่าห้องจะว่าง เมื่อเธรดแรกเสร็จสิ้นธุระในห้อง มันจะปลดล็อกประตู ออกจากห้อง และปล่อยกุญแจ ฉันเคยพูดถึงกุญแจสองสามครั้งด้วยเหตุผล — เพราะมีบางสิ่งที่คล้ายคลึงกันอยู่จริง นี่คือออบเจ็กต์พิเศษที่มีสถานะไม่ว่าง/ว่าง ทุกอ็อบเจ็กต์ใน Java มีอ็อบเจ็กต์ดังกล่าว ดังนั้นเมื่อเราใช้ บล็อก ซิงโครไนซ์ เราจำเป็นต้องใช้วงเล็บเพื่อระบุอ็อบเจ็กต์ที่ mutex จะถูกล็อค:
Cat cat = new Cat();
synchronized (cat) {
// Some logic
}
เรายังสามารถใช้ mutex ที่เกี่ยวข้องกับคลาสได้ เช่นเดียวกับที่ฉันทำในตัวอย่างแรก ( Main.class ) ท้ายที่สุดเมื่อเราใช้วิธีซิงโครไนซ์ เราไม่ได้ระบุวัตถุที่เราต้องการล็อคใช่ไหม ในกรณีนี้ สำหรับวิธีการที่ไม่คงที่ mutex ที่จะถูกล็อคคือ อ็อบเจ็กต์ นี้ นั่นคืออ็อบเจ็กต์ปัจจุบันของคลาส สำหรับวิธีการแบบสแตติก mutex ที่เกี่ยวข้องกับคลาสปัจจุบัน ( this.getClass(); ) จะถูกล็อค wait()เป็นวิธีการที่ปล่อย mutex และทำให้เธรดปัจจุบันเข้าสู่สถานะรอ เหมือนกับว่าเชื่อมต่อกับมอนิเตอร์ปัจจุบัน (คล้ายกับจุดยึด) ด้วยเหตุนี้ วิธีการนี้สามารถเรียกได้จากบล็อกหรือวิธีการซิงโครไนซ์ เท่านั้น ไม่เช่นนั้นจะรออะไรและจะออกอะไร?) โปรดทราบว่านี่เป็นวิธีการของคลาสObject ไม่ใช่หนึ่ง แต่เป็นสาม:
-
wait()ทำให้เธรดปัจจุบันอยู่ในสถานะรอจนกว่าเธรดอื่นจะเรียกใช้เมธอดnotify()หรือnotifyAll()บนวัตถุนี้ (เราจะพูดถึงวิธีการเหล่านี้ในภายหลัง)
-
wait(long timeout)ทำให้เธรดปัจจุบันอยู่ในสถานะรอจนกว่าเธรดอื่นจะเรียกใช้เมธอดnotify()หรือnotifyAll()บนอ็อบเจ็กต์นี้ หรือช่วงเวลาที่ระบุโดยการหมดเวลาหมดอายุ
-
wait(long timeout, int nanos)เหมือนกับวิธีก่อนหน้า แต่ที่นี่nanosให้คุณระบุ nanoseconds (การหมดเวลาที่แม่นยำยิ่งขึ้น)
-
notify()ให้คุณปลุกเธรดสุ่มหนึ่งเธรดที่รออยู่ในบล็อกการซิงโครไนซ์ปัจจุบัน ขอย้ำอีกครั้งว่าวิธีนี้สามารถเรียกได้เฉพาะใน บล็อกหรือวิธี การซิงโครไนซ์ เท่านั้น (ท้ายที่สุดแล้วในที่อื่นจะไม่มีใครตื่น)
-
notifyAll()ปลุกเธรดทั้งหมดที่รออยู่บนมอนิเตอร์ปัจจุบัน (ใช้เฉพาะใน บล็อกหรือวิธีการ ซิงโครไน ซ์เท่านั้น )
110. เราจะหยุดกระทู้ได้อย่างไร?
สิ่งแรกที่ต้องพูดที่นี่คือเมื่อการrun()ทำงานจนเสร็จสิ้น เธรดจะยุติโดยอัตโนมัติ แต่บางครั้งเราต้องการฆ่าเธรดก่อนกำหนดก่อนที่วิธีการนี้จะเสร็จสิ้น ดังนั้นสิ่งที่เราจะทำ? บางทีเราอาจใช้ เมธอด stop()บน วัตถุ Threadได้ ไม่! วิธีการนั้นเลิกใช้แล้วและอาจทำให้ระบบล่ม
public class CustomThread extends Thread {
private boolean isActive;
public CustomThread() {
this.isActive = true;
}
@Override
public void run() {
{
while (isActive) {
System.out.println("The thread is executing some logic...");
}
System.out.println("The thread stopped!");
}
}
public void stopRunningThread() {
isActive = false;
}
}
การเรียกเมธอดstopRunningThread()จะตั้งค่าสถานะภายในเป็นเท็จ ส่งผลให้เมธอดrun()ยุติลง เรียกมันว่าmain :
System.out.println("Program starting...");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// As long as our main thread is asleep, our CustomThread runs and prints its message on the console
thread.stopRunningThread();
System.out.println("Program stopping...");
ด้วยเหตุนี้เราจะเห็นสิ่งนี้ในคอนโซล:
public class CustomThread extends Thread {
@Override
public void run() {
{
while (!Thread.interrupted()) {
System.out.println("The thread is executing some logic...");
}
System.out.println("The thread stopped!");
}
}
}
ทำงานในหลัก :
System.out.println("Program starting...");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Program stopping...");
ผลลัพธ์ของการดำเนินการนี้เหมือนกับในกรณีแรก แต่ฉันชอบวิธีนี้มากกว่า: เราเขียนโค้ดน้อยลงและใช้ฟังก์ชันมาตรฐานสำเร็จรูปมากขึ้น เอาล่ะ สำหรับวันนี้เท่านั้น!
GO TO FULL VERSION