Java Core сөзін алғаш рет естігендер үшін бұл тілдің іргелі негіздері. Осы біліммен сіз тағылымдамадан өтуге / тағылымдамадан өтуге болады.
Бұл сұрақтар сұхбат алдында біліміңізді жаңартуға немесе өзіңіз үшін жаңа нәрсені үйренуге көмектеседі. Практикалық дағдыларды алу үшін JavaRush бағдарламасында оқыңыз . Түпнұсқа мақала Басқа бөліктерге сілтемелер: Java Core. Сұхбат сұрақтары, Java Core 1 бөлімі. Сұхбатқа арналған сұрақтар, 3 бөлім
Мысал бағдарлама:
Неліктен finalize() әдісінен аулақ болу керек?
Біз бәрімізге белгілі бір әдістіfinalize()
an object алып жатқан жадты босату алдында қоқыс жинаушы шақырады. Міне, әдісті шақыруға 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 блогында In catch блогында In sonunda блок In try block In catch block In sonunda block In try block In catch block In sonunda блок Таң қаларлықтай әдіс finalize
ешбір ағын үшін орындалмады. Бұл менің сөздерімді дәлелдейді. Менің ойымша, бұл аяқтаушылардың жеке қоқыс жинаушы ағынымен орындалады. Егер Java виртуалды машинасы тым ерте аяқталса, қоқыс жинағышта аяқтағыштарды жасауға және орындауға жеткілікті уақыт болмайды. Бұл әдісті қолданбаудың басқа себептері finalize()
болуы мүмкін:
- Әдіс
finalize()
конструкторлар сияқты тізбектермен жұмыс істемейді. Бұл класс конструкторын шақырған кезде суперкласс конструкторлары сөзсіз шақырылатынын білдіреді. Бірақ әдіс жағдайындаfinalize()
бұл орындалмайды. Суперкласс әдісінfinalize()
анық түрде шақыру керек. - Әдіспен шығарылған кез келген ерекшелік
finalize
қоқыс жинаушы ағынымен еленбейді және одан әрі таралмайды, яғни оқиға журналдарыңызда жазылмайды. Бұл өте жаман, солай емес пе? -
Сондай-ақ, әдіс
finalize()
сіздің сыныбыңызда болса, сізге айтарлықтай өнімділік жазасы беріледі. Тиімді бағдарламалауда (2-ші басылым) Джошуа Блох:
«Иә, және тағы бір нәрсе: аяқтағыштарды пайдалану кезінде үлкен өнімділік айыппұлы бар. Менің құрылғымда қарапайым нысандарды жасау және жою уақыты шамамен 5,6 наносекундты құрайды.
Аяқтаушыны қосу уақытты 2400 наносекундқа дейін арттырады. Басқаша айтқанда, аяқтау құралы бар нысанды жасау және жою шамамен 430 есе баяу».
Неліктен HashMap көп ағынды ортада пайдаланылмауы керек? Бұл шексіз циклды тудыруы мүмкін бе?
БізHashMap
бұл синхрондалмаған жинақ екенін білеміз, оның синхрондалған аналогы HashTable
. Сонымен, жинаққа қатынасқанда және барлық ағындар жинақтың бір данасына қатынасы бар көп ағынды ортада, оны HashTable
лас оқуларды болдырмау және деректердің сәйкестігін қамтамасыз ету сияқты анық себептермен пайдалану қауіпсіз болады. Ең нашар жағдайда, бұл көп ағынды орта шексіз циклды тудырады. Иә бұл шындық. HashMap.get()
шексіз цикл тудыруы мүмкін. Қалай көрейік? Егер әдістің бастапқы codeын қарасаңыз 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);
Бұл code бөлігі, егер өлшемін өзгерту басқа ағын карта данасын өзгертуге әрекеттенуімен бір уақытта орын алса, шексіз цикл жасауға бейім болады ( HashMap
). Бұл сценарийді болдырмаудың жалғыз жолы - codeта синхрондауды пайдалану немесе жақсырақ, синхрондалған топтаманы пайдалану.
Абстракция мен инкапсуляцияны түсіндіріңіз. Олар қалай байланысты?
Қарапайым сөзбен айтқанда , « Абстракция тек ағымдағы көрініс үшін маңызды болып табылатын нысанның қасиеттерін көрсетеді » . Объектіге бағытталған программалау теориясында абстракция жұмысты орындай алатын, өз күйіндегі өзгерістерді өзгертетін және хабарлай алатын, жүйедегі басқа an objectілермен «өзара әрекеттесетін» абстрактілі «актерлерді» бейнелейтін an objectілерді анықтау мүмкіндігін қамтиды. Кез келген бағдарламалау тілінде абстракция көптеген жолдармен жұмыс істейді. Мұны төменгі деңгейлі тіл пәрмендері үшін интерфейстерді анықтау тәртібін жасаудан көруге болады. Кейбір абстракциялар жобалау үлгілері сияқты құрастырылған абстракцияларды толығымен жасыру арқылы бағдарламашының қажеттіліктерін жалпы ұсынудың кеңдігін шектеуге тырысады. Әдетте абстракцияны екі жолмен көруге болады: Деректерді абстракциялау күрделі деректер түрлерін жасау және деректер үлгісімен өзара әрекеттесу үшін тек мағыналы операцияларды көрсету тәсілі, сонымен бірге сыртқы әлемнен барлық іске асыру мәліметтерін жасырады. Орындау абстракциясы - бұл барлық маңызды мәлімдемелерді анықтау және оларды жұмыс бірлігі ретінде көрсету процесі. Біз әдетте бұл мүмкіндікті кейбір жұмыстарды орындау әдісін жасағанда пайдаланамыз. Жасыруды орындаумен (қолжетімділікті басқаруды пайдалану) бірге сыныптар ішінде деректер мен әдістерді шектеу көбінесе инкапсуляция деп аталады. Нәтиже сипаттамалары мен мінез-құлқы бар деректер түрі болып табылады. Инкапсуляция негізінен деректерді жасыруды және іске асыруды жасыруды қамтиды. «Өзгеруі мүмкін барлық нәрсені инкапсуляциялау» . Бұл дәйексөз белгілі дизайн принципі болып табылады. Осыған байланысты, кез келген сыныпта деректер өзгерістері орындалу уақытында болуы мүмкін және іске асыру өзгерістері болашақ нұсқаларда болуы мүмкін. Осылайша, инкапсуляция деректерге де, іске асыруға да қолданылады. Сондықтан оларды келесідей қосуға болады:- Абстракция - бұл класс не істей алады [Идея]
- Инкапсуляция көбірек Бұл функционалдылыққа қалай қол жеткізуге болады [Іске асыру]
Интерфейс пен дерексіз класс арасындағы айырмашылықтар?
Негізгі айырмашылықтарды келесідей көрсетуге болады:- Интерфейс кез келген әдістерді жүзеге асыра алмайды, бірақ абстрактілі класс жасай алады.
- Класс көптеген интерфейстерді жүзеге асыра алады, бірақ тек бір суперкласс болуы мүмкін (дерексіз немесе дерексіз)
- Интерфейс класс иерархиясының бөлігі емес. Байланысты емес сыныптар бірдей интерфейсті жүзеге асыра алады.
Cat
және Dog
абстрактілі сыныптан мұра алады Animal
және бұл дерексіз базалық класс тыныс алу әдісін жүзеге асырады void Breathe()
, осылайша барлық жануарлар бірдей орындайтын болады. Менің сыныбыма қандай етістіктерді қолдануға болады және басқаларға қолдануға болады? Осы етістіктердің әрқайсысы үшін интерфейс жасаңыз. Мысалы, барлық жануарлар жей алады, сондықтан мен интерфейс жасаймын IFeedable
және оны Animal
сол интерфейсті жүзеге асырамын. Интерфейсті іске асыру үшін жеткілікті жақсы ( Dog
мені ұната алады), бірақ бәрі емес. Біреу айтты: басты айырмашылық - сіз іске асырғыңыз келетін жерде. Интерфейсті жасаған кезде іске асыруды интерфейсті жүзеге асыратын кез келген сыныпқа жылжытуға болады. Абстрактілі класс жасау арқылы сіз барлық туынды сыныптардың орындалуын бір жерде бөлісе аласыз және codeты қайталау сияқты көптеген жаман нәрселерден аулақ бола аласыз. Horse
ILikeable
StringBuffer жадты қалай сақтайды?
КлассString
өзгермейтін нысан ретінде жүзеге асырылады, яғни сіз бастапқыда нысанға бірдеңе қоюды шешкен кезде String
, виртуалды машина сіздің бастапқы мәніңіздің дәл өлшеміне сәйкес тұрақты ұзындықты массив бөледі. Содан кейін бұл виртуалды машинаның ішіндегі тұрақты мән ретінде қарастырылады, ол жолдың мәні өзгермесе, өнімділікті айтарлықтай жақсартуды қамтамасыз етеді. Дегенмен, жолдың мазмұнын қандай да бір жолмен өзгертуді шешсеңіз, виртуалды машина шын мәнінде бастапқы жолдың мазмұнын уақытша кеңістікке көшіру, өзгертулерді енгізу, содан кейін сол өзгертулерді жаңа жад массивіне сақтау болып табылады. Осылайша, инициализациядан кейін жолдың мәніне өзгертулер енгізу қымбат операция болып табылады. StringBuffer
, екінші жағынан, виртуалды машинаның ішінде динамикалық түрде кеңейетін массив ретінде жүзеге асырылады, бұл кез келген өзгерту операциясы бар жад ұяшығында орын алуы мүмкін және қажет болған жағдайда жаңа жад бөлінетінін білдіреді. Дегенмен, виртуалды машинаның оңтайландыруды орындау мүмкіндігі жоқ, StringBuffer
себебі оның мазмұны әрбір данада сәйкес емес деп саналады.
Неліктен күту және хабарландыру әдістері Thread орнына Object сыныбында жарияланған?
wait
, notify
, әдістері notifyAll
ағындарыңыздың ортақ ресурстарға қатынасуын қаласаңыз және ортақ ресурс үймедегі кез келген java нысаны болуы мүмкін болғанда ғана қажет. Осылайша, бұл әдістер негізгі сыныпта анықталған Object
, сондықтан әрбір нысанда ағындардың мониторында күтуіне мүмкіндік беретін басқару элементі болады. Java-да ортақ ресурсты ортақ пайдалану үшін пайдаланылатын арнайы нысан жоқ. Мұндай деректер құрылымы анықталмаған. Object
Сондықтан ортақ ресурсқа айналу және wait()
, notify()
, сияқты көмекші әдістерді қамтамасыз ету сыныптың міндеті notifyAll()
. Java Чарльз Хоардың мониторлар идеясына негізделген. Java тілінде барлық an objectілерде монитор бар. Мониторларда ағындар күтеді, сондықтан күтуді орындау үшін бізге екі параметр қажет:
- жіп
- монитор (кез келген нысан).
wait
). Бұл жақсы дизайн, өйткені егер біз кез келген басқа ағынды белгілі бір мониторда күтуге мәжбүрлей алсақ, ол «басқыншылыққа» әкеледі, бұл параллельді бағдарламаларды жобалау/бағдарламалауды қиындатады. Java тілінде басқа ағындарға кедергі келтіретін барлық әрекеттер ескіргенін есте сақтаңыз (мысалы, stop()
).
Java тілінде тығырыққа тірелетін бағдарламаны жазыңыз және оны түзетіңіз
Java-даdeadlock
бұл кем дегенде екі ағын әртүрлі ресурстарда блокты ұстайтын және екеуі де басқа ресурстың өз тапсырмасын орындау үшін қолжетімді болуын күтетін жағдай. Және олардың ешқайсысы ұстап тұрған ресурста құлыпты қалдыра алмайды. ![Java ядросы. Сұхбатқа арналған сұрақтар, 2 - 2 бөлім](https://cdn.javarush.com/images/article/5f7eb0a9-0861-4f37-bdd2-f62548c67f79/original.jpeg)
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;
}
}
}
Жоғарыдағы codeты іске қосу өте айқын себептерге байланысты (жоғарыда түсіндірілді) тығырыққа әкеледі. Енді бұл мәселені шешуіміз керек. Кез келген мәселенің шешімі сол мәселенің түбінде жатыр деп есептеймін. Біздің жағдайда А және В-ға қол жеткізу моделі басты мәселе болып табылады. Сондықтан оны шешу үшін біз жай ғана қол жеткізу операторларының ретін ортақ ресурстарға ауыстырамыз. Өзгертуден кейін ол келесідей болады:
// 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");
}
}
}
};
Бұл сыныпты қайта іске қосыңыз, енді сіз тығырықты көрмейсіз. Бұл тығырықтан аулақ болуға және олар кездескен жағдайда олардан құтылуға көмектеседі деп үміттенемін.
Серияланатын интерфейсті жүзеге асыратын сыныпта серияланbyteын компонент болса не болады? Мұны қалай түзетуге болады?
NotSerializableException
Бұл жағдайда ол орындау кезінде лақтырылады . Бұл мәселені шешу үшін өте қарапайым шешім бар - осы құсбелгілерді қойыңыз transient
. Бұл тексерілген өрістер серияланбайды дегенді білдіреді. Егер сіз сондай-ақ осы өрістердің күйін сақтағыңыз келсе, қазірдің өзінде Serializable
. readResolve()
Сондай-ақ және әдістерін пайдалану қажет болуы мүмкін writeResolve()
. Жинақтау:
- Біріншіден, өрісті серияланbyteын етіп жасаңыз
transient
. - Алдымен
writeObject
,defaultWriteObject
барлық емес өрістерді сақтау үшін ағынды шақырыңызtransient
, содан кейін серияланbyteын нысанның жеке сипаттарын сериялау үшін қалған әдістерді шақырыңыз. - ішінде барлық емес өрістерді оқу үшін
readObject
алдыменdefaultReadObject
ағынға қоңырау шалыңыз, содан кейін емес нысанды сериядан шығару үшінtransient
басқа әдістерді (сіз қосқандарыңызға сәйкес) шақырыңыз .writeObject
transient
Java тіліндегі өтпелі және өзгермелі кілт сөздерді түсіндіріңіз
"Кілт сөзtransient
серияланbyteын өрістерді көрсету үшін пайдаланылады." Java тілінің спецификациясына сәйкес: айнымалылар нысанның тұрақты күйінің бөлігі емес екенін көрсету үшін өтпелі индикатормен белгіленуі мүмкін. Мысалы, сізде басқа өрістерден алынған өрістер болуы мүмкін және олардың күйін сериялау арқылы қалпына келтіргеннен гөрі, бағдарламалық жолмен алған дұрыс. Мысалы, сыныпта (директор) және (ставка) BankPayment.java
сияқты өрістер сериялануы мүмкін және (есептелген пайыздар) кез келген уақытта, тіпті сериядан шығарылғаннан кейін де есептелуі мүмкін. Есімізде болса, Java-дағы әрбір ағынның өзінің жергілікті жады бар және осы жергілікті жадта оқу/жазу операцияларын орындайды. Барлық әрекеттер орындалғанда, ол айнымалының өзгертілген күйін барлық ағындар айнымалыға қатынасатын ортақ жадқа жазады. Әдетте, бұл виртуалды машинаның ішіндегі қалыпты ағын. Бірақ өзгермелі модификатор виртуалды машинаға ағынның сол айнымалыға қол жеткізуі әрқашан сол айнымалының жеке көшірмесімен жадтағы айнымалының басты көшірмесімен сәйкес келуі керек екенін айтады. Бұл ағын айнымалының күйін оқығысы келген сайын ішкі жад күйін тазартып, айнымалыны негізгі жадтан жаңарту керек дегенді білдіреді. құлыпсыз алгоритмдерде ең пайдалы. Ортақ деректерді сақтайтын айнымалы мәнді өзгермелі деп белгілейсіз, содан кейін бұл айнымалы мәнге қол жеткізу үшін құлыптарды қолданбайсыз және бір ағынмен жасалған барлық өзгертулер басқаларға көрінетін болады. Немесе өзгертулердің нақты уақытта көрінуін қамтамасыз ету үшін есептеулердің қайталанбауын қамтамасыз ету үшін «болған соң» қатынасын жасағыңыз келсе. Ұшқышты көп ағынды ортада өзгермейтін нысандарды қауіпсіз жариялау үшін пайдалану керек. Өріс декларациясы барлық ағындардың әрқашан данаға ағымдағы қол жетімді сілтемені көруін қамтамасыз етеді. principal
rate
interest
Volatile
public volatile ImmutableObject
Итератор мен ListIterator арасындағы айырмашылық?
Біз пайдалана аламыз немесе элементтердіIterator
қайталау үшін . Бірақ оны элементтерді қайталау үшін ғана пайдалануға болады . Басқа айырмашылықтар төменде сипатталған. Сен істе аласың: Set
List
Map
ListIterator
List
- кері ретпен қайталаңыз.
- индексті кез келген жерден алыңыз.
- кез келген жерде кез келген мәнді қосыңыз.
- ағымдағы орынға кез келген мәнді орнатыңыз.
GO TO FULL VERSION