طرح 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
. شفاف سازی کنید لطفا
- برای درج یک عنصر در وسط
ArrayList
، عنصر را در لیست در زمان ثابت پیدا می کنیم و سپس شاخص های عناصر در سمت راست عنصر درج شده را در زمان خطی دوباره محاسبه می کنیم. - برای
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!*
-
دو نمونه از کلاس A ایجاد کنید
-
یک نقشه خالی ایجاد می کنیم که به طور پیش فرض دارای 16 سبد است. کلید یک شی از کلاس A است که متدهای
equals
و در آن بازنویسی نمی شوندhashcode
. -
آن را
a1
در نقشه قرار دهید. برای این کار ابتدا هش را محاسبه می کنیمa1
.هش برابر با چه خواهد بود؟
آدرس یک سلول در حافظه پیاده سازی یک متد از یک کلاس است
Object
-
بر اساس هش، شاخص سبد را محاسبه می کنیم.
چگونه می توانیم آن را محاسبه کنیم؟
*متاسفانه اینجا پاسخ روشنی ندادم. شما یک عدد طولانی دارید - یک هش، و 16 سطل وجود دارد - چگونه یک شاخص تعریف کنید تا اشیا با هش های مختلف به طور مساوی در بین سطل ها توزیع شوند؟ من می توانم تصور کنم که شاخص به این صورت محاسبه می شود:
int index = hash % buckets.length
قبلاً در خانه دیدم که اجرای اصلی در کد منبع تا حدودی متفاوت است:
static int indexFor(int h, int length) { return h & (length - 1); }
-
بررسی می کنیم که هیچ برخوردی وجود نداشته باشد و a1 را وارد می کنیم.
-
بریم سراغ روش
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 ماه آموزش در پیش دارم و اگر همه چیز خوب پیش برود، شغلی در شرکت دارم) در صورت علاقه می توانم یک مقاله دیگر، این بار کوچکتر، با تجزیه و تحلیل یک مشکل ساده اما گویا که در یک شرکت دیگر با من مصاحبه شد. این همه برای من است، امیدوارم این مقاله به کسی کمک کند تا دانش خود را تعمیق یا سازماندهی کند. یادگیری همه مبارک!
GO TO FULL VERSION