JavaRush /Java Blogu /Random-AZ /Java nüvəsi. Müsahibə sualları, 2-ci hissə
Andrey
Səviyyə

Java nüvəsi. Müsahibə sualları, 2-ci hissə

Qrupda dərc edilmişdir
Java Core sözünü ilk dəfə eşidənlər üçün bunlar dilin əsas təməlləridir. Bu biliklə siz təhlükəsiz şəkildə staj/təcrübə üçün gedə bilərsiniz.
Java nüvəsi.  Müsahibə üçün suallar, 2-ci hissə - 1
Bu suallar müsahibədən əvvəl biliklərinizi yeniləməyə və ya özünüz üçün yeni bir şey öyrənməyə kömək edəcək. Praktik bacarıqlar əldə etmək üçün JavaRush -da təhsil alın . Orijinal məqalə Digər hissələrə keçidlər: Java Core. Müsahibə sualları, Java Core hissəsi 1. Müsahibə üçün suallar, 3-cü hissə

Niyə finalize() metodundan qaçınmaq lazımdır?

Biz hamımız bilirik ki, finalize()obyektin tutduğu yaddaşı boşaltmazdan əvvəl zibil yığan şəxs metodu çağırır. finalize()Metod çağırışına zəmanət verilmədiyini sübut edən bir proqram nümunəsidir :
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();
	}
	}
}
Nəticə: In try block In catch block In sonunda block In try block In catch block In Nəhayət blok In try block In catch block In sonunda block Təəccüblüdür ki, metod finalizeheç bir mövzu üçün icra olunmayıb. Bu mənim sözlərimi sübut edir. Düşünürəm ki, bunun səbəbi sonlaşdırıcıların ayrıca bir zibil toplayıcı ip tərəfindən icra edilməsidir. Java Virtual Maşın çox erkən bitirsə, zibil toplayıcının yekunlaşdırıcıları yaratmaq və icra etmək üçün kifayət qədər vaxtı yoxdur. Metoddan istifadə etməməyin digər səbəbləri finalize()ola bilər:
  1. Metod finalize()konstruktorlar kimi zəncirlərlə işləmir. Bu o deməkdir ki, siz sinif konstruktorunu çağırdığınız zaman supersinif konstruktorları qeyd-şərtsiz çağırılacaq. Ancaq metod vəziyyətində finalize()bu əməl etməyəcək. Superclass metodu finalize()açıq şəkildə çağırılmalıdır.
  2. Metod tərəfindən atılan hər hansı bir istisna finalizezibil toplayıcı ip tərəfindən nəzərə alınmır və daha da yayılmayacaq, yəni hadisə jurnallarınızda qeyd olunmayacaq. Bu çox pisdir, elə deyilmi?
  3. Metod finalize()sinifinizdə varsa, siz də əhəmiyyətli performans cəzası alırsınız. Effektiv Proqramlaşdırmada (2-ci nəşr) Joshua Bloch dedi:
    “Bəli və daha bir şey: yekunlaşdırıcılardan istifadə edərkən böyük bir performans cəzası var. Mənim maşınımda sadə obyektləri yaratmaq və məhv etmək vaxtı təxminən 5,6 nanosaniyədir.
    Sonlandırıcının əlavə edilməsi vaxtı 2400 nanosaniyəyə qədər artırır. Başqa sözlə, yekunlaşdırıcı ilə obyekt yaratmaq və silmək təxminən 430 dəfə yavaşdır”.

Niyə HashMap çox yivli mühitdə istifadə edilməməlidir? Bu sonsuz bir döngəyə səbəb ola bilərmi?

Biz bilirik ki, HashMapbu, sinxronlaşdırılmamış kolleksiyadır, onun sinxron qarşılığı HashTable. Beləliklə, siz kolleksiyaya daxil olarkən və bütün mövzuların kolleksiyanın tək nümunəsinə çıxışı olan çox yivli mühitdə HashTableçirkli oxunmaların qarşısını almaq və məlumatların ardıcıllığını təmin etmək kimi aşkar səbəblərdən istifadə etmək daha təhlükəsizdir. Ən pis halda, bu çox yivli mühit sonsuz döngəyə səbəb olacaq. Bəli doğrudur. HashMap.get()sonsuz döngəyə səbəb ola bilər. Görək necə? Metodun mənbə koduna baxsanız HashMap.get(Object key), bu belə görünür:
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)nədənsə e.nextözünə işarə edə bilsə, həmişə çox yivli iş mühitində sonsuz döngənin qurbanı ola bilər. Bu, sonsuz bir döngəyə səbəb olacaq, ancaq e.nextözünə necə işarə edəcək (yəni e)? Bu , ölçüsü dəyişdirilərkən void transfer(Entry[] newTable)çağırılan metodda baş verə bilər .HashMap
do {
    Entry next = e.next;
    int i = indexFor(e.hash, newCapacity);
    e.next = newTable[i];
    newTable[i] = e;
    e = next;
} while (e != null);
Ölçü dəyişməsi başqa bir başlığın xəritə nümunəsini dəyişməyə çalışdığı vaxt baş verərsə, bu kod parçası sonsuz döngə yaratmağa meyllidir ( HashMap). Bu ssenaridən qaçmağın yeganə yolu kodunuzda sinxronizasiyadan istifadə etmək və ya daha yaxşısı sinxronlaşdırılmış kolleksiyadan istifadə etməkdir.

Abstraksiya və inkapsulyasiyanı izah edin. Onlar necə bağlıdırlar?

Sadə sözlərlə desək , “ Abstraksiya obyektin yalnız cari görünüş üçün əhəmiyyətli olan xassələrini göstərir . ” Obyekt yönümlü proqramlaşdırma nəzəriyyəsində abstraksiya işi yerinə yetirə, öz vəziyyətində dəyişiklikləri dəyişə və xəbər verə bilən və sistemdəki digər obyektlərlə “qarşılıqlı əlaqədə olan” mücərrəd “aktyorları” təmsil edən obyektləri müəyyən etmək bacarığını nəzərdə tutur. İstənilən proqramlaşdırma dilində abstraksiya bir çox cəhətdən işləyir. Bunu aşağı səviyyəli dil əmrləri üçün interfeysləri müəyyən etmək üçün rutinlərin yaradılmasından görmək olar. Bəzi abstraksiyalar, dizayn nümunələri kimi üzərində qurulduqları abstraksiyaları tamamilə gizlətməklə proqramçının ehtiyaclarının ümumi təsvirinin genişliyini məhdudlaşdırmağa çalışır. Tipik olaraq, abstraksiya iki şəkildə görünə bilər: Məlumat abstraksiya mürəkkəb məlumat növləri yaratmaq və məlumat modeli ilə qarşılıqlı əlaqə yaratmaq üçün yalnız mənalı əməliyyatları ifşa etmək üsuludur, eyni zamanda bütün icra detallarını xarici dünyadan gizlədir. İcra mücərrədliyi bütün əhəmiyyətli ifadələrin müəyyən edilməsi və onların bir iş vahidi kimi ifşa edilməsi prosesidir. Biz adətən bəzi işləri görmək üçün metod yaratdıqda bu xüsusiyyətdən istifadə edirik. Gizlətmə (giriş nəzarətindən istifadə etməklə) ilə birlikdə siniflər daxilində məlumat və metodların məhdudlaşdırılması çox vaxt inkapsulyasiya adlanır. Nəticə xüsusiyyətləri və davranışı olan bir məlumat növüdür. İnkapsulyasiya həmçinin məlumatların gizlədilməsini və həyata keçirilməsinin gizlədilməsini də əhatə edir. "Dəyişə biləcək hər şeyi əhatə edin" . Bu sitat tanınmış dizayn prinsipidir. Bununla əlaqədar olaraq, istənilən sinifdə məlumat dəyişiklikləri icra zamanı baş verə bilər və tətbiqetmə dəyişiklikləri gələcək versiyalarda baş verə bilər. Beləliklə, inkapsulyasiya həm məlumatlara, həm də həyata keçirməyə aiddir. Beləliklə, onlar bu şəkildə bağlana bilər:
  • Abstraksiya əsasən sinfin edə biləcəyi şeydir [İdeya]
  • İnkapsulyasiya daha çoxdur Bu funksionallığa necə nail olmaq olar [İcra]

İnterfeys və abstrakt sinif arasındakı fərqlər?

Əsas fərqləri aşağıdakı kimi qeyd etmək olar:
  • İnterfeys heç bir metodu həyata keçirə bilməz, lakin abstrakt sinif edə bilər.
  • Bir sinif bir çox interfeys tətbiq edə bilər, lakin yalnız bir superclass ola bilər (mücərrəd və ya qeyri-mücərrəd)
  • İnterfeys sinif iyerarxiyasının bir hissəsi deyil. Əlaqəsiz siniflər eyni interfeysi həyata keçirə bilər.
Xatırlamalı olduğunuz şey budur: “Bir konsepsiyanı “necə etdiyini” təyin etmədən “nə edir” baxımından tam təsvir edə bildiyiniz zaman interfeysdən istifadə etməlisiniz. Bəzi icra təfərrüatlarını daxil etməlisinizsə, o zaman konsepsiyanızı mücərrəd bir sinifdə təmsil etməlisiniz." Həmçinin, başqa cür desək: “Birlikdə qruplaşdırıla” və tək isimlə təsvir edilə bilən siniflər çoxdurmu? Əgər belədirsə, bu ismin adı ilə mücərrəd sinif yaradın və ondan sinifləri miras alın. Məsələn, CatDogmücərrəd sinifdən miras ala bilər Animalvə bu mücərrəd əsas sinif metodunu həyata keçirəcək void Breathe()- nəfəs al, beləliklə bütün heyvanlar eyni şəkildə yerinə yetirəcəklər. Hansı felləri mənim sinfimə aid etmək olar və başqalarına şamil etmək olar? Bu fellərin hər biri üçün interfeys yaradın. Məsələn, bütün heyvanlar yeyə bilər, ona görə də mən interfeys yaradacağam IFeedableAnimalo interfeysi həyata keçirəcəm. Yalnız interfeysi həyata keçirmək üçün kifayət qədər yaxşıdır Dog( məni bəyənməyə qadirdir), lakin hamısı deyil. Biri dedi: əsas fərq, harada həyata keçirmək istədiyinizdir. İnterfeys yaratdığınız zaman tətbiqi interfeysinizi həyata keçirən istənilən sinfə köçürə bilərsiniz. Mücərrəd bir sinif yaratmaqla, bütün törəmə siniflərin tətbiqini bir yerdə paylaşa və kodun təkrarlanması kimi bir çox pis şeylərdən qaça bilərsiniz. HorseILikeable

StringBuffer yaddaşı necə saxlayır?

Sinif Stringdəyişməz obyekt kimi həyata keçirilir, yəni ilkin olaraq obyektə nəyisə yerləşdirmək qərarına gəldikdə String, virtual maşın ilkin dəyərinizin ölçüsünə uyğun olaraq sabit uzunluqlu massiv ayırır. Daha sonra bu, virtual maşın daxilində sabit kimi qəbul ediləcək və bu, sətirin dəyəri dəyişməzsə, əhəmiyyətli performans yaxşılaşdırılmasını təmin edir. Bununla belə, əgər sətirin məzmununu hər hansı bir şəkildə dəyişdirmək qərarına gəlsəniz, virtual maşının əslində etdiyi şey orijinal sətirin məzmununu müvəqqəti boşluğa köçürmək, dəyişikliklərinizi etmək və sonra bu dəyişiklikləri yeni yaddaş massivində saxlamaqdır. Beləliklə, inisializasiyadan sonra sətirin dəyərində dəyişiklik etmək bahalı əməliyyatdır. StringBuffer, digər tərəfdən, virtual maşın daxilində dinamik olaraq genişlənən massiv kimi həyata keçirilir, bu o deməkdir ki, mövcud yaddaş hüceyrəsində istənilən modifikasiya əməliyyatı baş verə bilər və lazım olduqda yeni yaddaş ayrılacaq. Bununla belə, virtual maşının optimallaşdırması üçün heç bir yol yoxdur, StringBufferçünki onun məzmunu hər bir nümunədə uyğunsuz hesab olunur.

Nə üçün gözləmə və bildiriş metodları Thread əvəzinə Obyekt sinfində elan edilir?

wait, notify, metodları notifyAllyalnız mövzularınızın paylaşılan resurslara daxil olmasını istədiyiniz zaman tələb olunur və paylaşılan resurs yığındakı hər hansı java obyekti ola bilər. Beləliklə, bu üsullar əsas sinifdə müəyyən edilir Objectki, hər bir obyekt öz monitorunda ipləri gözləməyə imkan verən idarəetməyə malik olsun. Java-da paylaşılan resursu paylaşmaq üçün istifadə olunan heç bir xüsusi obyekt yoxdur. Belə bir məlumat strukturu müəyyən edilməyib. ObjectBuna görə də, paylaşılan mənbəyə çevrilmək və wait(), notify(), kimi köməkçi üsulları təmin etmək sinfin məsuliyyətidir notifyAll(). Java Çarlz Hoarenin monitorlar ideyasına əsaslanır. Java-da bütün obyektlərin monitoru var. Mövzular monitorlarda gözləyir, buna görə gözləməni yerinə yetirmək üçün bizə iki parametr lazımdır:
  • bir ip
  • monitor (hər hansı bir obyekt).
Java dizaynında mövzu dəqiq müəyyən edilə bilməz; həmişə kodu icra edən cari ipdir. Bununla belə, biz bir monitor təyin edə bilərik (bu, metodu çağıra biləcəyimiz bir obyektdir wait). Bu, yaxşı dizayndır, çünki hər hansı digər mövzunu müəyyən bir monitorda gözləməyə məcbur edə bilsək, bu, paralel proqramların layihələndirilməsini/proqramlanmasını çətinləşdirərək “işğal”la nəticələnəcək. Unutmayın ki, Java-da digər mövzulara müdaxilə edən bütün əməliyyatlar köhnəlmişdir (məsələn, stop()).

Java-da çıxılmaz vəziyyət yaratmaq və onu düzəltmək üçün proqram yazın

Java-da deadlockbu, ən azı iki mövzunun müxtəlif resurslarda blok saxladığı və hər ikisinin tapşırıqlarını yerinə yetirmək üçün digər resursun əlçatan olmasını gözlədiyi bir vəziyyətdir. Və onların heç biri saxlanılan resursda kilid buraxa bilmir. Java nüvəsi.  Müsahibə üçün suallar, 2-ci hissə Nümunə proqram:
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;
		}
	}
}
Yuxarıdakı kodun işlədilməsi çox açıq səbəblərə görə (yuxarıda izah edilmişdir) dalana səbəb olacaqdır. İndi bu problemi həll etməliyik. Mən hesab edirəm ki, hər hansı bir problemin həlli problemin özündə dayanır. Bizim vəziyyətimizdə A və B-yə giriş modeli əsas problemdir. Buna görə də, onu həll etmək üçün biz sadəcə olaraq, ortaq resurslara giriş operatorlarının sırasını dəyişdiririk. Dəyişiklikdən sonra belə görünəcək:
// 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");
			}
		}
	}
};
Bu sinfi yenidən işə salın və indi çıxılmaz vəziyyəti görməyəcəksiniz. Ümid edirəm ki, bu, çıxılmaz vəziyyətdən qaçmağa və qarşılaşdığınız təqdirdə onlardan qurtulmağa kömək edir.

Seriallaşdırıla bilən interfeysi həyata keçirən sinifinizdə seriallaşdırıla bilməyən komponent varsa nə baş verir? Bunu necə düzəltmək olar?

NotSerializableExceptionBu halda, icra zamanı atılacaq . Bu problemi həll etmək üçün çox sadə bir həll var - bu qutuları yoxlayın transient. Bu o deməkdir ki, yoxlanılan sahələr seriallaşdırılmayacaq. Əgər siz də bu sahələrin vəziyyətini saxlamaq istəyirsinizsə, onda siz artıq Serializable. readResolve()və üsullarından da istifadə etməli ola bilərsiniz writeResolve(). Ümumiləşdirək:
  • Birincisi, sahənizi seriyalaşdırıla bilməyəcək hala gətirin transient.
  • Əvvəlcə bütün qeyri-sahələri saxlamaq üçün mövzuya writeObjectzəng edin , sonra seriallaşdırıla bilməyən obyektinizin fərdi xüsusiyyətlərini seriallaşdırmaq üçün qalan metodları çağırın.defaultWriteObjecttransient
  • -də readObjectəvvəlcə defaultReadObjectbütün qeyri sahələri oxumaq üçün axına zəng edin transient, sonra qeyri-obyektinizi seriyadan çıxarmaq üçün digər metodlara (əlavə etdiyinizlərə uyğun writeObject) zəng edin transient.

Java-da keçici və dəyişkən açar sözləri izah edin

"Açar söz transientseriallaşdırılmayacaq sahələri göstərmək üçün istifadə olunur." Java Dilinin Spesifikasiyasına əsasən: Dəyişənlər obyektin davamlı vəziyyətinin bir hissəsi olmadığını göstərmək üçün keçid göstəricisi ilə qeyd edilə bilər. Məsələn, siz digər sahələrdən əldə edilmiş sahələri ehtiva edə bilərsiniz və serializasiya yolu ilə onların vəziyyətini bərpa etməkdənsə, onları proqramlı şəkildə əldə etmək üstünlük təşkil edir. Məsələn, bir sinifdə (direktor) və (dərəcə) BankPayment.javakimi sahələr seriyalaşdırıla bilər və (hesablanmış faizlər) istənilən vaxt, hətta seriyadan çıxarıldıqdan sonra da hesablana bilər. Xatırlasaq, Java-da hər bir ipin öz lokal yaddaşı var və bu lokal yaddaşda oxu/yazma əməliyyatlarını yerinə yetirir. Bütün əməliyyatlar yerinə yetirildikdə, dəyişənin dəyişdirilmiş vəziyyətini paylaşılan yaddaşa yazır, buradan bütün mövzular dəyişənə daxil olur. Tipik olaraq, bu, virtual maşın içərisində normal bir mövzudur. Lakin uçucu modifikator virtual maşına deyir ki, mövzunun həmin dəyişənə girişi həmişə həmin dəyişənin öz nüsxəsi ilə yaddaşdakı dəyişənin master surəti ilə uyğun olmalıdır. Bu o deməkdir ki, ip hər dəfə dəyişənin vəziyyətini oxumaq istəyəndə daxili yaddaş vəziyyətini təmizləməli və dəyişəni əsas yaddaşdan yeniləməlidir. kilidsiz alqoritmlərdə ən faydalıdır. Paylaşılan məlumatları dəyişkən olaraq saxlayan dəyişəni qeyd edirsiniz, sonra həmin dəyişənə daxil olmaq üçün kilidlərdən istifadə etmirsiniz və bir başlıq tərəfindən edilən bütün dəyişikliklər başqalarına görünəcək. Və ya hesablamaların təkrarlanmamasını təmin etmək üçün "sonra baş verdi" əlaqəsi yaratmaq istəyirsinizsə, dəyişikliklərin real vaxtda görünməsini təmin etmək üçün yenidən. Dəyişməz obyektləri çox yivli mühitdə təhlükəsiz dərc etmək üçün uçucu istifadə edilməlidir. Sahə bəyannaməsi bütün mövzuların həmişə nümunə üçün mövcud olan istinadı görməsini təmin edir. principalrateinterestVolatilepublic volatile ImmutableObject

İterator və ListIterator arasındakı fərq?

Biz istifadə edə bilərik və ya Iteratorelementləri təkrarlamaq üçün . Lakin o, yalnız elementləri təkrarlamaq üçün istifadə edilə bilər . Digər fərqlər aşağıda təsvir edilmişdir. Bacararsan: SetListMapListIteratorList
  1. tərs qaydada təkrarlayın.
  2. istənilən yerdə indeks əldə edin.
  3. hər hansı bir dəyər əlavə edin.
  4. cari mövqedə istənilən dəyəri təyin edin.
Təhsilinizdə uğurlar!! Məqalənin müəllifi Lokesh Gupta Orijinal məqalə Java Core. Müsahibə sualları, Java Core hissəsi 1. Müsahibə üçün suallar, 3-cü hissə
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION