JavaRush /จาวาบล็อก /Random-TH /จาวาคอร์ คำถามสัมภาษณ์ ตอนที่ 2
Andrey
ระดับ

จาวาคอร์ คำถามสัมภาษณ์ ตอนที่ 2

เผยแพร่ในกลุ่ม
สำหรับผู้ที่ได้ยินคำว่า Java Core เป็นครั้งแรก สิ่งเหล่านี้ถือเป็นรากฐานพื้นฐานของภาษา ด้วยความรู้นี้ คุณสามารถไปฝึกงาน/ฝึกงานได้อย่างปลอดภัย
จาวาคอร์  คำถามสัมภาษณ์ ตอนที่ 2 - 1
คำถามเหล่านี้จะช่วยให้คุณทบทวนความรู้ก่อนการสัมภาษณ์หรือเรียนรู้สิ่งใหม่ๆ สำหรับตัวคุณเอง หากต้องการเพิ่มทักษะ การ ปฏิบัติ เรียนที่JavaRush บทความต้นฉบับ ลิงก์ไปยังส่วนอื่น ๆ : Java Core คำถามสัมภาษณ์ ตอนที่ 1 Java Core คำถามสัมภาษณ์งาน ตอนที่ 3

เหตุใดจึงควรหลีกเลี่ยงวิธีการสรุป ()

เราทุกคนรู้ข้อความที่ว่าตัวfinalize()รวบรวมขยะเรียกเมธอดก่อนที่จะปล่อยหน่วยความจำที่วัตถุครอบครอง นี่คือตัวอย่างโปรแกรมที่พิสูจน์ว่าfinalize()ไม่รับประกันการเรียกใช้เมธอด:
public class TryCatchFinallyTest implements Runnable {

	private void testMethod() throws InterruptedException
	{
		try
		{
			System.out.println("In try block");
			throw new NullPointerException();
		}
		catch(NullPointerException npe)
		{
			System.out.println("In catch block");
		}
		finally
		{
			System.out.println("In finally block");
		}
	}

	@Override
	protected void finalize() throws Throwable {
		System.out.println("In finalize block");
		super.finalize();
	}

	@Override
	public void run() {
		try {
			testMethod();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
public class TestMain
{
	@SuppressWarnings("deprecation")
	public static void main(String[] args) {
	for(int i=1;i< =3;i++)
	{
		new Thread(new TryCatchFinallyTest()).start();
	}
	}
}
เอาท์พุต: ใน try block ใน catch block ในในที่สุด block ใน try block ใน catch block ในในที่สุดก็บล็อก ใน try block ใน catch block ในบล็อกสุดท้าย น่าประหลาดใจที่วิธีนี้finalizeไม่ได้ดำเนินการกับเธรดใด ๆ นี่เป็นการพิสูจน์คำพูดของฉัน ฉันคิดว่าเหตุผลก็คือผู้เข้ารอบสุดท้ายจะดำเนินการโดยเธรดตัวรวบรวมขยะแยกต่างหาก หาก Java Virtual Machine หยุดทำงานเร็วเกินไป ตัวรวบรวมขยะจะไม่มีเวลาเพียงพอที่จะสร้างและดำเนินการตัวสรุปผล เหตุผลอื่นที่ไม่ใช้วิธีการนี้finalize()อาจเป็น:
  1. วิธีการนี้finalize()ใช้ไม่ได้กับเชนเช่นคอนสตรัคเตอร์ ซึ่งหมายความว่าเมื่อคุณเรียกตัวสร้างคลาส ตัวสร้างคลาสระดับสูงจะถูกเรียกโดยไม่มีเงื่อนไข แต่ในกรณีของวิธีนี้finalize()สิ่งนี้จะไม่เกิดขึ้น finalize()ต้องเรียกเมธอด ซูเปอร์คลาสอย่างชัดเจน
  2. ข้อยกเว้นใดๆ ที่เกิดขึ้นโดยวิธีการนี้finalizeจะถูกละเว้นโดยเธรดตัวรวบรวมขยะ และจะไม่ถูกเผยแพร่เพิ่มเติม ซึ่งหมายความว่าเหตุการณ์จะไม่ถูกบันทึกไว้ในบันทึกของคุณ นี่มันแย่มากเลยใช่ไหม?
  3. คุณยังได้รับค่าปรับด้านประสิทธิภาพอย่างมากหากมีวิธีการfinalize()ดังกล่าวในชั้นเรียนของคุณ ใน Effective Programming (ฉบับพิมพ์ครั้งที่ 2) Joshua Bloch กล่าวว่า:
    “ใช่ และอีกอย่างหนึ่ง: มีการลงโทษด้านประสิทธิภาพอย่างมากเมื่อใช้โปรแกรมสรุปผล บนเครื่องของฉัน เวลาในการสร้างและทำลายวัตถุธรรมดาคือประมาณ 5.6 นาโนวินาที
    การเพิ่มตัวปิดท้ายจะเพิ่มเวลาเป็น 2,400 นาโนวินาที กล่าวอีกนัยหนึ่ง การสร้างและลบออบเจ็กต์ด้วยโปรแกรมขั้นสุดท้ายจะช้าลงประมาณ 430 เท่า”

เหตุใดจึงไม่ควรใช้ HashMap ในสภาพแวดล้อมแบบมัลติเธรด สิ่งนี้อาจทำให้เกิดการวนซ้ำไม่สิ้นสุดหรือไม่?

เรารู้ว่าHashMapนี่คือคอลเล็กชันที่ไม่ซิงโครไนซ์ ซึ่งคอลเลกชั่นที่ซิงโครไนซ์HashTableคือ ดังนั้น เมื่อคุณเข้าถึงคอลเลกชันและในสภาพแวดล้อมแบบมัลติเธรดที่เธรดทั้งหมดสามารถเข้าถึงอินสแตนซ์เดียวของคอลเลกชันได้ จะปลอดภัยกว่าที่จะใช้HashTableด้วยเหตุผลที่ชัดเจน เช่น หลีกเลี่ยงการอ่านสกปรกและรับรองความสอดคล้องของข้อมูล ในกรณีที่เลวร้ายที่สุด สภาพแวดล้อมแบบมัลติเธรดนี้จะทำให้เกิดการวนซ้ำไม่สิ้นสุด ใช่มันเป็นความจริง. HashMap.get()อาจทำให้เกิดการวนซ้ำไม่สิ้นสุด มาดูกันว่าเป็นอย่างไร? หากคุณดูที่ซอร์สโค้ดของวิธีการHashMap.get(Object key)ดูเหมือนว่านี้:
public Object get(Object key) {
    Object k = maskNull(key);
    int hash = hash(k);
    int i = indexFor(hash, table.length);
    Entry e = table[i];
    while (true) {
        if (e == null)
            return e;
        if (e.hash == hash && eq(k, e.key))
            return e.value;
        e = e.next;
    }
}
while(true)สามารถตกเป็นเหยื่อของลูปไม่สิ้นสุดในสภาพแวดล้อมรันไทม์แบบมัลติเธรดได้เสมอ หากe.nextสามารถชี้ไปที่ตัวมันเองได้ ด้วยเหตุผลบางประการ สิ่งนี้จะทำให้เกิดการวนซ้ำไม่รู้จบ แต่e.nextจะชี้ไปที่ตัวมันเองได้อย่างไร (นั่นคือ ถึงe)? สิ่งนี้สามารถเกิดขึ้นได้ในวิธีการvoid transfer(Entry[] newTable)ที่เรียกว่าในขณะที่HashMapกำลังปรับขนาด
do {
    Entry next = e.next;
    int i = indexFor(e.hash, newCapacity);
    e.next = newTable[i];
    newTable[i] = e;
    e = next;
} while (e != null);
โค้ดชิ้นนี้มีแนวโน้มที่จะสร้างการวนซ้ำไม่สิ้นสุดหากการปรับขนาดเกิดขึ้นในเวลาเดียวกันกับที่เธรดอื่นพยายามเปลี่ยนอินสแตนซ์แมป ( HashMap) วิธีเดียวที่จะหลีกเลี่ยงสถานการณ์นี้คือการใช้การซิงโครไนซ์ในโค้ดของคุณ หรือดีกว่านั้น ให้ใช้คอลเลกชันที่ซิงโครไนซ์

อธิบายนามธรรมและการห่อหุ้ม พวกเขาเชื่อมโยงกันอย่างไร?

พูดง่ายๆ ก็คือ “ สิ่งที่เป็นนามธรรมจะแสดงเฉพาะคุณสมบัติของวัตถุที่มีนัยสำคัญสำหรับมุมมองปัจจุบัน ” ในทฤษฎีการเขียนโปรแกรมเชิงวัตถุ นามธรรมเกี่ยวข้องกับความสามารถในการกำหนดวัตถุที่เป็นตัวแทนของ "ผู้แสดง" ที่เป็นนามธรรมซึ่งสามารถทำงาน เปลี่ยนแปลงและรายงานการเปลี่ยนแปลงในสถานะของพวกเขา และ "โต้ตอบ" กับวัตถุอื่น ๆ ในระบบ นามธรรมในภาษาโปรแกรมใดๆ ก็ตามทำงานได้หลายวิธี ดังจะเห็นได้จากการสร้างรูทีนเพื่อกำหนดอินเทอร์เฟซสำหรับคำสั่งภาษาระดับต่ำ นามธรรมบางอย่างพยายามจำกัดความกว้างของการนำเสนอความต้องการของโปรแกรมเมอร์โดยรวมโดยการซ่อนนามธรรมที่ถูกสร้างขึ้น เช่น รูปแบบการออกแบบ โดยทั่วไปแล้ว นามธรรมสามารถเห็นได้สองวิธี: Data abstractionเป็นวิธีการสร้างประเภทข้อมูลที่ซับซ้อนและเปิดเผยเฉพาะการดำเนินการที่มีความหมายเท่านั้นเพื่อโต้ตอบกับโมเดลข้อมูล ในขณะเดียวกันก็ซ่อนรายละเอียดการใช้งานทั้งหมดจากโลกภายนอก การดำเนินการที่เป็นนามธรรมเป็นกระบวนการในการระบุข้อความที่สำคัญทั้งหมดและเปิดเผยเป็นหน่วยงาน เรามักจะใช้คุณสมบัตินี้เมื่อเราสร้างวิธีการทำงานบางอย่าง การจำกัดข้อมูลและวิธีการภายในคลาสร่วมกับการซ่อน (โดยใช้การควบคุมการเข้าถึง) มักเรียกว่าการห่อหุ้ม ผลลัพธ์ที่ได้คือชนิดข้อมูลที่มีลักษณะและพฤติกรรม การห่อหุ้มโดยพื้นฐานแล้วยังเกี่ยวข้องกับการซ่อนข้อมูลและการซ่อนการใช้งาน “สรุปทุกสิ่งที่เปลี่ยนแปลงได้” . คำพูดนี้เป็นหลักการออกแบบที่รู้จักกันดี สำหรับเรื่องนั้น ในคลาสใดก็ตาม การเปลี่ยนแปลงข้อมูลสามารถเกิดขึ้นได้ที่รันไทม์ และการเปลี่ยนแปลงการใช้งานสามารถเกิดขึ้นได้ในเวอร์ชันต่อๆ ไป ดังนั้นการห่อหุ้มจึงใช้ได้กับทั้งข้อมูลและการนำไปใช้งาน จึงสามารถเชื่อมต่อได้ดังนี้:
  • สิ่งที่เป็นนามธรรมส่วนใหญ่เป็นสิ่งที่ชั้นเรียนสามารถทำได้ [ไอเดีย]
  • การห่อหุ้มมีมากกว่าวิธีการใช้งานฟังก์ชันนี้ให้สำเร็จ [การใช้งาน]

ความแตกต่างระหว่างอินเทอร์เฟซและคลาสนามธรรม?

ความแตกต่างหลักสามารถแสดงได้ดังนี้:
  • อินเทอร์เฟซไม่สามารถใช้วิธีการใด ๆ ได้ แต่คลาสนามธรรมสามารถทำได้
  • คลาสสามารถใช้อินเทอร์เฟซได้หลายแบบ แต่สามารถมีซูเปอร์คลาสได้เพียงคลาสเดียวเท่านั้น (นามธรรมหรือไม่ใช่นามธรรม)
  • อินเทอร์เฟซไม่ได้เป็นส่วนหนึ่งของลำดับชั้นของคลาส คลาสที่ไม่เกี่ยวข้องสามารถใช้อินเทอร์เฟซเดียวกันได้
สิ่งที่คุณต้องจำคือ: “เมื่อคุณสามารถอธิบายแนวคิดในแง่ของ “มันทำอะไร” ได้อย่างเต็มที่ โดยไม่ต้องระบุว่า “มันทำงานอย่างไร” คุณควรใช้อินเทอร์เฟซ หากคุณต้องการใส่รายละเอียดการนำไปปฏิบัติ คุณจำเป็นต้องนำเสนอแนวคิดของคุณในคลาสนามธรรม" นอกจากนี้ กล่าวอีกนัยหนึ่ง: มีหลายคลาสที่สามารถ "จัดกลุ่มเข้าด้วยกัน" และอธิบายด้วยคำนามเดียวได้หรือไม่ หากเป็นเช่นนั้น ให้สร้างคลาสนามธรรมโดยใช้ชื่อของคำนามนี้ และสืบทอดคลาสจากคลาสนั้น ตัวอย่างเช่นCatและDogสามารถสืบทอดมาจากคลาสนามธรรมAnimalและคลาสฐานนามธรรมนี้จะใช้วิธีvoid Breathe()การหายใจ ซึ่งสัตว์ทุกตัวจะดำเนินการในลักษณะเดียวกัน คำกริยาใดบ้างที่สามารถนำไปใช้กับชั้นเรียนของฉันและนำไปใช้กับผู้อื่นได้ สร้างอินเทอร์เฟซสำหรับคำกริยาแต่ละคำเหล่านี้ ตัวอย่างเช่น สัตว์ทุกตัวสามารถกินได้ ดังนั้นฉันจะสร้างอินเทอร์เฟซIFeedableและทำให้มันAnimalใช้อินเทอร์เฟซนั้น ดีพอที่จะใช้อินเทอร์เฟซเท่านั้นDog( สามารถชอบฉันได้) แต่ไม่ใช่ทั้งหมด มีคนกล่าวว่า: ความแตกต่างที่สำคัญคือจุดที่คุณต้องการนำไปปฏิบัติ เมื่อคุณสร้างอินเทอร์เฟซ คุณสามารถย้ายการใช้งานไปยังคลาสใดๆ ที่ใช้อินเทอร์เฟซของคุณได้ ด้วยการสร้างคลาสนามธรรม คุณสามารถแบ่งปันการใช้งานคลาสที่ได้รับทั้งหมดในที่เดียว และหลีกเลี่ยงสิ่งเลวร้ายมากมาย เช่น รหัสที่ซ้ำกัน HorseILikeable

StringBuffer ช่วยประหยัดหน่วยความจำได้อย่างไร

คลาสStringถูกนำไปใช้เป็นอ็อบเจ็กต์ที่ไม่เปลี่ยนรูป ซึ่งหมายความว่าเมื่อคุณเริ่มตัดสินใจที่จะใส่บางสิ่งลงในอ็อบเจ็กต์Stringเครื่องเสมือนจะจัดสรรอาเรย์ที่มีความยาวคงที่เท่ากับขนาดของค่าดั้งเดิมของคุณทุกประการ จากนั้นจะถือเป็นค่าคงที่ภายในเครื่องเสมือน ซึ่งจะช่วยปรับปรุงประสิทธิภาพที่สำคัญหากค่าของสตริงไม่เปลี่ยนแปลง อย่างไรก็ตาม หากคุณตัดสินใจที่จะเปลี่ยนเนื้อหาของสตริงในทางใดทางหนึ่ง สิ่งที่เครื่องเสมือนทำจริงๆ คือการคัดลอกเนื้อหาของสตริงต้นฉบับลงในพื้นที่ชั่วคราว ทำการเปลี่ยนแปลง จากนั้นบันทึกการเปลี่ยนแปลงเหล่านั้นไปยังอาร์เรย์หน่วยความจำใหม่ ดังนั้นการเปลี่ยนแปลงค่าของสตริงหลังจากการกำหนดค่าเริ่มต้นจึงเป็นการดำเนินการที่มีราคาแพง StringBufferในทางกลับกัน ถูกนำมาใช้เป็นอาร์เรย์ขยายแบบไดนามิกภายในเครื่องเสมือน ซึ่งหมายความว่าการดำเนินการแก้ไขใดๆ สามารถเกิดขึ้นได้บนเซลล์หน่วยความจำที่มีอยู่ และหน่วยความจำใหม่จะได้รับการจัดสรรตามความจำเป็น อย่างไรก็ตาม ไม่มีวิธีใดที่เครื่องเสมือนจะทำการออปติไมซ์ได้StringBufferเนื่องจากเนื้อหาในเครื่องถือว่าไม่สอดคล้องกันในแต่ละอินสแตนซ์

เหตุใดจึงมีการประกาศวิธีการรอและแจ้งเตือนในคลาส Object แทนที่จะเป็น Thread

วิธีการ, waitจำเป็นเฉพาะเมื่อคุณต้องการให้เธรดของคุณมีสิทธิ์เข้าถึงทรัพยากรที่ใช้ร่วมกัน และทรัพยากรที่ใช้ร่วมกันอาจเป็นวัตถุ Java ใดๆ ในฮีป ดังนั้น วิธีการเหล่านี้จึงถูกกำหนดไว้บนคลาสพื้นฐานเพื่อให้แต่ละวัตถุมีตัวควบคุมที่อนุญาตให้เธรดรอบนจอภาพ Java ไม่มีวัตถุพิเศษใด ๆ ที่ใช้ในการแบ่งปันทรัพยากรที่ใช้ร่วมกัน ไม่มีการกำหนดโครงสร้างข้อมูลดังกล่าว ดังนั้นจึงเป็นความรับผิดชอบของชั้นเรียน ที่ จะกลายเป็นทรัพยากรที่ใช้ร่วมกัน และจัดเตรียมวิธีการช่วยเหลือ เช่น, , Java มีพื้นฐานมาจากแนวคิดเรื่องจอภาพของ Charles Hoare ใน Java วัตถุทั้งหมดมีจอภาพ เธรดรออยู่บนมอนิเตอร์ ดังนั้นเพื่อดำเนินการรอ เราจำเป็นต้องมีพารามิเตอร์สองตัว: notifynotifyAllObjectObjectwait()notify()notifyAll()
  • ด้าย
  • มอนิเตอร์ (วัตถุใด ๆ )
ในการออกแบบ Java ไม่สามารถกำหนดเธรดได้อย่างแม่นยำ แต่เป็นเธรดปัจจุบันที่รันโค้ดเสมอ อย่างไรก็ตาม เราสามารถกำหนดมอนิเตอร์ได้ (ซึ่งเป็นวัตถุที่เราสามารถเรียกเมธอดได้wait) นี่เป็นการออกแบบที่ดี เพราะหากเราสามารถบังคับให้เธรดอื่นรอบนจอภาพเฉพาะได้ มันจะส่งผลให้เกิด "การบุกรุก" ทำให้การออกแบบ/การเขียนโปรแกรมโปรแกรมแบบขนานทำได้ยาก โปรดจำไว้ว่าใน Java การดำเนินการทั้งหมดที่รบกวนเธรดอื่นจะเลิกใช้แล้ว (เช่นstop())

เขียนโปรแกรมเพื่อสร้าง deadlock ใน Java แล้วแก้ไข

ใน Java deadlockนี่เป็นสถานการณ์ที่อย่างน้อยสองเธรดเก็บบล็อกไว้บนรีซอร์สที่แตกต่างกัน และทั้งสองกำลังรอให้รีซอร์สอื่นพร้อมใช้งานเพื่อทำงานให้เสร็จสิ้น และไม่มีใครสามารถออกจากการล็อคทรัพยากรที่กำลังถืออยู่ได้ จาวาคอร์  คำถามสัมภาษณ์ ตอนที่ 2 - 2 โปรแกรมตัวอย่าง:
package thread;

public class ResolveDeadLockTest {

	public static void main(String[] args) {
		ResolveDeadLockTest test = new ResolveDeadLockTest();

		final A a = test.new A();
		final B b = test.new B();

		// Thread-1
		Runnable block1 = new Runnable() {
			public void run() {
				synchronized (a) {
					try {
					// Добавляем задержку, чтобы обе нити могли начать попытки
					// блокирования ресурсов
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					// Thread-1 заняла A но также нуждается в B
					synchronized (b) {
						System.out.println("In block 1");
					}
				}
			}
		};

		// Thread-2
		Runnable block2 = new Runnable() {
			public void run() {
				synchronized (b) {
					// Thread-2 заняла B но также нуждается в A
					synchronized (a) {
						System.out.println("In block 2");
					}
				}
			}
		};

		new Thread(block1).start();
		new Thread(block2).start();
	}

	// Resource A
	private class A {
		private int i = 10;

		public int getI() {
			return i;
		}

		public void setI(int i) {
			this.i = i;
		}
	}

	// Resource B
	private class B {
		private int i = 20;

		public int getI() {
			return i;
		}

		public void setI(int i) {
			this.i = i;
		}
	}
}
การเรียกใช้โค้ดด้านบนจะส่งผลให้เกิดการหยุดชะงักด้วยเหตุผลที่ชัดเจนมาก (อธิบายไว้ข้างต้น) ตอนนี้เราจำเป็นต้องแก้ไขปัญหานี้ ฉันเชื่อว่าการแก้ปัญหาใดๆ อยู่ที่ต้นตอของปัญหานั่นเอง ในกรณีของเรา รูปแบบการเข้าถึง A และ B คือปัญหาหลัก ดังนั้น เพื่อแก้ปัญหานี้ เราเพียงแค่เปลี่ยนลำดับของผู้ดำเนินการเข้าถึงเป็นทรัพยากรที่ใช้ร่วมกัน หลังจากการเปลี่ยนแปลงจะมีลักษณะดังนี้:
// Thread-1
Runnable block1 = new Runnable() {
	public void run() {
		synchronized (b) {
			try {
				// Добавляем задержку, чтобы обе нити могли начать попытки
				// блокирования ресурсов
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// Thread-1 заняла B но также нуждается в А
			synchronized (a) {
				System.out.println("In block 1");
			}
		}
	}
};

// Thread-2
Runnable block2 = new Runnable() {
	public void run() {
		synchronized (b) {
			// Thread-2 заняла B но также нуждается в А
			synchronized (a) {
				System.out.println("In block 2");
			}
		}
	}
};
เรียกใช้คลาสนี้อีกครั้ง และตอนนี้คุณจะไม่เห็นการหยุดชะงัก ฉันหวังว่านี่จะช่วยคุณหลีกเลี่ยงการหยุดชะงักและกำจัดมันออกไปหากคุณพบมัน

จะเกิดอะไรขึ้นหากคลาสของคุณที่ใช้อินเทอร์เฟซแบบซีเรียลไลซ์มีส่วนประกอบที่ไม่สามารถซีเรียลไลซ์ได้ จะแก้ไขปัญหานี้ได้อย่างไร?

ในกรณีนี้ มันจะถูกโยนทิ้งNotSerializableExceptionระหว่างการดำเนินการ เพื่อแก้ไขปัญหานี้ มีวิธีแก้ไขที่ง่ายมาก - ทำเครื่องหมายที่ช่องเหล่าtransientนี้ ซึ่งหมายความว่าฟิลด์ที่เลือกจะไม่ถูกทำให้เป็นอนุกรม หากคุณต้องการจัดเก็บสถานะของฟิลด์เหล่านี้ด้วย คุณต้องพิจารณาตัวแปรอ้างอิงซึ่งมีการใช้งานSerializable. คุณอาจจำเป็นต้องใช้readResolve()และwriteResolve()วิธี การ สรุป:
  • ขั้นแรก ทำให้ฟิลด์ของคุณไม่สามารถซีเรียลไลซ์transientได้
  • ขั้นแรกwriteObjectให้เรียกใช้defaultWriteObjectเธรดเพื่อบันทึกฟิลด์ที่ไม่ใช่transientฟิลด์ทั้งหมด จากนั้นเรียกใช้เมธอดที่เหลือเพื่อทำให้เป็นอนุกรมคุณสมบัติแต่ละรายการของอ็อบเจ็กต์ที่ไม่ทำให้เป็นอนุกรมของคุณ
  • ในreadObjectขั้นแรกให้เรียกdefaultReadObjectใช้สตรีมเพื่ออ่านฟิลด์ที่ไม่ใช่ทั้งหมดtransientจากนั้นเรียกวิธีการอื่น (ซึ่งสอดคล้องกับวิธีที่คุณเพิ่มในwriteObject) เพื่อทำการดีซีเรียลไลซ์ที่ไม่ใช่transientอ็อบเจ็กต์ ของคุณ

อธิบายคำสำคัญชั่วคราวและผันผวนใน Java

"คำสำคัญtransientถูกใช้เพื่อระบุฟิลด์ที่จะไม่ถูกทำให้เป็นอนุกรม" ตามข้อกำหนดภาษา Java: ตัวแปรสามารถทำเครื่องหมายด้วยตัวบ่งชี้ชั่วคราวเพื่อระบุว่าไม่ได้เป็นส่วนหนึ่งของสถานะคงอยู่ของวัตถุ ตัวอย่างเช่น คุณอาจมีช่องที่ได้มาจากช่องอื่น และขอแนะนำให้รับช่องเหล่านั้นโดยทางโปรแกรม แทนที่จะกู้คืนสถานะผ่านการทำให้เป็นอนุกรม ตัวอย่างเช่น ในคลาส ฟิลด์BankPayment.javaต่างๆ เช่นprincipal(ผู้อำนวยการ) และrate(อัตรา) สามารถซีเรียลไลซ์ได้ และinterest(ดอกเบี้ยค้างรับ) สามารถคำนวณได้ตลอดเวลา แม้หลังจากการดีซีเรียลไลซ์แล้วก็ตาม หากเราจำได้ว่า แต่ละเธรดใน Java มีหน่วยความจำในเครื่องของตัวเอง และดำเนินการอ่าน/เขียนในหน่วยความจำในเครื่องนี้ เมื่อการดำเนินการทั้งหมดเสร็จสิ้น ระบบจะเขียนสถานะที่แก้ไขของตัวแปรลงในหน่วยความจำที่ใช้ร่วมกัน ซึ่งเป็นจุดที่เธรดทั้งหมดเข้าถึงตัวแปร โดยทั่วไป นี่เป็นเธรดปกติภายในเครื่องเสมือน แต่ตัวดัดแปลงระเหยจะบอกเครื่องเสมือนว่าการเข้าถึงของเธรดไปยังตัวแปรนั้นจะต้องตรงกับสำเนาของตัวแปรนั้นกับสำเนาหลักของตัวแปรในหน่วยความจำเสมอ ซึ่งหมายความว่าทุกครั้งที่เธรดต้องการอ่านสถานะของตัวแปร เธรดนั้นจะต้องล้างสถานะหน่วยความจำภายในและอัปเดตตัวแปรจากหน่วยความจำหลัก Volatileมีประโยชน์มากที่สุดในอัลกอริธึมที่ไม่มีการล็อค คุณทำเครื่องหมายตัวแปรที่จัดเก็บข้อมูลที่ใช้ร่วมกันว่ามีความผันผวน จากนั้นคุณจะไม่ใช้การล็อกเพื่อเข้าถึงตัวแปรนั้น และการเปลี่ยนแปลงทั้งหมดที่ทำโดยเธรดหนึ่งจะมองเห็นได้โดยผู้อื่น หรือหากคุณต้องการสร้างความสัมพันธ์ "ที่เกิดขึ้นภายหลัง" เพื่อให้แน่ใจว่าการคำนวณจะไม่เกิดซ้ำ อีกครั้งเพื่อให้แน่ใจว่าการเปลี่ยนแปลงจะมองเห็นได้แบบเรียลไทม์ ควรใช้สารระเหยเพื่อเผยแพร่อ็อบเจ็กต์ที่ไม่เปลี่ยนรูปได้อย่างปลอดภัยในสภาพแวดล้อมแบบมัลติเธรด การประกาศภาคสนามpublic volatile ImmutableObjectช่วยให้แน่ใจว่าเธรดทั้งหมดเห็นการอ้างอิงอินสแตนซ์ที่มีอยู่ในปัจจุบันเสมอ

ความแตกต่างระหว่างตัววนซ้ำและ ListIterator?

เราสามารถใช้หรือเพื่อIteratorวนซ้ำองค์ประกอบต่างๆ แต่สามารถใช้เพื่อวนซ้ำองค์ประกอบเท่านั้น ความแตกต่างอื่นๆ มีอธิบายไว้ด้านล่าง คุณสามารถ: SetListMapListIteratorList
  1. วนซ้ำในลำดับย้อนกลับ
  2. รับดัชนีได้ทุกที่
  3. เพิ่มมูลค่าได้ทุกที่
  4. ตั้งค่าใด ๆ ที่ตำแหน่งปัจจุบัน
ขอให้โชคดีกับการเรียนนะ!! ผู้เขียนบทความLokesh Gupta บทความต้นฉบับ Java Core คำถามสัมภาษณ์ ตอนที่ 1 Java Core คำถามสัมภาษณ์งาน ตอนที่ 3
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION