CodeGym /وبلاگ جاوا /Random-FA /بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه...
John Squirrels
مرحله
San Francisco

بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه دهنده جاوا. قسمت 12

در گروه منتشر شد
سلام! دانش قدرت است. هر چه در اولین مصاحبه خود دانش بیشتری داشته باشید، اعتماد به نفس بیشتری خواهید داشت. بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه دهنده جاوا.  قسمت 12 - 1اگر مغزی بزرگ و پر از دانش وارد کنید، مصاحبه‌گر شما دشوار خواهد بود که شما را گیج کند و احتمالاً شگفت‌زده خواهد شد. بنابراین بدون هیچ مقدمه ای، امروز با بررسی سوالات یک توسعه دهنده جاوا به تقویت پایه نظری شما ادامه خواهیم داد.

103. چه قوانینی برای بررسی استثنایی در حین وراثت اعمال می شود؟

اگر من سوال را درست متوجه شده باشم، آنها در مورد قوانینی برای کار با استثنا در هنگام ارث می پرسند. قوانین مربوطه به شرح زیر است:
  • یک متد لغو یا پیاده‌سازی شده در یک نسل/پیاده‌سازی نمی‌تواند استثناهای بررسی شده را که در سلسله مراتب بالاتر از استثناهای یک متد سوپرکلاس/اینترفیس هستند، ایجاد کند.
به عنوان مثال، فرض کنید ما یک رابط Animal با روشی داریم که یک IOException را ایجاد می کند :
public interface Animal {
   void speak() throws IOException;
}
هنگام پیاده‌سازی این رابط، نمی‌توانیم یک استثنای پرتاب‌پذیر عمومی‌تر (مثلاً Exception ، Throwable ) را در معرض نمایش بگذاریم، اما می‌توانیم استثنای موجود را با زیر کلاس جایگزین کنیم، مانند FileNotFoundException :
public class Cat implements Animal {
   @Override
   public void speak() throws FileNotFoundException {
// Some implementation
   }
}
  • عبارت throws سازنده کلاس فرعی باید شامل تمام کلاس های استثنا باشد که توسط سازنده سوپرکلاس فراخوانده شده برای ایجاد شیء پرتاب شده است.
فرض کنید سازنده کلاس Animal استثناهای زیادی ایجاد می کند:
public class Animal {
  public Animal() throws ArithmeticException, NullPointerException, IOException {
  }
سپس یک سازنده زیر کلاس نیز باید آنها را پرتاب کند:
public class Cat extends Animal {
   public Cat() throws ArithmeticException, NullPointerException, IOException {
       super();
   }
یا، مانند روش‌ها، می‌توانید استثناهای متفاوت و کلی‌تری را مشخص کنید. در مورد ما، می‌توانیم Exception را نشان دهیم ، زیرا کلی‌تر است و جد مشترک هر سه استثنا است که در superclass نشان داده شده‌اند:
public class Cat extends Animal {
   public Cat() throws Exception {
       super();
   }

104. آیا می توانید کدی بنویسید که بلوک نهایی اجرا نشود؟

اول، بیایید به یاد بیاوریم که در نهایت چیست. قبلاً، مکانیسم ثبت استثنا را بررسی کردیم: یک بلوک try مشخص می‌کند که در آن استثناها گرفته می‌شوند، و بلوک‌های catch کدی هستند که وقتی یک استثنای مربوطه گرفته می‌شود، فراخوانی می‌شوند. سومین بلوک کد که با کلمه کلیدی نهایی مشخص شده است ، می تواند جایگزین یا بعد از بلوک های catch شود. ایده پشت این بلوک این است که کد آن همیشه بدون توجه به آنچه در یک بلوک try یا catch اتفاق می افتد (صرف نظر از اینکه استثنا وجود دارد یا خیر) اجرا می شود. مواردی که این بلوک اجرا نمی شود نادر هستند و غیرعادی هستند. ساده ترین مثال زمانی است که System.exit(0) قبل از بلوک نهایی فراخوانی می شود و در نتیجه برنامه خاتمه می یابد:
try {
   throw new IOException();
} catch (IOException e) {
   System.exit(0);
} finally {
   System.out.println("This message will not be printed on the console");
}
همچنین شرایط دیگری وجود دارد که بلوک نهایی اجرا نمی شود:
  • به عنوان مثال، یک خاتمه غیرعادی برنامه ناشی از خطاهای مهم سیستم، یا برخی از خطاهایی که باعث از کار افتادن برنامه می شود (به عنوان مثال، StackOverflowError ، که زمانی رخ می دهد که پشته برنامه سرریز می شود).

  • وضعیت دیگر زمانی است که یک نخ شبح وارد یک بلوک try- end می شود، اما سپس رشته اصلی برنامه خاتمه می یابد. به هر حال، موضوعات شبح برای کارهای پس‌زمینه‌ای هستند که اولویت بالایی یا اجباری ندارند، بنابراین برنامه منتظر نمی‌ماند تا آنها تمام شود.

  • بی‌اهمیت‌ترین مثال، یک حلقه بی‌پایان در داخل یک بلوک try یا catch است - زمانی که داخل آن قرار گیرد، یک نخ برای همیشه در آنجا گیر می‌کند:

    try {
       while (true) {
       }
    } finally {
       System.out.println("This message will not be printed on the console");
    }
این سوال در مصاحبه های توسعه دهندگان جوان بسیار محبوب است، بنابراین بهتر است چند مورد از این موقعیت های استثنایی را به خاطر بسپارید. بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه دهنده جاوا.  قسمت 12 - 2

105. مثالی بنویسید که در آن چندین استثنا را در یک بلوک catch مدیریت کنید.

1) مطمئن نیستم که این سوال درست پرسیده شده باشد. تا جایی که من متوجه شدم، این سوال به چندین بلوک گرفتن و یک امتحان اشاره دارد :
try {
  throw new FileNotFoundException();
} catch (FileNotFoundException e) {
   System.out.print("Oops! There was an exception: " + e);
} catch (IOException e) {
   System.out.print("Oops! There was an exception: " + e);
} catch (Exception e) {
   System.out.print("Oops! There was an exception: " + e);
}
اگر یک استثنا در یک بلوک try انداخته شود ، بلوک‌های catch مرتبط سعی می‌کنند آن را به‌طور متوالی از بالا به پایین بگیرند. وقتی استثنا با یکی از بلوک‌های catch مطابقت داشت ، بلوک‌های باقی‌مانده دیگر نمی‌توانند آن را بگیرند و مدیریت کنند. همه اینها به این معنی است که استثناهای باریک بالاتر از موارد کلی تر در مجموعه بلوک های catch مرتب شده اند . برای مثال، اگر اولین بلوک catch ما کلاس Exception را بگیرد ، بلوک‌های بعدی استثناهای بررسی شده را نمی‌گیرند (یعنی بلاک‌های باقیمانده با زیر کلاس‌های Exception کاملاً بی‌فایده خواهند بود). 2) یا شاید سوال به درستی پرسیده شده است. در آن صورت، می‌توانیم استثنائات را به صورت زیر مدیریت کنیم:
try {
  throw new NullPointerException();
} catch (Exception e) {
   if (e instanceof FileNotFoundException) {
       // Some handling that involves a narrowing type conversion: (FileNotFoundException)e
   } else if (e instanceof ArithmeticException) {
       // Some handling that involves a narrowing type conversion: (ArithmeticException)e
   } else if(e instanceof NullPointerException) {
       // Some handling that involves a narrowing type conversion: (NullPointerException)e
   }
پس از استفاده از catch برای گرفتن یک استثنا، سپس سعی می کنیم نوع خاص آن را با استفاده از عملگر instanceof کشف کنیم ، که بررسی می کند آیا یک شی به یک نوع خاص تعلق دارد یا خیر. این به ما امکان می دهد تا بدون ترس از عواقب منفی، تبدیل نوع باریک را با اطمینان انجام دهیم. ما می‌توانیم هر یک از این رویکردها را در شرایط مشابه اعمال کنیم. من در مورد سوال فقط به این دلیل ابراز تردید کردم که گزینه دوم را رویکرد خوبی نمی نامم. در تجربه‌ام، هرگز با آن برخورد نکرده‌ام، و اولین رویکردی که شامل چندین بلوک گیر است، گسترده است.

106. کدام عملگر به شما اجازه می دهد تا یک استثنا را مجبور کنید که پرتاب شود؟ یک مثال بنویسید

من قبلاً چندین بار در مثال های بالا از آن استفاده کرده ام، اما یک بار دیگر آن را تکرار می کنم: کلمه کلیدی throw . مثالی از پرتاب دستی یک استثنا:
throw new NullPointerException();

107. آیا روش اصلی می تواند استثناء ایجاد کند؟ اگر چنین است، پس کجا می رود؟

اول از همه، می خواهم توجه داشته باشم که روش اصلی چیزی بیش از یک روش معمولی نیست. بله، برای شروع اجرای یک برنامه توسط ماشین مجازی فراخوانی می شود، اما فراتر از آن، می توان آن را از هر کد دیگری فراخوانی کرد. این بدان معناست که آن را نیز تابع قوانین معمول در مورد نشان دادن استثناهای علامت‌دار بعد از کلمه کلیدی throws است :
public static void main(String[] args) throws IOException {
بر این اساس، می تواند استثناهایی را ایجاد کند. وقتی main به عنوان نقطه شروع برنامه نامیده می شود (به جای روش دیگری)، هر استثنایی که ایجاد می کند توسط UncaughtExceptionHandler مدیریت می شود . هر نخ دارای یک چنین کنترل کننده است (یعنی در هر رشته یک چنین کنترل کننده وجود دارد). در صورت لزوم، می‌توانید کنترل‌کننده خود را ایجاد کرده و با فراخوانی عمومی static void main(String[] args) throws IOException {setDefaultUncaughtExceptionHandler متد در یک public static void main(String[] args) IOException {Thread object.

چند رشته ای

بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه دهنده جاوا.  قسمت 12 - 3

108. چه مکانیسم هایی برای کار در محیط چند رشته ای می شناسید؟

مکانیسم های اصلی برای چند رشته ای در جاوا عبارتند از:
  • کلمه کلیدی همگام سازی شده ، که راهی برای یک رشته برای قفل کردن یک روش/بلاک در هنگام ورود است و از ورود رشته های دیگر جلوگیری می کند.

  • کلمه کلیدی فرار ، دسترسی ثابت به متغیری را که رشته های مختلف به آن دسترسی دارند، تضمین می کند. یعنی وقتی این اصلاح کننده روی یک متغیر اعمال می شود، تمام عملیات اختصاص دادن و خواندن آن متغیر اتمی می شود. به عبارت دیگر، رشته ها متغیر را در حافظه محلی خود کپی نمی کنند و آن را تغییر نمی دهند. ارزش اصلی آن را تغییر خواهند داد.

  • Runnable - ما می توانیم این رابط (که از یک متد run() منفرد تشکیل شده است ) در برخی کلاس ها پیاده سازی کنیم:

    public class CustomRunnable implements Runnable {
       @Override
       public void run() {
           // Some logic
       }
    }

    و هنگامی که یک شی از آن کلاس ایجاد می کنیم، می توانیم یک رشته جدید را با ارسال شیء خود به سازنده Thread و سپس فراخوانی متد start() شروع کنیم :

    Runnable runnable = new CustomRunnable();
    new Thread(runnable).start();

    متد start ، متد run() پیاده سازی شده را روی یک رشته مجزا اجرا می کند .

  • Thread - ما می توانیم این کلاس را به ارث ببریم و روش اجرای آن را لغو کنیم :

    public class CustomThread extends Thread {
       @Override
       public void run() {
           // Some logic
       }
    }

    ما می توانیم با ایجاد یک شی از این کلاس و سپس فراخوانی متد start() یک رشته جدید راه اندازی کنیم :

    new CustomThread().start();

  • Concurrency - این مجموعه ای از ابزارها برای کار در یک محیط چند رشته ای است.

    متشکل از:

    • مجموعه‌های همزمان - مجموعه‌ای از مجموعه‌هایی است که به صراحت برای کار در یک محیط چند رشته‌ای ایجاد شده‌اند.

    • صف - صف های تخصصی برای یک محیط چند رشته ای (مسدود و غیر مسدود).

    • همگام‌سازها - اینها ابزارهای تخصصی برای کار در یک محیط چند رشته‌ای هستند.

    • مجریان - مکانیسم هایی برای ایجاد استخرهای نخ.

    • قفل ها - مکانیسم های همگام سازی نخ ها که نسبت به موارد استاندارد انعطاف پذیرتر هستند (همگام، منتظر، اطلاع رسانی، اطلاع رسانی به همه).

    • Atomics - کلاس های بهینه شده برای چند رشته ای. هر یک از عملیات آنها اتمی است.

109. در مورد همگام سازی بین رشته ها به ما بگویید. متدهای wait()، notify()، notifyAll() و join() برای چیست؟

همگام سازی بین رشته ها مربوط به کلمه کلیدی همگام شده است . این اصلاح کننده را می توان مستقیماً روی بلوک قرار داد:
synchronized (Main.class) {
   // Some logic
}
یا مستقیماً در امضای متد:
public synchronized void move() {
   // Some logic }
همانطور که قبلاً گفتم، synchronized مکانیزمی برای قفل کردن یک بلوک/روش به رشته های دیگر پس از ورود یک رشته است. بیایید یک بلوک/روش کد را به عنوان یک اتاق در نظر بگیریم. مقداری نخ به اتاق نزدیک می شود، وارد اتاق می شود و در را با کلیدش قفل می کند. وقتی نخ های دیگر به اتاق نزدیک می شوند، می بینند که در قفل است و در همان نزدیکی منتظر می مانند تا اتاق در دسترس قرار گیرد. هنگامی که اولین نخ با کار خود در اتاق تمام شد، در را باز می کند، اتاق را ترک می کند و کلید را رها می کند. من چند بار به یک دلیل به یک کلید اشاره کردم - زیرا چیزی مشابه واقعا وجود دارد. این یک شی خاص است که حالت اشغال/آزاد دارد. هر شی در جاوا چنین شی ای دارد، بنابراین وقتی از بلوک همگام سازی شده استفاده می کنیم ، باید از پرانتز برای نشان دادن شی ای که mutex آن قفل می شود استفاده کنیم:
Cat cat = new Cat();
synchronized (cat) {
   // Some logic
}
ما همچنین می‌توانیم از mutex مرتبط با یک کلاس استفاده کنیم، همانطور که در مثال اول انجام دادم ( Main.class ). به هر حال، وقتی از synchronized روی یک متد استفاده می کنیم، شی مورد نظر را که می خواهیم قفل کنیم را مشخص نمی کنیم، درست است؟ در این حالت، برای متدهای غیراستاتیک، mutex قفل شده، شی this است ، یعنی شی فعلی کلاس. برای روش‌های استاتیک، mutex مرتبط با کلاس فعلی ( this.getClass(); ) قفل می‌شود. Wait() متدی است که mutex را آزاد می کند و thread فعلی را در حالت انتظار قرار می دهد، گویی به مانیتور فعلی متصل می شود (چیزی شبیه یک لنگر). به همین دلیل، این روش را فقط می توان از یک بلوک یا متد هماهنگ فراخوانی کرد. در غیر این صورت، منتظر چه چیزی بود و چه چیزی منتشر می شد؟). همچنین توجه داشته باشید که این متد از کلاس Object است . خوب، نه یک، بلکه سه:
  • Wait() رشته فعلی را در حالت انتظار قرار می دهد تا زمانی که رشته دیگری متد notify() یا notifyAll() را روی این شیء فراخوانی کند (در ادامه در مورد این متدها صحبت خواهیم کرد).

  • Wait(long timeout) رشته فعلی را در حالت انتظار قرار می دهد تا زمانی که رشته دیگری متد notify() یا notifyAll() را روی این شیء فراخوانی کند یا بازه زمانی مشخص شده توسط timeout منقضی شود.

  • انتظار (تایم اوت طولانی، نانوهای داخلی) مانند روش قبلی است، اما در اینجا نانو به شما امکان می‌دهد نانوثانیه‌ها را مشخص کنید (تایم اوت دقیق‌تر).

  • notify() به شما امکان می دهد تا یک رشته تصادفی را که در بلوک همگام سازی فعلی منتظر است، بیدار کنید. باز هم، این روش را فقط می توان در یک بلوک یا روش همگام فراخوانی کرد (به هر حال، در جاهای دیگر کسی برای بیدار شدن وجود نخواهد داشت).

  • notifyAll() تمام رشته های منتظر در مانیتور فعلی را بیدار می کند (همچنین فقط در یک بلوک یا روش همگام استفاده می شود ).

110. چگونه یک نخ را متوقف کنیم؟

اولین چیزی که در اینجا باید بگوییم این است که وقتی run() تا پایان کامل می شود، رشته به طور خودکار خاتمه می یابد. اما گاهی اوقات می خواهیم قبل از انجام روش، یک نخ را زودتر از موعد مقرر بکشیم. پس چه کار کنیم؟ شاید بتوانیم از متد stop() روی شی Thread استفاده کنیم ؟ جواب منفی! این روش منسوخ شده است و ممکن است باعث خرابی سیستم شود. بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه دهنده جاوا.  قسمت 12 - 4خب پس چی؟ دو راه برای انجام این کار وجود دارد: اول ، از پرچم بولین داخلی آن استفاده کنید. بیایید به یک مثال نگاه کنیم. ما یک رشته را پیاده سازی می کنیم که باید عبارت خاصی را روی صفحه نمایش دهد تا زمانی که موضوع کاملاً متوقف شود:
public class CustomThread extends Thread {
private boolean isActive;

   public CustomThread() {
       this.isActive = true;
   }

   @Override
   public void run() {
       {
           while (isActive) {
               System.out.println("The thread is executing some logic...");
           }
           System.out.println("The thread stopped!");
       }
   }

   public void stopRunningThread() {
       isActive = false;
   }
}
فراخوانی متد stopRunningThread() پرچم داخلی را روی false قرار می دهد و باعث خاتمه متد run() می شود. بیایید آن را به صورت اصلی بنامیم :
System.out.println("Program starting...");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// As long as our main thread is asleep, our CustomThread runs and prints its message on the console
thread.stopRunningThread();
System.out.println("Program stopping...");
در نتیجه، چیزی شبیه به این را در کنسول خواهیم دید:
شروع برنامه... thread در حال اجرای برخی از منطق است... Thread در حال اجرای برخی از منطق ها... Thread در حال اجرای برخی از منطق ها... Thread در حال اجرای برخی از منطق ها... Thread در حال اجرای برخی از منطق ها... موضوع در حال اجرای یک منطق است... برنامه متوقف می شود... موضوع متوقف شد!
این بدان معناست که موضوع ما شروع شد، چندین پیام را روی کنسول چاپ کرد و سپس با موفقیت متوقف شد. توجه داشته باشید که تعداد پیام های نمایش داده شده از راه اندازی به راه اندازی متفاوت است. و گاهی اوقات ممکن است رشته کمکی اصلاً چیزی را نمایش ندهد. رفتار خاص بستگی به مدت زمان خواب نخ اصلی دارد. هرچه بیشتر بخوابد، کمتر احتمال دارد که رشته کمکی بتواند چیزی را نمایش دهد. با زمان خواب 1 میلی ثانیه، تقریباً هرگز پیام ها را نخواهید دید. اما اگر آن را روی 20 میلی ثانیه تنظیم کنید، تقریباً همیشه پیام ها نمایش داده می شوند. وقتی زمان خواب کوتاه است، نخ به سادگی زمان شروع و انجام کار خود را ندارد. در عوض، بلافاصله متوقف می شود. راه دوم استفاده از متد interrupted() در شی Thread است . مقدار پرچم قطع شده داخلی را برمی گرداند که به طور پیش فرض نادرست است . یا متد interrupt() آن ، که این پرچم را روی true قرار می دهد (زمانی که پرچم true باشد ، رشته باید از کار بیفتد). بیایید به یک مثال نگاه کنیم:
public class CustomThread extends Thread {

   @Override
   public void run() {
       {
           while (!Thread.interrupted()) {
               System.out.println("The thread is executing some logic...");
           }
           System.out.println("The thread stopped!");
       }
   }
}
در حال اجرا به صورت اصلی :
System.out.println("Program starting...");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Program stopping...");
نتیجه اجرای این همان حالت اول است، اما من این روش را بیشتر دوست دارم: کد کمتری نوشتیم و از عملکردهای آماده و استاندارد بیشتری استفاده کردیم. خوب، برای امروز همین است!
بیشتر بخوانید:
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION