JavaRush /وبلاگ جاوا /Random-FA /داستان یک مصاحبه: سوالات جالب
GuitarFactor
مرحله
Санкт-Петербург

داستان یک مصاحبه: سوالات جالب

در گروه منتشر شد
اخیراً این فرصت را داشتم که در یک مصاحبه برای یک موقعیت کارآموز در یکی از شرکت های بزرگ فناوری اطلاعات شرکت کنم. داستان یک مصاحبه: سوالات جالب - 1این اولین مصاحبه من در زمینه فناوری اطلاعات بود و به نظر من جالب بود. در مجموع، بیش از 3 ساعت "بازجویی" شدم (قبل از انجام مشق شب و آزمایش در دفتر روی رایانه). می‌خواهم از مصاحبه‌کننده قدردانی کنم که وقتی به سؤال نادرست پاسخ دادم تسلیم نشد، اما با کمک سؤالات اصلی او مرا مجبور کرد فکر کنم و به پاسخ صحیح برسم. در زیر چندین "طرح" را ارائه خواهم داد - به نظر من سؤالات بسیار جالبی است که برخی از آنها درک عمیق تری از جنبه های خاصی در جاوا به من داد. شاید این چیزها برای برخی بدیهی به نظر برسد، اما من فکر می کنم کسانی هستند که این برای آنها مفید باشد. در زیر عبارات با فونت‌های زیر برجسته شده‌اند: مصاحبه‌گر - با درشت توضیحات صوتی و افکار من - با حروف کج پاسخ‌های من - با فونت معمولی کار با پس‌زمینه تمام شد، بیایید کار را شروع کنیم)

طرح 1. "روش به ظاهر ساده"

بنویسید که چگونه روشی را اجرا می کنید که نتیجه تقسیم عدد a بر عدد b را برمی گرداند. مصاحبه کننده روی یک کاغذ می نویسد.
int divide(int a, int b) {
}
*با ناباوری به کاغذ امضای روش نگاه کردم. گیرش چیست؟* می نویسم:
int divide(int a, int b) {
    return a/b;
}
آیا این روش مشکلی دارد؟ *دارم یک احمق واقعا احمق میگیرم* ظاهراً نه.. بعد یک سوال مشروع مطرح می شود: اگر b=0 چه می شود؟ *اوه، اگر به همین منوال ادامه دهم نزدیک است از این دفتر اخراج شوم!* اوه بله، البته. در اینجا ما آرگومان هایی از نوع int داریم، بنابراین یک Exception حسابی ایجاد می شود. اگر آرگومان ها از نوع float یا double بودند، نتیجه Infinity خواهد بود. قرار است در این مورد چه کنیم؟ من شروع به نوشتن تلاش/گرفتن می کنم
int divide(int a, int b) {
    try {
        return a/b;
    } catch (Exception e) {
        e.printStackTrace();
        return ... // ??? what the hack?
    }
}
*می‌توانم برگردم و فریز کنم: در صورت بروز خطا، چیزی باید برگردانده شود. اما چگونه می توان این "چیزی" را از نتیجه محاسبه متمایز کرد؟* چه چیزی را برمی گردانیم؟ Hm... نوع متغیر بازگشتی را به Integer تغییر می‌دادم و در صورت استثنا null را برمی‌گرداندم. بیایید تصور کنیم که ما نمی توانیم نوع را تغییر دهیم. آیا می توانیم به نحوی از آن خارج شویم؟ شاید بتوانیم به استثنای کار دیگری انجام دهیم؟ *در اینجا می آید* ما همچنین می توانیم آن را به روش فراخوانی فوروارد کنیم! درست. چه شکلی خواهد بود؟
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();
    }
}
آیا رسیدگی به استثناء ضروری است؟ بله، زیرا ما به صراحت آن را از روش تقسیم فوروارد می کنیم. (*من در اینجا اشتباه کردم! آنچه در زیر می آید سوالات اصلی مصاحبه کننده برای رسیدن به پاسخ صحیح است*) و استثنای حسابی - چه نوع استثنایی است - بررسی یا علامت زده نشده است؟ این یک استثنا در Runtime است، که به معنای بدون علامت است. *اینجا سوال قاتل پیش می آید* پس معلوم می شود، به قول شما، اگر در امضای متد، Exception های حسابی را مشخص کنیم، آنگاه تبدیل به یک استثناء بررسی شده می شود؟ *اوه!* احتمالا... نه. بله، رفته است. اگر در امضا، پرتاب‌های /اکسثنای علامت‌نخورده/ را نشان دهیم، فقط هشدار می‌دهیم که متد می‌تواند یک استثنا ایجاد کند، اما لازم نیست آن را در متد فراخوانی مدیریت کنیم. که مرتب شده است. آیا کار دیگری وجود دارد که بتوانیم برای جلوگیری از اشتباه انجام دهیم؟ *بعد از کمی فکر* بله، ما همچنین می توانیم بررسی کنیم که آیا (b==0). و کمی منطق را اجرا کنید. درست. بنابراین می توانیم 3 راه برویم:
  • تلاش/گرفتن
  • پرتاب - ارسال به روش فراخوانی
  • بررسی استدلال
در این صورت divideبه نظر شما کدام روش ارجح است؟
من ترجیح می دهم استثنا را به روش فراخوانی فوروارد کنم، زیرا... در روش تقسیم مشخص نیست که چگونه این استثنا را پردازش کنیم و intدر صورت بروز خطا چه نوع نتیجه ای را برگردانیم. و در روش فراخوانی از آرگومان b استفاده می کنم تا بررسی کنم که آیا برابر با صفر است یا خیر. به نظر می رسد که این پاسخ مصاحبه شونده را راضی کرده است، اما صادقانه بگویم، مطمئن نیستم که این پاسخ بدون ابهام باشد))

طرح 2. "چه کسی سریعتر است؟"

پس از سؤال استاندارد، تفاوت ArrayList با LinkedList، این بود: چه اتفاقی می‌افتد سریع‌تر - وارد کردن یک عنصر در وسط ArrayListیا وسط LinkedList؟ *اینجا پریدم، یادم افتاد که هر جا چیزی مانند «استفاده LinkedListبرای درج یا حذف عناصر در وسط فهرست» را می‌خواندم. در خانه، من حتی سخنرانی های JavaRush را دوبار بررسی کردم، یک عبارت وجود دارد: "اگر می خواهید عناصر زیادی را در وسط یک مجموعه قرار دهید (یا حذف کنید)، بهتر است از LinkedList. در تمام موارد دیگر - ArrayList. به صورت خودکار پاسخ داده می شود* با LinkedList. شفاف سازی کنید لطفا
  1. برای درج یک عنصر در وسط ArrayList، عنصر را در لیست در زمان ثابت پیدا می کنیم و سپس شاخص های عناصر در سمت راست عنصر درج شده را در زمان خطی دوباره محاسبه می کنیم.
  2. برای LinkedList.. ابتدا در زمان خطی به وسط می رسیم و سپس یک عنصر را در زمان ثابت وارد می کنیم و پیوندها را برای عناصر همسایه تغییر می دهیم.
بنابراین معلوم می شود که کدام سریعتر است؟ هوم... همینطور معلوم می شود. اما چه زمانی سریعتر است LinkedList؟ معلوم می شود که وقتی آن را در نیمه اول لیست قرار می دهیم. به عنوان مثال، اگر آن را در همان ابتدا وارد کنید، ArrayListباید تمام شاخص ها را تا انتهای دم دوباره محاسبه کنید، اما LinkedListفقط باید مرجع عنصر اول را تغییر دهید. اخلاقی: به معنای واقعی کلمه همه چیزهایی که نوشته شده است را باور نکنید، حتی در JavaRush!)

طرح 3. "بدون برابر و هش کد کجا خواهیم بود!"

مکالمه در مورد برابر و هش کد بسیار طولانی بود - چگونه آن را لغو کنیم، چه پیاده سازی در آن انجام شود 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. دو نمونه از کلاس A ایجاد کنید

  2. یک نقشه خالی ایجاد می کنیم که به طور پیش فرض دارای 16 سبد است. کلید یک شی از کلاس A است که متدهای equalsو در آن بازنویسی نمی شوند hashcode.

  3. آن را a1در نقشه قرار دهید. برای این کار ابتدا هش را محاسبه می کنیم a1.

    هش برابر با چه خواهد بود؟

    آدرس یک سلول در حافظه پیاده سازی یک متد از یک کلاس استObject

  4. بر اساس هش، شاخص سبد را محاسبه می کنیم.

    چگونه می توانیم آن را محاسبه کنیم؟

    *متاسفانه اینجا پاسخ روشنی ندادم. شما یک عدد طولانی دارید - یک هش، و 16 سطل وجود دارد - چگونه یک شاخص تعریف کنید تا اشیا با هش های مختلف به طور مساوی در بین سطل ها توزیع شوند؟ من می توانم تصور کنم که شاخص به این صورت محاسبه می شود:

    int index = hash % buckets.length

    قبلاً در خانه دیدم که اجرای اصلی در کد منبع تا حدودی متفاوت است:

    static int indexFor(int h, int length)
    {
        return h & (length - 1);
    }
  5. بررسی می کنیم که هیچ برخوردی وجود نداشته باشد و a1 را وارد می کنیم.

  6. بریم سراغ روش get. نمونه‌های a1 و a2 تضمین می‌شوند که دارای یک hashآدرس متفاوت (در حافظه متفاوت) هستند، بنابراین ما چیزی برای این کلید پیدا نمی‌کنیم.

    اگر آن را فقط hashcodeدر کلاس A مجدداً تعریف کنیم و سعی کنیم ابتدا یک جفت با کلید a1 و سپس با a2 در نقشه درج کنیم، چه؟

    سپس ابتدا سبد مورد نظر را توسط hashcode- این عملیات به درستی انجام می شود. در مرحله بعد، بیایید شروع کنیم به بررسی اشیاء Entryدر LinkedList متصل به سبد خرید و مقایسه کلیدها با equals. زیرا equalsلغو نمی شود، سپس پیاده سازی پایه از کلاس گرفته می شود Object- مقایسه با مرجع. a1 و a2 دارای پیوندهای متفاوتی هستند، بنابراین عنصر درج شده a1 را "از دست خواهیم داد" و a2 به عنوان یک گره جدید در LinkedList قرار خواهد گرفت.

    نتیجه گیری چیست؟ آیا می توان به عنوان یک کلید در HashMapیک شی با non-overriden استفاده کرد equalshashcode؟

    نه نمی توانی.

طرح 4. "بیایید آن را از روی عمد بشکنیم!"

پس از سؤالات مربوط به خطا و استثنا، سؤال زیر دنبال شد: یک مثال ساده بنویسید که در آن یک تابع StackOverflow را پرتاب می کند. *سپس به یاد آوردم که چگونه این خطا هنگام نوشتن یک تابع بازگشتی مرا آزار می دهد * این احتمالاً در مورد تماس بازگشتی اتفاق می افتد، اگر شرط خروج از بازگشت به درستی مشخص نشده باشد. *سپس شروع به امتحان کردن چیزهای هوشمندانه کردم، در نهایت مصاحبه کننده کمک کرد، همه چیز ساده شد*
void sof() {
    sof();
}
این خطا با چه تفاوتی دارد OutOfMemory؟ *در اینجا پاسخی ندادم، فقط بعداً متوجه شدم که این سؤال مربوط به دانش حافظه جاوا است Stack( Heapتماس ها و ارجاع به اشیا در پشته ذخیره می شوند و خود اشیا در حافظه Heap ذخیره می شوند). Stackبر این اساس، زمانی که فضای بیشتری در حافظه برای فراخوانی متد بعدی وجود نداشته باشد و OutOfMemoryفضای اشیاء در حافظه تمام شده باشد، StackOverflow حذف می‌شود Heap*
اینها لحظاتی از مصاحبه است که به یاد دارم. در نهایت برای کارآموزی پذیرفته شدم، بنابراین 2.5 ماه آموزش در پیش دارم و اگر همه چیز خوب پیش برود، شغلی در شرکت دارم) در صورت علاقه می توانم یک مقاله دیگر، این بار کوچکتر، با تجزیه و تحلیل یک مشکل ساده اما گویا که در یک شرکت دیگر با من مصاحبه شد. این همه برای من است، امیدوارم این مقاله به کسی کمک کند تا دانش خود را تعمیق یا سازماندهی کند. یادگیری همه مبارک!
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION