JavaRush /وبلاگ جاوا /Random-FA /تجزیه و تحلیل پرسش و پاسخ از مصاحبه برای توسعه دهنده جاوا...

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

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

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

در حافظه در جاوا (Heap که بعداً در مورد آن صحبت خواهیم کرد) یک ناحیه وجود دارد - String pool یا string pool. برای ذخیره مقادیر رشته طراحی شده است. به عبارت دیگر، هنگامی که یک رشته خاص را ایجاد می کنید، به عنوان مثال از طریق دو نقل قول:
String str = "Hello world";
یک بررسی انجام می شود تا ببیند که استخر رشته مقدار داده شده را دارد یا خیر. اگر چنین است، متغیر str یک مرجع به آن مقدار در استخر اختصاص داده می شود. اگر این کار را نکرد، یک مقدار جدید در pool ایجاد می‌شود و یک مرجع به آن به متغیر str اختصاص داده می‌شود . بیایید به یک مثال نگاه کنیم:
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
true روی صفحه نمایش داده می شود . ما به یاد داریم که == مراجع را با هم مقایسه می کند - به این معنی که این دو مرجع به یک مقدار از مجموعه رشته ها اشاره می کنند. این کار برای این است که بسیاری از اشیاء یکسان از نوع String در حافظه تولید نشوند، زیرا همانطور که به یاد داریم، 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);
ما دو مقدار نادرست دریافت خواهیم کرد ، به این معنی که در اینجا سه ​​مقدار متفاوت داریم که به آنها ارجاع داده می شود. در واقع، به همین دلیل است که توصیه می شود رشته ها را به سادگی با استفاده از دو نقل قول ایجاد کنید. با این حال، می‌توانید هنگام ایجاد یک شی با استفاده از new ، مقادیر را به یک استخر رشته اضافه کنید (یا به آن ارجاع دهید) . برای این کار از متد کلاس رشته - intern() استفاده می کنیم . این روش به اجبار یک مقدار را در مجموعه رشته ایجاد می کند، یا اگر قبلاً در آنجا ذخیره شده باشد، پیوندی به آن دریافت می کند. در اینجا یک مثال است:
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);
در نتیجه، سه مقدار واقعی را در کنسول دریافت خواهیم کرد ، به این معنی که هر سه متغیر به یک رشته اشاره دارند.تجزیه و تحلیل پرسش و پاسخ از مصاحبه برای توسعه دهنده جاوا.  قسمت 7 - 2

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

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

   public Lawyer() {
       System.out.println("Юрист взят в штат.");
   }

   @Override
   public void work() {
       System.out.println("Решение юридических вопросов...");
   }
}
و حسابدار:
public class Accountant implements Employee{

   public Accountant() {
       System.out.println("Бухгалтер взят в штат.");
   }

   @Override
   public void work() {
       System.out.println("Ведение бухгалтерского отчёта....");
   }
}
روش ها بسیار مشروط هستند: فقط باید ببینیم که آنها اجرا می شوند. همین وضعیت در مورد سازنده نیز صدق می کند. به لطف خروجی کنسول، می بینیم که چه زمانی اشیاء جدید ایجاد می شوند. همچنین یک اداره کارمند داریم که وظیفه آن صدور کارمند درخواستی است و اگر نبود او را استخدام کنید و در پاسخ به درخواست صادر کنید:
public class StaffDepartment {
   private Map<String, Employee> currentEmployees = new HashMap<>();

   public Employee receiveEmployee(String type) throws Exception {
       Employee result;
       if (currentEmployees.containsKey(type)) {
           result = currentEmployees.get(type);
       } else {
           switch (type) {
               case "Бухгалтер":
                   result = new Accountant();
                   currentEmployees.put(type, result);
                   break;
               case "Юрист":
                   result = new Lawyer();
                   currentEmployees.put(type, result);
                   break;
               default:
                   throw new Exception("Данный сотрудник в штате не предусмотрен!");
           }
       }
       return result;
   }
}
یعنی منطق ساده است: اگر یک واحد داده شده وجود دارد، آن را برگردانید، اگر نه، آن را ایجاد کنید، آن را در ذخیره سازی (چیزی شبیه کش) قرار دهید و آن را پس دهید. حالا بیایید ببینیم همه اینها چگونه کار می کند:
public static void main(String[] args) throws Exception {
   StaffDepartment staffDepartment = new StaffDepartment();
   Employee empl1  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl2  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl3  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl4  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl5  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl6  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl7  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl8  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl9  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl10  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
}
و بر این اساس در کنسول یک خروجی وجود خواهد داشت:
وکیل استخدام شده است. حل مسائل حقوقی ... حسابدار استخدام شد. نگهداری گزارش حسابداری .... حل مسائل حقوقی ... نگهداری گزارش حسابداری .... حل مسائل حقوقی ... نگهداری گزارش حسابداری .... حل مسائل حقوقی ... نگهداری گزارش حسابداری .... حل مسائل حقوقی ... نگهداری گزارشات حسابداری ...
همانطور که می بینید، تنها دو شی ایجاد شد که بارها مورد استفاده مجدد قرار گرفتند. مثال بسیار ساده است، اما به وضوح نشان می دهد که چگونه استفاده از این الگو می تواند منابع ما را ذخیره کند. خوب همانطور که متوجه شدید منطق این الگو بسیار شبیه به منطق استخر بیمه است. در این مقاله می توانید در مورد انواع الگوهای GOF بیشتر بخوانید .تجزیه و تحلیل پرسش و پاسخ از مصاحبه برای توسعه دهنده جاوا.  قسمت 7 - 3

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" و فقط یک عبارت رشته " " استفاده کنیم ). روش دوم، بیش از حد دارای یک آرگومان اضافی است - حد . limit - حداکثر مقدار مجاز آرایه حاصل. یعنی زمانی که رشته قبلاً به حداکثر تعداد مجاز زیررشته تقسیم شده باشد، دیگر شکافی وجود نخواهد داشت و آخرین عنصر دارای «باقی» از رشته احتمالاً زیر تقسیم خواهد بود. مثال:
String str = "Hello, world it's Amigo!";
String[] arr = str.split(" ", 2);
for (String s : arr) {
  System.out.println(s);
}
خروجی کنسول:
سلام، دنیا آمیگو است!
همانطور که می بینیم، اگر برای محدودیت = 2 نبود ، آخرین عنصر آرایه می تواند به سه رشته فرعی تقسیم شود.تجزیه و تحلیل پرسش و پاسخ از مصاحبه برای توسعه دهنده جاوا.  قسمت 7 - 4

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

دلایل مختلفی برای ترجیح دادن یک آرایه به یک رشته در هنگام ذخیره رمز عبور وجود دارد: 1. مخزن رشته و تغییرناپذیری رشته. هنگام استفاده از یک آرایه ( char[] )، می‌توانیم به صراحت داده‌ها را پس از پایان کار با آن پاک کنیم. همچنین، می‌توانیم آرایه را تا جایی که می‌خواهیم بازنویسی کنیم و رمز عبور معتبر در هیچ کجای سیستم وجود نخواهد داشت، حتی قبل از جمع‌آوری زباله (کافی است چند سلول را به مقادیر نامعتبر تغییر دهیم). در عین حال، String یک کلاس تغییرناپذیر است. یعنی اگر بخواهیم مقدار آن را تغییر دهیم یک عدد جدید می گیریم در حالی که قدیمی در استخر رشته باقی می ماند. اگر بخواهیم مقدار String یک رمز عبور را حذف کنیم، این می‌تواند کار بسیار دشواری باشد، زیرا ما به جمع‌آورنده زباله نیاز داریم تا مقدار را از String Pool حذف کند ، و احتمال زیادی وجود دارد که این مقدار String برای مدتی در آنجا باقی بماند. مدت زمان طولانی. یعنی در این شرایط String از نظر امنیت ذخیره سازی داده ها از آرایه char پایین تر است. 2. اگر مقدار String به طور تصادفی به کنسول (یا گزارش‌ها) خروجی شود، خود مقدار نمایش داده می‌شود:
String password = "password";
System.out.println("Пароль - " + password);
خروجی کنسول:
کلمه عبور
در همان زمان، اگر به طور تصادفی یک آرایه را به کنسول خروجی دهید:
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Пароль - " + arr);
گوبلدیگوک نامفهومی در کنسول وجود خواهد داشت:
رمز عبور - [C@7f31245a
در واقع gobbledygook نیست، اما: [C نام کلاس یک آرایه char است ، @ یک جداکننده است، و به دنبال آن 7f31245a یک کد هگزادسیمال است. 3. سند رسمی، راهنمای معماری رمزنگاری جاوا، به صراحت به ذخیره رمزهای عبور در char[] به جای String اشاره می‌کند : «به نظر منطقی می‌رسد که یک رمز عبور در یک شی از نوع java.lang.String جمع‌آوری و ذخیره شود . با این حال، در اینجا یک اخطار وجود دارد: اشیاء رشته تغییر ناپذیر هستند، به عنوان مثال، هیچ روشی تعریف نشده است که اجازه دهد محتویات یک شی String پس از استفاده تغییر (بازنویسی) یا باطل شود. این ویژگی اشیاء String را برای ذخیره اطلاعات حساس مانند رمز عبور کاربر نامناسب می کند. در عوض، همیشه باید اطلاعات امنیتی حساس را در یک آرایه کاراکتر جمع‌آوری و ذخیره کنید.»تجزیه و تحلیل پرسش و پاسخ از مصاحبه برای توسعه دهنده جاوا.  قسمت 7 - 5

Enum

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

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

67. آیا Enum می تواند رابط ها را پیاده سازی کند؟

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

68. آیا Enum می تواند یک کلاس را گسترش دهد؟

نه، نمی‌تواند، زیرا 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() را لغو کنید تا هنگام فراخوانی متد toString یک روش خاص برای نمایش enum خود تعریف کنید (هنگامی که enum را به یک رشته معمولی ترجمه می‌کنید، مثلاً برای خروجی به کنسول یا گزارش‌ها).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Выбрана роль - " + super.toString();
   }
}
این همه برای امروز، تا قسمت بعدی!تجزیه و تحلیل پرسش و پاسخ از مصاحبه برای توسعه دهنده جاوا.  قسمت 7 - 6
سایر مواد این سری:
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION