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

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

در گروه منتشر شد
هی همه! برنامه نویسی پر از مشکلات است. و به ندرت یک موضوع وجود دارد که باعث لغزش و خنثی شدن انگشت پا نشود. این به ویژه برای مبتدیان صادق است. تنها راه نجات انگشتان پا یادگیری است. به ویژه، شما باید عمیقاً در اساسی ترین موضوعات فرو بروید. امروز، ما به بررسی محبوب ترین سوالات در طول مصاحبه برای توسعه دهندگان جاوا ادامه خواهیم داد. این سوالات مصاحبه در پوشش موضوعات اساسی بسیار عالی عمل می کند. توجه داشته باشید که این لیست شامل چند سوال نه چندان استاندارد نیز می شود که به شما امکان می دهد به گونه ای متفاوت به مسائل رایج برخورد کنید. بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه دهنده جاوا.  قسمت 7 - 1

62. حوض زهی چیست و چرا به آن نیاز است؟

بخشی از حافظه ای که در دسترس یک برنامه جاوا قرار می گیرد heap نام دارد (که بعداً در مورد آن صحبت خواهیم کرد) و بخشی از heap String pool نامیده می شود . این برای ذخیره مقادیر رشته است. به عبارت دیگر، هنگامی که یک رشته ایجاد می کنید، برای مثال، با استفاده از دو نقل قول مانند زیر:
String str = "Hello world";
JVM بررسی می کند که آیا مجموعه رشته ها از قبل مقدار مشخص شده را دارد یا خیر. اگر اینطور باشد، آنگاه به متغیر str مرجعی به آن مقدار در pool اختصاص داده می شود. اگر اینطور نباشد، یک مقدار جدید در pool ایجاد می‌شود و یک مرجع به آن به متغیر str اختصاص داده می‌شود . بیایید یک مثال را در نظر بگیریم:
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
true روی صفحه نمایش داده می شود. به یاد داشته باشید که == مراجع را با هم مقایسه می کند و این دو متغیر به یک مقدار در مجموعه رشته ها اشاره می کنند. این به جلوگیری از تولید بسیاری از اشیاء رشته ای یکسان در حافظه کمک می کند. ما می‌توانیم این کار را انجام دهیم، زیرا همانطور که به خاطر می‌آورید، String یک کلاس تغییرناپذیر است، بنابراین داشتن چندین مرجع به یک مقدار اشکالی ندارد. اکنون غیرممکن است که شرایطی داشته باشیم که تغییر مقدار در یک مکان منجر به تغییر چندین مرجع دیگر شود. با این حال، اگر یک رشته با استفاده از new ایجاد کنیم :
String str = new String("Hello world");
سپس یک شی جداگانه در حافظه ایجاد می شود و مقدار رشته مشخص شده را ذخیره می کند (مهم نیست که آن مقدار قبلاً در مجموعه رشته ها باشد). برای تایید این ادعا به این نکته توجه کنید:
String firstStr = new String("Hello world");
String secondStr = "Hello world";
String thirdStr = new String("Hello world");
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
ما دو خط دریافت خواهیم کرد که نشان دهنده false است ، به این معنی که ما سه رشته مجزا داریم. اساسا، به همین دلیل است که شما باید رشته ها را به سادگی با استفاده از دو نقل قول ایجاد کنید. با این حال، می‌توان مقادیری را در مجموعه رشته‌ها اضافه کرد (یا به آنها اشاره کرد، حتی هنگام ایجاد یک شی با استفاده از کلمه کلیدی جدید . برای این کار از متد intern() کلاس String استفاده می کنیم . این روش تضمین می‌کند که یا مقدار را در استخر رشته ایجاد می‌کنیم یا اگر از قبل وجود داشته باشد، به آن ارجاع می‌دهیم. در اینجا یک مثال است:
String firstStr = new String("Hello world").intern();
String secondStr = "Hello world";
String thirdStr = new String("Hello world").intern();
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
System.out.println(secondStr == thirdStr);
این کد سه بار خروجی درست به کنسول می دهد، که به ما می گوید که هر سه متغیر به یک رشته در حافظه اشاره دارند.

63. چه الگوهای طراحی GoF در استخر رشته استفاده می شود؟

در استخر رشته، الگوی طراحی GoF یک الگوی وزن مگس است . اگر به الگوی طراحی دیگری در اینجا توجه کرده اید، آن را در نظرات به اشتراک بگذارید. در اینجا ما در مورد الگوی طراحی Flyweight صحبت خواهیم کرد. این یک الگوی طراحی ساختاری است که در آن یک شی که خود را به عنوان یک نمونه منحصر به فرد در مکان های مختلف برنامه نشان می دهد، در واقع منحصر به فرد نیست. Flyweight با ذخیره کردن حالت اشتراکی اشیا به جای ذخیره داده های یکسان در هر شی، حافظه را ذخیره می کند. برای درک اصل مطلب، این مثال ابتدایی را در نظر بگیرید. فرض کنید یک رابط کاربری داریم :
public interface Employee {
   void work();
}
و چند پیاده سازی دارد، مانند کلاس حقوقی :
public class Lawyer implements Employee {

   public Lawyer() {
       System.out.println("A lawyer was hired.");
   }

   @Override
   public void work() {
       System.out.println("Settling legal issues...");
   }
}
و یک کلاس حسابدار :
public class Accountant implements Employee {

   public Accountant() {
       System.out.println("An accountant was hired.");
   }

   @Override
   public void work() {
       System.out.println("Keeping accounting records...");
   }
}
روش ها کاملاً دلخواه هستند - برای این مثال، فقط باید ببینیم که آنها در حال اجرا هستند. در مورد سازنده هم همینطور است. خروجی کنسول زمان ایجاد اشیاء جدید را به ما می گوید. ما همچنین یک بخش منابع انسانی داریم که وظیفه آن بازگرداندن کارمند درخواستی است. اگر آن کارمند قبلاً کارمند نباشد، استخدام می‌شوند و بخش منابع انسانی کارمند جدید را برمی‌گرداند:
public class HumanResourcesDepartment {
   private Map<String, Employee> currentEmployees = new HashMap<>();

   public Employee getEmployee(String type) throws Exception {
       Employee result;
       if (currentEmployees.containsKey(type)) {
           result = currentEmployees.get(type);
       } else {
           switch (type) {
               case "Accountant":
                   result = new Accountant();
                   currentEmployees.put(type, result);
                   break;
               case "Lawyer":
                   result = new Lawyer();
                   currentEmployees.put(type, result);
                   break;
               default:
                   throw new Exception("This employee is not on the staff!");
           }
       }
       return result;
   }
}
بنابراین، منطق ساده است: اگر شی مورد نظر وجود دارد، آن را برگردانید. اگر نه، آن را ایجاد کنید، آن را در فضای ذخیره سازی (چیزی شبیه کش) قرار دهید و آن را برگردانید. حالا بیایید ببینیم همه اینها چگونه کار می کند:
public static void main(String[] args) throws Exception {
   HumanResourcesDepartment humanResourcesDepartment = new HumanResourcesDepartment();
   Employee empl1 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl2 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
   Employee empl3 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl4 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
   Employee empl5 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl6 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
   Employee empl7 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl8 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
   Employee empl9 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl10 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
}
در اینجا چیزی است که ما در کنسول خواهیم دید:
یک وکیل استخدام شد. حل و فصل مسائل حقوقی ... حسابدار استخدام شد. نگهداری سوابق حسابداری ... حل و فصل مسائل حقوقی ... نگهداری سوابق حسابداری ... حل و فصل مسائل حقوقی ... نگهداری سوابق حسابداری ... حل و فصل مسائل حقوقی ... نگهداری سوابق حسابداری ... حل و فصل مسائل حقوقی ... نگهداری حسابداری سوابق…
همانطور که می بینید، ما فقط دو شی ایجاد کردیم و بارها از آنها استفاده کردیم. مثال بسیار ساده است، اما نشان می دهد که چگونه این الگوی طراحی می تواند منابع ما را حفظ کند. همانطور که ممکن است متوجه شده باشید، منطق این الگو به طرز دردناکی شبیه منطق یک استخر بیمه است. بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه دهنده جاوا.  قسمت 7 - 2

64. چگونه یک رشته را به قطعات تقسیم کنیم؟ کد مربوطه را مثال بزنید

بدیهی است که این سوال در مورد روش تقسیم است . کلاس String دو تغییر از این متد دارد:
String split(String regex);
و
String split(String regex);
پارامتر regex جداکننده است - برخی از عبارت های منظم که برای تقسیم رشته به آرایه ای از رشته ها استفاده می شود، به عنوان مثال:
String str = "Hello, world it's Amigo!";
String[] arr = str.split("\\s");
for (String s : arr) {
  System.out.println(s);
}
کنسول نمایش خواهد داد:
سلام، دنیا آمیگو است!
بنابراین، رشته ما به آرایه‌ای از رشته‌ها تقسیم شد و از یک فاصله به‌عنوان جداکننده استفاده کرد (به‌جای عبارت منظم "\\s" ، ما همچنین می‌توانستیم از عبارت رشته معمولی " " استفاده کنیم ). نوع دوم، بیش از حد بارگذاری شده، دارای یک پارامتر حد اضافی است . حد حداکثر اندازه مجاز آرایه حاصل است. به عبارت دیگر، هنگامی که رشته به حداکثر تعداد مجاز زیررشته تقسیم شد، تقسیم متوقف می شود و آخرین عنصر حاوی هر "باقی مانده" از رشته احتمالاً غیرقابل تقسیم خواهد بود. مثال:
String str = "Hello, world it's Amigo!";
String[] arr = str.split(" ", 2);
for (String s : arr) {
  System.out.println(s);
}
خروجی کنسول:
سلام، دنیا آمیگو است!
همانطور که می بینیم، اگر برای limit = 2 نبود ، آخرین عنصر آرایه می تواند به سه رشته فرعی تقسیم شود.

65. چرا یک آرایه کاراکتری بهتر از یک رشته برای ذخیره رمز عبور است؟

دلایل مختلفی برای ترجیح آرایه به رشته در هنگام ذخیره رمز عبور وجود دارد:

1. استخر رشته و تغییرناپذیری رشته.

هنگام استفاده از یک آرایه ( char[] )، می‌توانیم به صراحت داده‌ها را پس از اتمام کار با آن پاک کنیم. همچنین می‌توانیم آرایه را تا جایی که می‌خواهیم بازنویسی کنیم و رمز عبور را حتی قبل از جمع‌آوری زباله از سیستم حذف کنیم (کافی است چند سلول را به مقادیر نامعتبر تغییر دهیم). در مقابل، String یک کلاس تغییرناپذیر است. به این معنی که اگر بخواهیم مقدار یک شی String را تغییر دهیم ، یک شی جدید دریافت می کنیم، اما قدیمی در استخر رشته باقی می ماند. اگر بخواهیم رشته حاوی رمز عبور را حذف کنیم، با کار پیچیده‌ای روبرو می‌شویم زیرا به جمع‌آورنده زباله نیاز داریم تا آن مقدار را از مجموعه رشته‌ها حذف کند، اما احتمالاً آن رشته برای مدت طولانی در آنجا باقی خواهد ماند. یعنی وقتی صحبت از ذخیره ایمن داده ها می شود، String نسبت به آرایه char پایین تر است .

2. اگر مقدار String را به کنسول (یا یک log) خروجی دهیم ، دریافت می کنیم:

String password = "password";
System.out.println("Password - " + password);
خروجی کنسول:
رمز عبور - رمز عبور
و اگر آرایه را روی کنسول چاپ کنید:
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Password - " + arr);
کنسول حرف های نامفهوم را نمایش می دهد:
رمز عبور - [C@7f31245a
در واقع چرندیات نیست. در اینجا نحوه درک آنچه می بینید آمده است: [C نام کلاس است - آرایه char ، @ یک جداکننده است، و سپس 7f31245a یک کد هش هگزادسیمال است.

3. راهنمای مرجع رسمی معماری رمزنگاری جاوا (JCA) به صراحت به ذخیره گذرواژه‌ها در یک char[] به‌جای یک رشته اشاره می‌کند :

"به نظر می رسد منطقی است که رمز عبور را در یک شی از نوع java.lang.String جمع آوری و ذخیره کنیم . با این حال، در اینجا هشدار وجود دارد: اشیاء از نوع String غیر قابل تغییر هستند، به عنوان مثال، هیچ روشی تعریف نشده است که به شما امکان تغییر (بازنویسی) را بدهد. یا محتویات یک رشته را پس از استفاده صفر کنید. این ویژگی اشیاء String را برای ذخیره اطلاعات حساس امنیتی مانند رمزهای عبور کاربر نامناسب می کند. به جای آن همیشه باید اطلاعات حساس به امنیت را در یک آرایه نویسه جمع آوری و ذخیره کنید." بررسی پرسش ها و پاسخ های مصاحبه شغلی برای یک موقعیت توسعه دهنده جاوا.  قسمت 7 - 3

Enum

66. توضیح مختصری در مورد Enum در جاوا ارائه دهید

Enum مخفف enumeration است که مجموعه‌ای از ثابت‌های رشته‌ای است که با یک نوع مشترک متحد شده‌اند. ما یکی را با استفاده از کلمه کلیدی enum اعلام می کنیم . در اینجا یک مثال با enum آورده شده است : نقش های مجاز در برخی از محوطه مدرسه:
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD
}
کلماتی که با حروف بزرگ نوشته می شوند، ثابت های شمارش هستند. آنها به روشی ساده و بدون اپراتور جدید اعلام می شوند . استفاده از شمارش‌ها زندگی را بسیار آسان‌تر می‌کند زیرا به جلوگیری از اشتباهات و سردرگمی در نام‌ها کمک می‌کند (زیرا لیست تنها مقادیر معتبر را تعریف می‌کند). برای من، آنها در ساختار سوئیچ بسیار راحت هستند .

67. آیا Enum می تواند واسط ها را پیاده سازی کند (از کلمه کلیدی implements استفاده کند)؟

آره. به هر حال، enums باید بیش از مجموعه‌های غیرفعال (مانند نقش‌ها در محوطه مدرسه) را نشان دهد. در جاوا، آنها می توانند اشیاء پیچیده تری را نشان دهند، بنابراین ممکن است لازم باشد عملکردهای بیشتری را به آنها اضافه کنید. این همچنین به شما این امکان را می‌دهد که با جایگزین کردن مقدار enum در مکان‌هایی که نوع رابط پیاده‌سازی شده مورد نیاز است، از چندشکلی استفاده کنید .

68. آیا Enum می تواند یک کلاس را گسترش دهد (از کلمه کلیدی extends استفاده کند)؟

نه، نمی‌تواند، زیرا enum یک زیر کلاس از کلاس پیش‌فرض Enum<T> است که T نوع enum است. این چیزی نیست جز یک کلاس پایه مشترک برای همه انواع enum در زبان جاوا. تبدیل از enum به کلاس توسط کامپایلر جاوا در زمان کامپایل انجام می شود. پسوند به صراحت در کد نشان داده نشده است، اما همیشه ضمنی است.

69. آیا امکان ایجاد Enum بدون هیچ نمونه ای از آبجکت وجود دارد؟

این سوال کمی گیج کننده است و مطمئن نیستم که کاملا آن را درک کرده باشم. من دو تفسیر دارم: 1. آیا می توانید یک enum بدون هیچ مقداری داشته باشید ؟ بله، البته، اما مانند یک کلاس خالی خواهد بود - بیهوده، به عنوان مثال
public enum Role {
}
و اگر تماس بگیریم:
var s = Role.values();
System.out.println(s);
ما موارد زیر را در کنسول دریافت می کنیم:
[Lflyweight.Role;@9f70c54
(آرایه خالی از مقادیر Role ) 2. آیا امکان ایجاد enum بدون عملگر جدید وجود دارد ؟ بله حتما. همانطور که در بالا گفتم، شما از عملگر جدید برای مقادیر enum استفاده نمی کنید، زیرا آنها مقادیر ثابت هستند.

70. آیا می توانیم متد ()toString Enum را نادیده بگیریم؟

بله، مطمئناً می‌توانید متد toString() را لغو کنید تا نحوه نمایش enum خود را هنگام فراخوانی متد toString تعریف کنید ( مثلاً هنگام تبدیل یک enum به یک رشته معمولی برای خروجی آن به کنسول یا گزارش‌ها).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Selected role - " + super.toString();
   }
}
امروز برای من همین است. تا قسمت بعدی!
بیشتر بخوانید:
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION