JavaRush /Java blogi /Random-UZ /Java yadrosi. Intervyu savollari, 2-qism
Andrey
Daraja

Java yadrosi. Intervyu savollari, 2-qism

Guruhda nashr etilgan
Java Core so'zini birinchi marta eshitganlar uchun bu tilning asosiy asoslari. Ushbu bilim bilan siz amaliyot/stajirovkaga xavfsiz tarzda borishingiz mumkin.
Java yadrosi.  Suhbat uchun savollar, 2-1-qism
Bu savollar intervyu oldidan bilimingizni yangilashga yoki o'zingiz uchun yangi narsalarni o'rganishingizga yordam beradi. Amaliy ko'nikmalarga ega bo'lish uchun JavaRush -da o'qing . Asl maqola Boshqa qismlarga havolalar: Java Core. Intervyu savollari, Java Core 1-qism. Intervyu uchun savollar, 3-qism

Nima uchun finalize() usulidan qochish kerak?

finalize()Ob'ekt egallagan xotirani bo'shatishdan oldin axlat yig'uvchi tomonidan usul chaqirilishi haqidagi bayonot hammamizga ma'lum . finalize()Usul chaqiruvi kafolatlanmaganligini isbotlovchi misol dastur :
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();
	}
	}
}
Chiqish: try blokida In catch blokida In nihoyat blokda In try block In catch block In finally block In try block In catch block In finally block Ajablanarlisi shundaki, usul finalizehech qanday ip uchun bajarilmadi. Bu mening so'zlarimni tasdiqlaydi. Menimcha, buning sababi shundaki, yakunlovchilar alohida axlat yig'uvchi ip tomonidan bajariladi. Agar Java virtual mashinasi juda erta tugatsa, axlat yig'uvchida yakunlovchilarni yaratish va bajarish uchun etarli vaqt yo'q. Usulni qo'llamaslikning boshqa sabablari quyidagilar finalize()bo'lishi mumkin:
  1. Usul finalize()konstruktorlar kabi zanjirlar bilan ishlamaydi. Bu shuni anglatadiki, siz sinf konstruktorini chaqirganingizda, superklass konstruktorlari shartsiz chaqiriladi. Ammo usul bo'lsa finalize(), bu amal qilmaydi. Superklass usuli finalize()aniq chaqirilishi kerak.
  2. Usul tomonidan tashlangan har qanday istisno finalizeaxlat yig'uvchi ip tomonidan e'tiborga olinmaydi va bundan keyin tarqalmaydi, ya'ni voqea sizning jurnallaringizga yozilmaydi. Bu juda yomon, shunday emasmi?
  3. Agar usul finalize()sizning sinfingizda mavjud bo'lsa, siz ham muhim ish jazosiga ega bo'lasiz. "Effektiv dasturlash" (2-nashr) da Joshua Bloch shunday dedi:
    "Ha, va yana bir narsa: yakunlovchilardan foydalanishda katta ishlash jazosi mavjud. Mening mashinamda oddiy ob'ektlarni yaratish va yo'q qilish vaqti taxminan 5,6 nanosekundni tashkil qiladi.
    Yakunlovchini qo'shish vaqtni 2400 nanosekundga oshiradi. Boshqacha qilib aytganda, yakunlovchi bilan ob'ektni yaratish va o'chirish taxminan 430 baravar sekinroq.

Nega HashMap ko'p tarmoqli muhitda ishlatilmasligi kerak? Bu cheksiz tsiklga olib kelishi mumkinmi?

Biz bilamizki, HashMapbu sinxronlashtirilmagan to'plam bo'lib, uning sinxronlashtirilgan hamkasbi HashTable. Shunday qilib, siz to'plamga kirayotganingizda va barcha mavzular to'plamning bitta nusxasiga kirish huquqiga ega bo'lgan ko'p tarmoqli muhitda, HashTableiflos o'qishlardan qochish va ma'lumotlar izchilligini ta'minlash kabi aniq sabablarga ko'ra foydalanish xavfsizroq bo'ladi. Eng yomon holatda, bu ko'p tarmoqli muhit cheksiz tsiklga olib keladi. Ha, bu haqiqat. HashMap.get()cheksiz aylanaga olib kelishi mumkin. Keling, qanday qilib ko'ramiz? Agar siz usulning manba kodiga qarasangiz HashMap.get(Object key), u quyidagicha ko'rinadi:
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.nextagar biron sababga ko'ra u o'zini ko'rsatishi mumkin bo'lsa, har doim ko'p oqimli ish vaqti muhitida cheksiz tsiklning qurboni bo'lishi mumkin . Bu cheksiz tsiklga olib keladi, lekin e.nextu qanday qilib o'ziga (ya'ni e) ishora qiladi? Bu o'lcham o'zgartirilayotganda void transfer(Entry[] newTable)chaqiriladigan usulda sodir bo'lishi mumkin .HashMap
do {
    Entry next = e.next;
    int i = indexFor(e.hash, newCapacity);
    e.next = newTable[i];
    newTable[i] = e;
    e = next;
} while (e != null);
Ushbu kod qismi cheksiz tsiklni yaratishga moyil bo'ladi, agar o'lcham o'zgartirilsa, boshqa oqim xarita misolini o'zgartirishga harakat qilayotgan bir vaqtda sodir bo'lsa ( HashMap). Ushbu stsenariydan qochishning yagona yo'li - kodingizda sinxronizatsiyadan foydalanish yoki yaxshiroq, sinxronlashtirilgan to'plamdan foydalanish.

Abstraksiya va inkapsulyatsiyani tushuntiring. Ular qanday bog'langan?

Oddiy so'zlar bilan aytganda , " Abstraktsiya faqat ob'ektning joriy ko'rinish uchun muhim bo'lgan xususiyatlarini ko'rsatadi . " Ob'ektga yo'naltirilgan dasturlash nazariyasida abstraktsiya ishni bajarish, o'z holatini o'zgartirish va o'zgarishlar haqida xabar berish, tizimning boshqa ob'ektlari bilan "o'zaro ta'sir qilish" mumkin bo'lgan mavhum "aktyorlar" ni ifodalovchi ob'ektlarni aniqlash qobiliyatini o'z ichiga oladi. Har qanday dasturlash tilida abstraktsiya ko'p jihatdan ishlaydi. Buni past darajadagi til buyruqlari uchun interfeyslarni aniqlash uchun tartiblarni yaratishdan ko'rish mumkin. Ba'zi abstraktsiyalar dasturchining ehtiyojlarini umumiy ifodalash kengligini cheklashga urinadi, masalan, dizayn naqshlari kabi ular qurilgan abstraktsiyalarni butunlay yashiradi. Odatda, abstraktsiyani ikki usulda ko'rish mumkin: Ma'lumotlarni abstraktsiyalash - bu murakkab ma'lumotlar turlarini yaratish va ma'lumotlar modeli bilan o'zaro ta'sir qilish uchun faqat mazmunli operatsiyalarni ochib berish, shu bilan birga barcha amalga oshirish tafsilotlarini tashqi dunyodan yashirish usuli. Bajarish abstraktsiyasi - bu barcha muhim bayonotlarni aniqlash va ularni ish birligi sifatida ko'rsatish jarayoni. Biz odatda bu xususiyatdan ba'zi ishlarni bajarish uchun usul yaratganimizda foydalanamiz. Ma'lumotlar va usullarni sinflar ichida yashirish (kirish nazorati yordamida) bilan birgalikda cheklash ko'pincha inkapsulyatsiya deb ataladi. Natijada xarakteristikalar va xatti-harakatlarga ega ma'lumotlar turi paydo bo'ladi. Inkapsulyatsiya, shuningdek, ma'lumotlarni yashirish va amalga oshirishni yashirishni ham o'z ichiga oladi. "O'zgarishi mumkin bo'lgan hamma narsani qamrab oling" . Ushbu tirnoq taniqli dizayn tamoyilidir. Shu munosabat bilan, har qanday sinfda ma'lumotlar o'zgarishi ish vaqtida sodir bo'lishi mumkin va amalga oshirish o'zgarishlar keyingi versiyalarda sodir bo'lishi mumkin. Shunday qilib, inkapsulyatsiya ma'lumotlarga ham, amalga oshirishga ham tegishli. Shunday qilib, ular quyidagicha ulanishi mumkin:
  • Abstraktsiya asosan sinf nima qila oladi [Idea]
  • Enkapsulyatsiya ko'proq Bu funksiyaga qanday erishish mumkin [Implementation]

Interfeys va mavhum sinf o'rtasidagi farqlar?

Asosiy farqlarni quyidagicha sanab o'tish mumkin:
  • Interfeys hech qanday usullarni amalga oshira olmaydi, lekin mavhum sinf amalga oshirishi mumkin.
  • Sinf ko'plab interfeyslarni amalga oshirishi mumkin, lekin faqat bitta superklassga ega bo'lishi mumkin (mavhum yoki mavhum bo'lmagan)
  • Interfeys sinf ierarxiyasining bir qismi emas. Bir-biriga bog'liq bo'lmagan sinflar bir xil interfeysni amalga oshirishi mumkin.
Esda tutishingiz kerak bo'lgan narsa: "Agar siz "qanday qiladi" ni ko'rsatmasdan turib, kontseptsiyani "nima qiladi" nuqtai nazaridan to'liq tasvirlab bera olsangiz, interfeysdan foydalanishingiz kerak. Agar siz amalga oshirishning ba'zi tafsilotlarini kiritishingiz kerak bo'lsa, unda siz o'z kontseptsiyangizni mavhum sinfda ko'rsatishingiz kerak." Bundan tashqari, boshqacha qilib aytadigan bo'lsak: "birga guruhlanishi" va bitta ot bilan tavsiflanishi mumkin bo'lgan sinflar ko'pmi? Agar shunday bo'lsa, ushbu ot nomi bilan mavhum sinf yarating va undan sinflarni meros qilib oling. Masalan, Catva Dogmavhum sinfdan meros bo'lishi mumkin Animalva bu mavhum tayanch sinf nafas olish usulini amalga oshiradi void Breathe(), shuning uchun barcha hayvonlar bir xil tarzda bajaradilar. Mening sinfimga qanday fe'llar qo'llanilishi mumkin va boshqalarga nisbatan qo'llanilishi mumkin? Ushbu fe'llarning har biri uchun interfeys yarating. Masalan, barcha hayvonlar ovqat eyishi mumkin, shuning uchun men interfeys yarataman IFeedableva uni Animalushbu interfeysni amalga oshirishga majbur qilaman. Faqat interfeysni amalga oshirish uchun etarlicha yaxshi Dog( meni yoqtirishi mumkin), lekin hammasi emas. Kimdir aytdi: asosiy farq - bu sizning amalga oshirishni xohlagan joyingizda. Interfeys yaratganingizda, dasturni interfeysingizni amalga oshiradigan har qanday sinfga ko'chirishingiz mumkin. Mavhum sinf yaratish orqali siz barcha olingan sinflarning bajarilishini bir joyda baham ko'rishingiz va kodni takrorlash kabi ko'plab yomon narsalardan qochishingiz mumkin. HorseILikeable

StringBuffer xotirani qanday saqlaydi?

Sinf Stringo'zgarmas ob'ekt sifatida amalga oshiriladi, ya'ni siz dastlab ob'ektga biror narsa qo'yishga qaror qilganingizda String, virtual mashina aniq uzunlikdagi massivni asl qiymatingiz o'lchamiga ajratadi. Keyinchalik, bu virtual mashina ichida doimiy sifatida ko'rib chiqiladi, agar satr qiymati o'zgarmasa, unumdorlikni sezilarli darajada oshiradi. Biroq, agar siz satr tarkibini biron-bir tarzda o'zgartirishga qaror qilsangiz, virtual mashina aslida asl satr tarkibini vaqtinchalik bo'sh joyga ko'chiradi, o'zgartirishlaringizni kiriting va keyin ushbu o'zgarishlarni yangi xotira qatoriga saqlang. Shunday qilib, ishga tushirilgandan so'ng satr qiymatiga o'zgartirish kiritish qimmat operatsiya hisoblanadi. StringBuffer, boshqa tomondan, virtual mashina ichida dinamik ravishda kengayadigan massiv sifatida amalga oshiriladi, ya'ni mavjud xotira katakchasida har qanday o'zgartirish operatsiyasi amalga oshirilishi mumkin va kerak bo'lganda yangi xotira ajratiladi. Biroq, virtual mashina uchun optimallashtirishni amalga oshirishning hech qanday usuli yo'q, StringBufferchunki uning mazmuni har bir misol uchun mos kelmaydigan hisoblanadi.

Nima uchun kutish va xabar berish usullari Thread o'rniga Object sinfida e'lon qilingan?

wait, notify, usullari notifyAllfaqat sizning mavzularingiz umumiy resurslarga kirishini xohlaganingizda kerak bo'ladi va umumiy resurs to'plamdagi har qanday java ob'ekti bo'lishi mumkin. Shunday qilib, bu usullar asosiy sinfda aniqlanadi Object, shunda har bir ob'ekt o'z monitorida iplarni kutish imkonini beruvchi boshqaruvga ega bo'ladi. Java-da umumiy manbani almashish uchun ishlatiladigan maxsus ob'ekt yo'q. Bunday ma'lumotlar strukturasi aniqlanmagan. ObjectShuning uchun, umumiy manbaga aylanish va , , wait()kabi yordamchi usullarni taqdim etish sinfning mas'uliyatidir . Java Charlz Xoarning monitor haqidagi g'oyasiga asoslanadi. Java-da barcha ob'ektlar monitorga ega. Mavzular monitorlarda kutiladi, shuning uchun kutish uchun bizga ikkita parametr kerak bo'ladi: notify()notifyAll()
  • ip
  • monitor (har qanday ob'ekt).
Java dizaynida ipni aniq belgilab bo'lmaydi; u har doim kodni bajaruvchi joriy oqimdir. Shu bilan birga, biz monitorni belgilashimiz mumkin (bu biz metod deb atashimiz mumkin bo'lgan ob'ekt wait). Bu yaxshi dizayn, chunki agar biz boshqa har qanday mavzuni ma'lum bir monitorda kutishga majbur qilsak, bu "bosqinga" olib keladi va parallel dasturlarni loyihalash/dasturlashni qiyinlashtiradi. Esda tutingki, Java-da boshqa oqimlarga xalaqit beradigan barcha operatsiyalar eskirgan (masalan, stop()).

Java-da blokirovka yaratish va uni tuzatish uchun dastur yozing

Java-da deadlock, bu kamida ikkita ip turli manbalarda blokni ushlab turadigan va ikkalasi ham o'z vazifalarini bajarish uchun boshqa resurs mavjud bo'lishini kutadigan holat. Va ularning hech biri ushlab turilgan resursda qulf qoldira olmaydi. Java yadrosi.  Suhbat uchun savollar, 2 - 2 qism Misol dastur:
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;
		}
	}
}
Yuqoridagi kodni ishga tushirish juda aniq sabablarga ko'ra boshi berk ko'chaga olib keladi (yuqorida tushuntirilgan). Endi biz bu muammoni hal qilishimiz kerak. Men har qanday muammoning yechimi muammoning o‘zida yotadi, deb hisoblayman. Bizning holatda, A va B ga kirish modeli asosiy muammodir. Shuning uchun, uni hal qilish uchun biz oddiygina umumiy resurslarga kirish operatorlarining tartibini o'zgartiramiz. O'zgartirishdan keyin u quyidagicha ko'rinadi:
// 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");
			}
		}
	}
};
Ushbu kursni qayta ishga tushiring va endi siz boshi berk ko'chani ko'rmaysiz. Umid qilamanki, bu sizga to'siqlardan qochishga yordam beradi va agar siz ularga duch kelsangiz, ulardan xalos bo'lishingiz mumkin.

Agar Serializable interfeysini qo'llaydigan sinfingiz seriyalashtirilmaydigan komponentni o'z ichiga olsa nima bo'ladi? Buni qanday tuzatish kerak?

NotSerializableExceptionBunday holda, u ijro paytida tashlanadi . Ushbu muammoni hal qilish uchun juda oddiy echim bor - bu katakchalarni belgilang transient. Bu shuni anglatadiki, belgilangan maydonlar ketma-ketlashtirilmaydi. Agar siz ushbu maydonlarning holatini ham saqlamoqchi bo'lsangiz, Serializable. readResolve()Shuningdek, va usullaridan foydalanishingiz kerak bo'lishi mumkin writeResolve(). Keling, xulosa qilaylik:
  • Birinchidan, maydoningizni seriyali bo'lmaydigan qilib qo'ying transient.
  • Birinchidan writeObject, defaultWriteObjectbarcha bo'lmagan maydonlarni saqlash uchun ipga qo'ng'iroq qiling transient, so'ngra ketma-ketlashtirilmaydigan ob'ektingizning individual xususiyatlarini ketma-ketlashtirish uchun qolgan usullarni chaqiring.
  • da readObject, avval defaultReadObjectbarcha bo'lmagan maydonlarni o'qish uchun oqimga qo'ng'iroq qiling transient, so'ngra ob'ektingizni seriyadan chiqarish uchun boshqa usullarni (siz qo'shganlarga mos keladigan writeObject) chaqiring transient.

Java tilidagi vaqtinchalik va o'zgaruvchan kalit so'zlarni tushuntiring

"Kalit so'z transientketma-ketlashtirilmaydigan maydonlarni ko'rsatish uchun ishlatiladi." Java tili spetsifikatsiyasiga ko'ra: O'zgaruvchilar ob'ektning doimiy holatining bir qismi emasligini ko'rsatish uchun vaqtinchalik indikator bilan belgilanishi mumkin. Misol uchun, siz boshqa maydonlardan olingan maydonlarni o'z ichiga olishi mumkin va ularni ketma-ketlashtirish orqali ularning holatini tiklashdan ko'ra, dasturiy tarzda olish afzalroqdir. Misol uchun, sinfda (direktor) va (stavka) BankPayment.javakabi maydonlar seriyali bo'lishi mumkin va (hisoblangan foizlar) istalgan vaqtda, hatto seriyadan chiqarilgandan keyin ham hisoblanishi mumkin. Eslasak, Java-dagi har bir ip o'zining mahalliy xotirasiga ega va shu lokal xotirada o'qish/yozish amallarini bajaradi. Barcha amallar bajarilganda, u o'zgaruvchining o'zgartirilgan holatini umumiy xotiraga yozadi, bu erdan barcha oqimlar o'zgaruvchiga kirishadi. Odatda, bu virtual mashina ichidagi oddiy ip. Ammo o'zgaruvchan modifikator virtual mashinaga ipning ushbu o'zgaruvchiga kirishi har doim ushbu o'zgaruvchining o'z nusxasi bilan xotiradagi o'zgaruvchining asosiy nusxasi bilan mos kelishi kerakligini aytadi. Bu shuni anglatadiki, har safar ip o'zgaruvchining holatini o'qishni xohlasa, u ichki xotira holatini tozalashi va o'zgaruvchini asosiy xotiradan yangilashi kerak. qulfsiz algoritmlarda eng foydali. Siz umumiy ma'lumotlarni saqlaydigan o'zgaruvchini o'zgaruvchan deb belgilaysiz, keyin siz ushbu o'zgaruvchiga kirish uchun qulflardan foydalanmaysiz va bitta ip tomonidan kiritilgan barcha o'zgarishlar boshqalarga ko'rinadi. Yoki hisob-kitoblar takrorlanmasligini ta'minlash uchun "keyin sodir bo'ldi" munosabatini yaratmoqchi bo'lsangiz, o'zgarishlar real vaqtda ko'rinishini ta'minlash uchun yana bir bor. Ko'p tarmoqli muhitda o'zgarmas ob'ektlarni xavfsiz nashr qilish uchun uchuvchidan foydalanish kerak. Maydon deklaratsiyasi barcha ish zarralari har doim misol uchun mavjud havolani ko'rishini ta'minlaydi. principalrateinterestVolatilepublic volatile ImmutableObject

Iterator va ListIterator o'rtasidagi farq?

Biz foydalanishimiz mumkin yoki elementlarni Iteratortakrorlash uchun . Lekin u faqat elementlarni takrorlash uchun ishlatilishi mumkin . Boshqa farqlar quyida tavsiflanadi. Siz .. qila olasiz; siz ... mumkin: SetListMapListIteratorList
  1. teskari tartibda takrorlang.
  2. istalgan joyda indeksni oling.
  3. istalgan joyda istalgan qiymatni qo'shing.
  4. joriy holatda istalgan qiymatni o'rnating.
O'qishlaringizga omad!! Maqola muallifi Lokesh Gupta Original maqola Java Core. Intervyu savollari, Java Core 1-qism. Intervyu uchun savollar, 3-qism
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION