JavaRush /Java блогы /Random-KK /Бір сұхбаттың оқиғасы: қызықты сұрақтар
GuitarFactor
Деңгей
Санкт-Петербург

Бір сұхбаттың оқиғасы: қызықты сұрақтар

Топта жарияланған
Жақында мен ірі IT-компаниялардың бірінде тағылымдамадан өту үшін сұхбатқа қатысу мүмкіндігіне ие болдым. Бір сұхбаттың оқиғасы: қызықты сұрақтар – 1Бұл менің IT саласындағы алғашқы сұхбатым болды және менің ойымша, қызықты болды. Жалпы, мен 3 сағаттан астам уақыт бойы «жауап алды» (оның алдында үй тапсырмасы және кеңседе компьютерде тест тапсырылды). Қойылған сұраққа қате жауап бергенде тайынбай, жетекші сұрақтары арқылы ойланып, дұрыс жауапқа келуге мәжбүр еткен сұхбат берушіге құрмет көрсеткім келеді. Төменде мен бірнеше «эскиздерді» ұсынамын - менің ойымша, өте қызықты сұрақтар, олардың кейбіреулері маған Java тіліндегі кейбір аспектілерді тереңірек түсінуге мүмкіндік берді. Мүмкін бұл нәрселер кейбіреулерге түсінікті болып көрінуі мүмкін, бірақ бұл пайдалы болатындар болады деп ойлаймын. Төменде фразалар келесі қаріптермен ерекшеленген: Сұхбат беруші - қалың дауыспен түсіндіру және менің ойым - курсивпен Менің жауаптарым - кәдімгі шрифтпен Біз фонмен жұмысты аяқтадық, іске кірісейік)

Эскиз 1. «Бір қарағанда қарапайым әдіс»

а санын b санына бөлудің нәтижесін беретін әдісті қалай орындайтыныңызды жазыңыз.Интервьюер қағазға жазады
int divide(int a, int b) {
}
*Әдіс қолтаңбасы бар қағазға сенбей қарадым. Бұл не?* Мен жазамын:
int divide(int a, int b) {
    return a/b;
}
Бұл әдіспен проблемалар бар ма? *Мен шынымен ақымақ ақымақты ұстап жатырмын* Жоқ сияқты.. Келесі заңды сұрақ туындайды: b=0 болса ше? *Ой, осылай жүре берсем, мені кеңседен қуып жіберетін шығармын!* Иә, әрине. Мұнда int түріндегі дәлелдер бар, сондықтан арифметикалық ерекшелік тасталады. Егер аргументтер float немесе double типті болса, нәтиже Infinity болар еді. Бұл туралы не істейміз? Мен try/catch деп жаза бастадым
int divide(int a, int b) {
    try {
        return a/b;
    } catch (Exception e) {
        e.printStackTrace();
        return ... // ??? what the hack?
    }
}
*Мен оралып, қатып қалуым керек: қате болған жағдайда бір нәрсені қайтару керек. Бірақ бұл «бірдеңені» есептеу нәтижесінен қалай ажыратуға болады?* Біз не қайтарамыз? Мм... Мен қайтарылатын айнымалының түрін Integer деп өзгертетін едім және ерекше жағдайда нөлді қайтаратын едім. Түрін өзгерте алмаймыз деп елестетейік. Біз қандай да бір жолмен шыға аламыз ба? Мүмкін біз ерекшеліктен басқа бірдеңе жасай аламыз ба? *Міне, келді* Біз оны шақыру әдісіне де жібере аламыз! Дұрыс. Ол қандай болады?
int divide(int a, int b) throws ArithmeticException{
    return a/b;
}

void callDivide(int a, int b) {
    try {
        divide(a, b);
    } catch (ArithmeticException e) {
        e.printStackTrace();
    }
}
Ерекше жағдайды өңдеу қажет пе? Иә, өйткені біз оны бөлу әдісінен анық жібереміз. (*Мен бұл жерде қателесіппін! Төменде сұхбат алушының дұрыс жауапқа әкелетін жетекші сұрақтары берілген*) Ал арифметикалық ерекшелік - бұл қандай ерекшелік - тексерілген немесе белгіленбеген? Бұл Орындалу уақытының ерекше жағдайы, яғни құсбелгі алынбаған. *Міне, өлтіруші сұрақ туындайды* Сонымен, сіздің сөзіңізше, егер біз әдіс қолтаңбасында арифметикалық ерекшелік тастайтынын көрсетсек, онда ол тексерілген ерекшелік болды ма? *Уф!* Мүмкін... жоқ. Иә, кетті. Қолтаңбада тастауларды /тексерілмеген ерекшелік/ көрсетсек, әдіс ерекше жағдайды шығара алатынын ғана ескертеміз, бірақ оны шақыру әдісінде өңдеу қажет емес. Бұл реттелді. Қателіктерді болдырмау үшін біз жасай алатын тағы бір нәрсе бар ма? *Біраз ойланғаннан кейін* Иә, біз де (b==0) тексере аламыз. Және біраз логиканы орындаңыз. Дұрыс. Сондықтан біз 3 жолмен жүре аламыз:
  • көріңіз/ұстаңыз
  • throws – шақыру әдісіне бағыттау
  • аргументтерді тексеру
Бұл жағдайда divideқай әдіс артықшылықты деп ойлайсыз?
Мен ерекше жағдайды шақыру әдісіне жіберуді таңдар едім, себебі... intбөлу әдісінде бұл ерекшелікті қалай өңдеу керек және қате болған жағдайда қандай нәтиже түрі қайтарылатыны анық емес . Ал шақыру әдісінде мен оның нөлге тең екенін тексеру үшін b аргументін қолданар едім. Бұл жауап сұхбат берушіні қанағаттандырған сияқты, бірақ шынымды айтсам, бұл жауаптың бір мәнді екеніне сенімді емеспін))

Эскиз 2. «Кім жылдам?»

Стандартты сұрақтан кейін ArrayList LinkedList-тен қалай ерекшеленеді: Не тезірек болады - элементті ортаға ArrayListнемесе ортаға кірістіру LinkedList? *Осы жерде мен секірдім, мен барлық жерде « LinkedListтізімнің ортасына элементтерді енгізу немесе жою үшін пайдаланыңыз» сияқты нәрсені оқығанымды есіме түсірдім. Үйде мен JavaRush лекцияларын екі рет тексердім, мынадай сөз тіркесі бар: «Егер сіз топтаманың ортасына көптеген элементтерді кірістіргіңіз (немесе жойғыңыз) болсаңыз, онда LinkedList. Барлық басқа жағдайларда - ArrayList. Автоматты түрде жауап береді* Ол арқылы жылдамырақ болады LinkedList. Түсіндіріңізші өтінемін
  1. Элементті ортаға енгізу үшін ArrayListбіз тізімдегі элементті тұрақты уақытта табамыз, содан кейін кірістірілгеннің оң жағындағы элементтердің индекстерін сызықтық уақытта қайта есептейміз.
  2. Үшін LinkedList.. Біз алдымен ортасына сызықтық уақытта жетеміз, содан кейін көрші элементтердің сілтемелерін өзгерте отырып, тұрақты уақытта элементті енгіземіз.
Сонда белгілі болды, қайсысы жылдам? Хм... Дәл солай болып шықты. Бірақ қай кезде LinkedListжылдамырақ? Оны тізімнің бірінші жартысына енгізгенімізде шығады. Мысалы, егер сіз оны ең басында кірістірсеңіз, сіз ArrayListең құйрығына дейін барлық индекстерді қайта есептеуіңіз керек, бірақ LinkedListбірінші элементтің сілтемесін өзгертуіңіз керек. Моральдық: тіпті JavaRush-те жазылғанның бәріне сенбеңіз!)

Эскиз 3. «Теңдерсіз және хэшcodeсыз біз қайда болар едік!»

Теңдіктер және хэшcode туралы әңгіме өте ұзақ болды - оны қалай қайта анықтау керек, ішінде қандай іске асыру Object, қалпақ астында не болады, элемент ішіне енгізілгенде HashMapжәне т.б. Мен өзімнің ойымша қызықты бірнеше жайттарды ғана келтіремін* Біз сыныпты құрдық деп елестетіңіз
public class A {
    int id;

    public A(int id) {
        this.id = id;
    }
}
Және олар жоққа шығарған жоқ equalsжәне hashcode. Код орындалғанда не болатынын сипаттаңыз
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*Сұхбат алдында мен негізгі алгоритмдерді, олардың күрделілігін және деректер құрылымдарын түсінуге арнайы екі күн жұмсағаным жақсы болды - бұл көп көмектесті, CS50-ге рахмет!*
  1. А класының екі данасын жасаңыз

  2. Біз бос картаны жасаймыз, ол әдепкі бойынша 16 себетке ие. Кілт А класының an objectісі болып табылады, онда equalsжәне әдістері қайта белгіленбейді hashcode.

  3. Оны a1картаға салыңыз. Ол үшін алдымен хэшті есептейміз a1.

    Хэш неге тең болады?

    Жадтағы ұяшықтың addressі сыныптағы әдісті жүзеге асыру болып табыладыObject

  4. Хэш негізінде біз себет индексін есептейміз.

    Оны қалай есептей аламыз?

    *Өкінішке орай, мен бұл жерде нақты жауап бермедім. Сізде ұзын сан бар - хэш және 16 шелек бар - әртүрлі хэштері бар нысандар шелектерге біркелкі таралатындай индексті қалай анықтауға болады? Мен индекстің келесідей есептелгенін елестете аламын:

    int index = hash % buckets.length

    Үйде мен бастапқы codeтағы бастапқы енгізудің сәл өзгеше екенін көрдім:

    static int indexFor(int h, int length)
    {
        return h & (length - 1);
    }
  5. Біз соқтығыстардың жоқтығын тексереміз және a1 енгіземіз.

  6. Әдіске көшейік get. hasha1 және a2 даналарының басқа (жадтағы басқа мекенжай) болуы кепілдендірілген , сондықтан біз бұл кілт үшін ештеңе таба алмаймыз.

    Егер біз оны тек hashcodeА класында қайта анықтасақ және хэшмапқа алдымен a1 пернесі бар жұпты, содан кейін a2 пернесін енгізуге тырыссақ ше?

    Содан кейін алдымен біз қажетті себетті табамыз hashcode- бұл операция дұрыс орындалады. EntryӘрі қарай, арбаға тіркелген LinkedList ішіндегі нысандарды қарап шығуды және кілттерді арқылы салыстыруды бастаймыз equals. Өйткені equalsқайта белгіленбейді, содан кейін базалық іске асыру сыныптан алынады Object- сілтеме бойынша салыстыру. a1 және a2 әр түрлі сілтемелерге кепілдік береді, сондықтан біз енгізілген a1 элементін «жіберіп аламыз», ал a2 LinkedList тізімінде жаңа түйін ретінде орналастырылады.

    Қорытынды қандай? HashMapҚайта анықталмаған нысанда кілт ретінде пайдалануға болады ма equalshashcode?

    Жоқ болмайды.

Эскиз 4. «Әдейі бұзайық!»

Қате және Ерекшелік туралы сұрақтардан кейін келесі сұрақ туындады: Функция StackOverflow жіберетін қарапайым мысалды жазыңыз. *Содан кейін мен кейбір рекурсивті функцияны жазуға тырысқанда бұл қатенің мені қалай қиналғанын есіме түсірдім* Бұл рекурсивті шақыру жағдайында, егер рекурсиядан шығу шарты дұрыс көрсетілмесе, орын алуы мүмкін. *Сосын мен аздап ақылды бола бастадым, соңында сұхбат беруші көмектесті, бәрі қарапайым болып шықты*
void sof() {
    sof();
}
Бұл қатенің айырмашылығы неде OutOfMemory? *Мен бұл жерде жауап бермедім, кейінірек бұл Java жады туралы сұрақ екенін түсіндім Stack( Heapan objectілерге қоңыраулар мен сілтемелер Стекте сақталады, ал нысандардың өзі үйме жадыда сақталады). StackТиісінше, келесі әдісті шақыру үшін жадта бос орын болмаған кезде және OutOfMemoryжадта нысандарға арналған орын таусылғанда, StackOverflow жойылады Heap*
Сұхбаттан есте қалған сәттері осылар. Соңында тағылымдамадан өтуге қабылдандым, сондықтан менде 2,5 ай оқу, егер бәрі ойдағыдай болса, компанияда жұмыс бар) Қызығушылығы болса, осы жолы кішірек, басқа мақала жаза аламын. маған басқа компанияда сұхбат берілген қарапайым, бірақ көрнекі мәселенің талдауы. Мұның бәрі мен үшін, бұл мақала біреуге білімін тереңдетуге немесе жүйелеуге көмектеседі деп үміттенемін. Барлығына оқуға сәттілік!
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION