JavaRush /Java Blogu /Random-AZ /Bir müsahibənin hekayəsi: maraqlı suallar
GuitarFactor
Səviyyə
Санкт-Петербург

Bir müsahibənin hekayəsi: maraqlı suallar

Qrupda dərc edilmişdir
Bu yaxınlarda böyük İT şirkətlərindən birində təcrübə keçmək üçün müsahibədə iştirak etmək imkanım oldu. Bir müsahibənin hekayəsi: maraqlı suallar - 1Bu, mənim ilk İT müsahibəm idi və fikrimcə, maraqlı oldu. Ümumilikdə, məni 3 saatdan çox "dindirdilər" (bundan əvvəl ev tapşırığı və ofisdə kompüterdə sınaq keçirildi). Mən suala səhv cavab verəndə təslim olmayan, lakin aparıcı suallarının köməyi ilə məni düşünməyə və düzgün cavaba gəlməyə məcbur edən müsahibimə ehtiramımı bildirmək istəyirəm. Aşağıda bir neçə "eskiz" təqdim edəcəyəm - mənim fikrimcə, olduqca maraqlı suallar, bəziləri mənə Java-nın müəyyən aspektlərini daha dərindən başa düşməyi təmin etdi. Ola bilsin ki, bəziləri üçün bunlar açıq-aşkar görünəcək, amma məncə bunun faydalı olacaqları olacaq. Aşağıda ifadələr aşağıdakı şriftlərlə vurğulanır: Müsahibəçi - qalın qalın səslə izahatlar və fikirlərim - kursivlə Cavablarım - adi şriftlə Arxa fonu bitirdik, gəlin işə başlayaq)

Eskiz 1. “Sadə görünən üsul”

a rəqəminin b ədədinə bölünməsinin nəticəsini qaytaran metodu necə həyata keçirəcəyinizi yazın. Müsahibi kağız parçasına yazır.
int divide(int a, int b) {
}
*Üsul imzası olan vərəqə inamsızcasına nəzər saldım. Nədir?* Mən yazıram:
int divide(int a, int b) {
    return a/b;
}
Bu üsulla bağlı hər hansı problem varmı? *Mən həqiqətən axmaq bir axmaqlığı tuturam* Görünür, yox.. Sonra qanuni bir sual gəlir: əgər b=0 olarsa? *Vay, belə davam etsəm, bu ofisdən qovulmaq üzrəyəm!* Hə, əlbəttə. Burada int tipli arqumentlərimiz var, ona görə də Arifmetik İstisna atılacaq. Arqumentlər float və ya double tipli olsaydı, nəticə Sonsuzluq olardı. Bununla bağlı nə edəcəyik? Mən cəhd/tutmaq yazmağa başlayıram
int divide(int a, int b) {
    try {
        return a/b;
    } catch (Exception e) {
        e.printStackTrace();
        return ... // ??? what the hack?
    }
}
*Mən qayıdıram və dondururam: xəta baş verərsə, nəyisə qaytarmaq lazımdır. Bəs bu “nəyisə” hesablamanın nəticəsindən necə fərqləndirmək olar?* Nə qaytaracağıq? Hm... Mən qaytarılan dəyişənin tipini Tam ədədə dəyişərdim və istisna halında null qaytarardım. Təsəvvür edək ki, növü dəyişdirə bilmərik. Birtəhər çıxa bilərik? Bəlkə istisna ilə başqa bir şey edə bilərik? *Budur gəlir* Biz də onu zəng metoduna yönləndirə bilərik! Sağ. Nə kimi görünəcək?
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();
    }
}
İstisna ilə məşğul olmaq lazımdırmı? Bəli, çünki biz onu bölmə metodundan açıq şəkildə irəliləyirik. (*Burada səhv etdim! Müsahibənin düzgün cavaba çatmasına səbəb olan suallar aşağıdakılardır*) Və Arifmetik İstisna - bu hansı istisnadır - yoxlanılır, yoxsa yoxlanılır? Bu Runtime istisnasıdır, yəni işarələnməmişdir. *Budur, qatil sualı gəlir* Beləliklə, sizin sözlərinizlə belə çıxır ki, əgər metod imzasında Arifmetik İstisna atdığını qeyd etsək, o, yoxlanılan istisna oldu? *Uf!* Yəqin ki... yox. Bəli, getdi. İmzada throws /checked exception/ işarəsini göstərsək, yalnız metodun istisna ata biləcəyini xəbərdar edirik, lakin onu çağırış metodunda idarə etmək lazım deyil. Bu sıralanır. Səhvlərdən qaçmaq üçün edə biləcəyimiz başqa bir şey varmı? *Bir qədər fikirləşdikdən sonra* Bəli, biz də yoxlaya bilərik (b==0). Və bir az məntiq həyata keçirin. Sağ. Beləliklə, 3 yolla gedə bilərik:
  • cəhd/tutmaq
  • atır – çağırış metoduna yönləndirmə
  • arqument yoxlanışı
Bu halda dividesizcə hansı üsula üstünlük verilir?
İstisnanı çağırış metoduna yönləndirməyi seçərdim, çünki... intbölmə metodunda bu istisnanın necə işlənəcəyi və xəta baş verdikdə hansı növ nəticənin qaytarılacağı aydın deyil . Çağırış metodunda isə onun sıfıra bərabər olub olmadığını yoxlamaq üçün b arqumentindən istifadə edərdim. Deyəsən bu cavab müsahibini qane etdi, amma düzünü desəm bu cavabın birmənalı olduğuna əmin deyiləm))

Eskiz 2. “Kim daha sürətli?”

Standart sualdan sonra, ArrayList-in LinkedList-dən nə ilə fərqləndiyi ortaya çıxdı: Nə daha tez baş verəcək - elementin ortasına ArrayListvə ya ortasına daxil edilməsi LinkedList? *Budur, atladım, hər yerdə “ siyahının ortasına elementləri daxil etmək və ya silmək üçün istifadə edin” kimi bir şey oxuduğumu xatırladım . LinkedListEvdə hətta JavaRush mühazirələrini iki dəfə yoxladım, belə bir ifadə var: “Əgər kolleksiyanın ortasına çoxlu elementlər daxil etmək (və ya silmək) istəyirsənsə, onda LinkedList. Bütün digər hallarda - ArrayList.” Avtomatik olaraq cavablandırılır* ilə daha sürətli olacaq LinkedList. Zəhmət olmasa aydınlaşdırın
  1. Ortaya bir element daxil etmək üçün ArrayListbiz siyahıdakı elementi sabit zamanda tapırıq və sonra daxil edilmiş elementin sağındakı elementlərin indekslərini xətti vaxtda yenidən hesablayırıq.
  2. Üçün LinkedList.. Biz əvvəlcə xətti vaxtda ortaya çatırıq və sonra qonşu elementlər üçün keçidləri dəyişdirərək sabit zamanda element daxil edirik.
Belə çıxır ki, hansı daha sürətlidir? Hm... Belə çıxır. Amma nə vaxt daha sürətli olur LinkedList? Belə çıxır ki, onu siyahının birinci yarısına daxil etdikdə. Məsələn, onu ən başlanğıcda daxil etsəniz, ArrayListquyruğa qədər bütün indeksləri yenidən hesablamalı olacaqsınız, ancaq LinkedListbirinci elementin istinadını dəyişdirməlisiniz. Əxlaq: hətta JavaRush-da yazılanların hamısına sözün həqiqi mənasında inanmayın!)

Eskiz 3. “Bərabərlər və hashcode olmasaydı, biz harada olardıq!”

Bərabərlər və hashcode haqqında söhbət çox uzun idi - onu necə ləğv etmək olar, hansı tətbiqetmə Object, başlıq altında nə baş verir, element daxil edildikdə HashMapvə s. Sadəcə fikrimcə maraqlı olan bir sıra məqamları qeyd edəcəyəm* Təsəvvür edin ki, biz sinif yaratmışıq
public class A {
    int id;

    public A(int id) {
        this.id = id;
    }
}
Və onlar ləğv etmədilər equalshashcode. Kod icra edildikdə nə baş verəcəyini təsvir edin
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*Yaxşı ki, müsahibədən əvvəl mən əsas alqoritmləri, onların mürəkkəbliyini və məlumat strukturlarını başa düşmək üçün xüsusi olaraq bir neçə gün sərf etdim - bu, çox kömək etdi, təşəkkürlər CS50!*
  1. A sinfinin iki nümunəsini yaradın

  2. Varsayılan olaraq 16 səbət olan boş bir xəritə yaradırıq. Açar A sinifinin obyektidir, burada equalsvə metodları ləğv edilmir hashcode.

  3. a1Xəritəyə qoyun . Bunu etmək üçün əvvəlcə hashı hesablayırıq a1.

    Haş nəyə bərabər olacaq?

    Yaddaşdakı hüceyrənin ünvanı bir sinifdən metodun həyata keçirilməsidirObject

  4. Hash əsasında biz səbət indeksini hesablayırıq.

    Bunu necə hesablaya bilərik?

    *Təəssüf ki, burada dəqiq cavab vermədim. Sizin uzun nömrəniz var - hash və 16 vedrə var - indeksi necə təyin etmək olar ki, müxtəlif hashlərə malik obyektlər vedrələr arasında bərabər paylansın? Təsəvvür edə bilərdim ki, indeks belə hesablanır:

    int index = hash % buckets.length

    Artıq evdə mən mənbə kodundakı orijinal tətbiqin bir qədər fərqli olduğunu gördüm:

    static int indexFor(int h, int length)
    {
        return h & (length - 1);
    }
  5. Toqquşmaların olmadığını yoxlayırıq və a1 daxil edirik.

  6. Gəlin üsula keçək get. a1 və a2 nümunələrinin fərqli (yaddaşda fərqli ünvan) olacağına zəmanət verilir hash, ona görə də bu açar üçün heç nə tapa bilməyəcəyik.

    Əgər biz onu yalnız hashcodeA sinfində yenidən təyin etsək və heşmapa əvvəlcə a1 açarı, sonra isə a2 ilə cüt daxil etməyə çalışsaq necə olar?

    Sonra əvvəlcə istədiyiniz səbəti tapacağıq hashcode- bu əməliyyat düzgün yerinə yetiriləcəkdir. EntrySonra, səbətə əlavə edilmiş LinkedList-dəki obyektləri nəzərdən keçirməyə başlayaq və açarları ilə müqayisə edək equals. Çünki equalsləğv edilmir, sonra əsas icra sinifdən götürülür Object- istinadla müqayisə. a1 və a2-nin fərqli keçidlərə malik olacağına zəmanət verilir, ona görə də daxil edilmiş a1 elementini “qaçıracağıq” və a2 LinkedList-ə yeni qovşaq kimi yerləşdiriləcək.

    Nəticə nədir? HashMapQeyri-aşkar edilmiş obyektdə açar kimi istifadə etmək mümkündürmü equalshashcode?

    Yox bacarmazsan.

Eskiz 4. “Gəlin onu qəsdən sındıraq!”

Xəta və İstisna ilə bağlı suallardan sonra aşağıdakı sual gəldi: Funksiyanın StackOverflow atacağı sadə bir nümunə yazın. *Sonra bəzi rekursiv funksiyanı yazmağa çalışarkən bu xətanın mənə necə əziyyət verdiyini xatırladım* Bu, rekursiv çağırış zamanı, əgər rekursiyadan çıxmaq şərti düzgün göstərilməyibsə, yəqin ki, baş verəcək. *Sonra bir az ağıllılaşmağa başladım, axırda müsahibim kömək etdi, hər şey sadə oldu*
void sof() {
    sof();
}
Bu səhv nə ilə fərqlənir OutOfMemory? *Burada cavab vermədim, yalnız sonradan başa düşdüm ki, bu, Java yaddaşını bilməklə bağlı sualdır Stack( Heapobyektlərə edilən zənglər və istinadlar Stack-də, obyektlərin özləri isə Heap yaddaşında saxlanılır). StackMüvafiq olaraq, növbəti metod çağırışı üçün yaddaşda yer qalmadıqda və OutOfMemoryobyektlər üçün yer yaddaşda tükəndikdə StackOverflow atılır Heap*
Müsahibədən yadımda qalan anlardır. Sonda təcrübə keçməyə qəbul olundum, ona görə də qarşıda 2,5 aylıq təlim və hər şey yolunda getsə şirkətdə bir iş var) Maraq olarsa, bu dəfə daha kiçik bir məqalə yaza bilərəm. başqa bir şirkətdə müsahibə aldığım sadə, lakin illüstrativ problemin təhlili. Hamısı mənim üçün budur, ümid edirəm ki, bu məqalə kiməsə biliklərini dərinləşdirməyə və ya təşkil etməyə kömək edəcək. Hər kəsə xoş öyrənmə!
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION