JavaRush /Java Blogu /Random-AZ /Java tərtibatçısı üçün müsahibələrdən alınan sualların və...

Java tərtibatçısı üçün müsahibələrdən alınan sualların və cavabların təhlili. 7-ci hissə

Qrupda dərc edilmişdir
Hamıya salam! Proqramlaşdırma tələlərlə doludur. Və praktiki olaraq heç bir mövzu yoxdur ki, büdrəməyəsiniz və qabarmayasınız. Bu, xüsusilə yeni başlayanlar üçün doğrudur. Bunu azaltmağın yeganə yolu öyrənməkdir. Xüsusilə, bu, ən əsas mövzuların ətraflı təhlilinə aiddir. Bu gün mən əsas mövzuları yaxşı əhatə edən Java developer müsahibələrindən 250+ sualı təhlil etməyə davam edirəm. Qeyd etmək istərdim ki, siyahıda ümumi mövzulara fərqli bucaqdan baxmağa imkan verən bəzi qeyri-standart suallar da var.Java tərtibatçısı üçün müsahibələrdən alınan sualların və cavabların təhlili.  Hissə 7 - 1

62. Simli hovuz nədir və nə üçün lazımdır?

Java-da yaddaşda (heap, daha sonra danışacağıq) bir sahə var - String pool və ya string pool. O, sətir dəyərlərini saxlamaq üçün nəzərdə tutulmuşdur. Başqa sözlə, müəyyən bir sətir yaratdığınız zaman, məsələn, qoşa dırnaqlar vasitəsilə:
String str = "Hello world";
sətir hovuzunun verilmiş qiymətə malik olub-olmadığını yoxlamaq üçün yoxlama aparılır. Əgər belədirsə, str dəyişəninə hovuzdakı həmin dəyərə istinad təyin edilir. Əks halda, hovuzda yeni dəyər yaradılacaq və ona istinad str dəyişəninə təyin ediləcək . Bir misala baxaq:
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
ekranda true göstərilir . Biz xatırlayırıq ki, == istinadları müqayisə edir, yəni bu iki istinad sətir hovuzundan eyni dəyərə istinad edir. Bu, yaddaşda String tipli bir çox eyni obyektlərin meydana çıxmaması üçün edilir , çünki xatırladığımız kimi, String dəyişməz bir sinifdir və eyni dəyərə çoxlu istinadlarımız varsa, bunun heç bir qəbahəti yoxdur. Bir yerdə bir dəyərin dəyişdirilməsinin eyni anda bir neçə digər keçid üçün dəyişikliklərə səbəb olduğu bir vəziyyət üçün artıq mümkün deyil. Ancaq buna baxmayaraq, new istifadə edərək bir sətir yaratsaq :
String str = new String("Hello world");
yaddaşda bu sətir dəyərini saxlayacaq ayrıca obyekt yaradılacaq (və sətir hovuzunda artıq belə bir dəyərin olub-olmamasının fərqi yoxdur). Təsdiq olaraq:
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);
İki yanlış dəyər alacağıq , yəni burada istinad edilən üç fərqli dəyərimiz var. Əslində, buna görə sadəcə ikiqat dırnaq işarələrindən istifadə edərək sətirlər yaratmaq tövsiyə olunur. Bununla belə, new istifadə edərək obyekt yaratarkən simli hovuza dəyərlər əlavə edə (və ya istinad əldə edə bilərsiniz) . Bunun üçün biz string class metodundan istifadə edirik - intern() . Bu üsul string hovuzda məcburi bir dəyər yaradır və ya artıq orada saxlanılırsa, ona keçid əldə edir. Budur bir nümunə:
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);
Nəticədə, konsolda üç həqiqi dəyər alacağıq , yəni hər üç dəyişən eyni sətirə istinad edir.Java tərtibatçısı üçün müsahibələrdən alınan sualların və cavabların təhlili.  7-2 hissə

63. Simli hovuzda hansı GOF nümunələri istifadə olunur?

GOF nümunəsi simli hovuzda aydın görünür - flyweight , əks halda məskunlaşan adlanır. Burada başqa şablon görsəniz, şərhlərdə paylaşın. Yaxşı, yüngül şablon haqqında danışaq. Yüngül, proqramın müxtəlif yerlərində özünü unikal nümunə kimi təqdim edən obyektin əslində belə olmadığı struktur dizayn nümunəsidir. Yüngül, hər bir obyektdə eyni məlumatları saxlamaq əvəzinə, obyektlərin paylaşılan vəziyyətini öz aralarında paylaşaraq yaddaşa qənaət edir. Mahiyyəti başa düşmək üçün ən sadə misala baxaq. Deyək ki, işçi interfeysimiz var:
public interface Employee {
   void work();
}
Və bəzi tətbiqlər var, məsələn, hüquqşünas:
public class Lawyer implements Employee {

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

   @Override
   public void work() {
       System.out.println("Решение юридических вопросов...");
   }
}
Və mühasib:
public class Accountant implements Employee{

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

   @Override
   public void work() {
       System.out.println("Ведение бухгалтерского отчёта....");
   }
}
Metodlar çox şərtlidir: sadəcə onların həyata keçirildiyini görmək lazımdır. Eyni vəziyyət konstruktora da aiddir. Konsol çıxışı sayəsində yeni obyektlərin nə zaman yaradıldığını görəcəyik. Bizim işçi şöbəmiz də var ki, onun vəzifəsi tələb olunan işçini çıxarmaq, o yoxdursa, onu işə götürmək və sorğuya cavab verməkdir:
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;
   }
}
Yəni, məntiq sadədir: əgər verilmiş vahid varsa, onu qaytarın, yoxdursa, onu yaradın, anbara yerləşdirin (keş kimi bir şey) və geri verin. İndi hamısının necə işlədiyini görək:
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();
}
Və konsolda, müvafiq olaraq, bir çıxış olacaq:
Vəkil işə götürülüb. Hüquqi məsələlərin həlli... Mühasib işə qəbul olunub. Mühasibat hesabatının aparılması.... Hüquqi məsələlərin həlli... Mühasibat hesabatının aparılması.... Hüquqi məsələlərin həlli... Mühasibat hesabatının aparılması.... Hüquqi məsələlərin həlli... Mühasibat hesabatının aparılması.... Hüquqi məsələlərin həlli... Mühasibat hesabatlarının aparılması...
Gördüyünüz kimi, dəfələrlə təkrar istifadə edilən yalnız iki obyekt yaradılmışdır. Nümunə çox sadədir, lakin bu şablondan istifadənin resurslarımıza necə qənaət edə biləcəyini aydın şəkildə nümayiş etdirir. Yaxşı, qeyd etdiyiniz kimi, bu nümunənin məntiqi sığorta hovuzunun məntiqinə çox oxşardır. Bu məqalədə GOF naxışlarının növləri haqqında daha çox oxuya bilərsiniz .Java tərtibatçısı üçün müsahibələrdən alınan sualların və cavabların təhlili.  7-3-cü hissə

64. Sətir hissələrə necə bölünür? Zəhmət olmasa müvafiq kodun nümunəsini təqdim edin

Aydındır ki, bu sual bölünmə üsulu ilə bağlıdır . String sinfi bu metodun iki variantına malikdir:
String split(String regex);
String split(String regex);
regex sətir ayırıcıdır - sətri sətirlər massivinə bölən bəzi müntəzəm ifadələr, məsələn:
String str = "Hello, world it's Amigo!";
String[] arr = str.split("\\s");
for (String s : arr) {
  System.out.println(s);
}
Konsola aşağıdakılar çıxacaq:
Salam, dünya bu Amigo!
Yəni, bizim sətir dəyərimiz sətirlər massivinə bölünmüşdü və ayırıcı boşluq idi (ayırmaq üçün biz boşluq olmayan normal ifadə "\\s" və sadəcə " " sətir ifadəsindən istifadə edə bilərdik ). İkinci, həddindən artıq yüklənmiş metodun əlavə bir arqumenti var - limit . limit — yaranan massivin icazə verilən maksimum dəyəri. Yəni, sətir artıq icazə verilən maksimum sayda alt sətirlərə bölündükdə, əlavə parçalanma olmayacaq və sonuncu elementdə ola bilsin ki, bölünmüş sətirdən “qalıq” olacaq. Misal:
String str = "Hello, world it's Amigo!";
String[] arr = str.split(" ", 2);
for (String s : arr) {
  System.out.println(s);
}
Konsol çıxışı:
Salam, dünya bu Amigo!
Gördüyümüz kimi, limit = 2 məhdudiyyəti olmasaydı , massivin sonuncu elementi üç alt sətirə bölünə bilərdi.Java tərtibatçısı üçün müsahibələrdən alınan sualların və cavabların təhlili.  7-4-cü hissə

65. Niyə simvollar massivi parolun saxlanması üçün sətirdən daha yaxşıdır?

Şifrəni saxlayarkən massivi sətirdən üstün tutmağın bir neçə səbəbi var: 1. Sətir hovuzu və sətir dəyişməzliyi. Massivdən ( char[] ) istifadə edərkən biz onunla işimiz bitdikdən sonra məlumatları açıq şəkildə silə bilərik. Həmçinin, massivi istədiyimiz qədər yenidən yaza bilərik və etibarlı parol sistemdə heç bir yerdə olmayacaq, hətta zibil yığılmadan əvvəl (bir neçə xananı etibarsız dəyərlərə dəyişdirmək kifayətdir). Eyni zamanda, String dəyişməz sinifdir. Yəni onun dəyərini dəyişmək istəsək, yenisini alacağıq, köhnəsi isə simli hovuzda qalacaq. Əgər biz parolun String dəyərini silmək istəyiriksə , bu, çox çətin iş ola bilər, çünki String hovuzundan dəyəri silmək üçün zibil toplayıcıya ehtiyacımız var və bu String dəyərinin bir müddət ərzində orada qalması ehtimalı yüksəkdir. uzun müddət. Yəni, bu vəziyyətdə, String məlumatların saxlanması təhlükəsizliyi baxımından char massivindən daha aşağıdır. 2. Sətir dəyəri təsadüfən konsola (və ya jurnallara) çıxarılarsa, dəyərin özü göstərilir:
String password = "password";
System.out.println("Пароль - " + password);
Konsol çıxışı:
parol
Eyni zamanda, təsadüfən konsola massiv çıxarsanız:
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Пароль - " + arr);
konsolda anlaşılmaz gobbledygook olacaq:
Parol - [C@7f31245a
Əslində gobbledygook deyil, lakin: [C sinif adı simvol massividir , @ ayırıcıdır, ardınca 7f31245a onaltılıq heşkoddur. 3. Rəsmi sənəd olan Java Kriptoqrafiya Arxitektura Təlimatında parolların String əvəzinə char[] -da saxlanması açıq şəkildə qeyd olunur : “Parolun java.lang.String tipli obyektdə toplanması və saxlanması məntiqli görünür . Bununla belə, burada bir xəbərdarlıq var: String obyektləri dəyişməzdir, yəni istifadədən sonra String obyektinin məzmununun dəyişdirilməsinə (üzerinə yazılmasına) və ya ləğv edilməsinə icazə vermək üçün müəyyən edilmiş metodlar yoxdur . Bu xüsusiyyət String obyektlərini istifadəçi parolları kimi həssas məlumatları saxlamaq üçün yararsız edir. Bunun əvəzinə, həmişə həssas təhlükəsizlik məlumatlarını simvollar massivində toplamalı və saxlamalısınız."Java tərtibatçısı üçün müsahibələrdən alınan sualların və cavabların təhlili.  7-5-ci hissə

Enum

66. Java-da Enum-un qısa təsvirini verin

Enum bir sıralamadır, ümumi tiplə birləşdirilmiş sətir sabitləri toplusudur. Açar söz - enum vasitəsilə elan edilir . Müəyyən bir məktəbdə etibarlı rolların sayına dair bir nümunə :
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD
}
Böyük hərflərlə yazılmış sözlər, new operatorundan istifadə etmədən sadələşdirilmiş şəkildə elan edilən eyni siyahı sabitləridir . Sadalamalardan istifadə həyatı çox asanlaşdırır, çünki onlar ad verməkdə səhvlərdən və çaşqınlıqlardan qaçmağa kömək edir (çünki orada yalnız müəyyən dəyərlər siyahısı ola bilər). Şəxsən mən onları Switch-in məntiq dizaynında istifadə edərkən çox rahat hesab edirəm .

67. Enum interfeysləri həyata keçirə bilərmi?

Bəli. Axı, sadalamalar yalnız passiv kolleksiyaları (məsələn, rolları) təmsil etməlidir. Java-da onlar bəzi funksionallığı olan daha mürəkkəb obyektləri təmsil edə bilər, ona görə də onlara əlavə funksionallıq əlavə etməli ola bilərsiniz. Bu, həmçinin həyata keçirilən interfeys tipinin tələb olunduğu yerlərdə enum dəyərini əvəz etməklə polimorfizmin imkanlarından istifadə etməyə imkan verəcək .

68. Enum sinfi genişləndirə bilərmi?

Xeyr, bunu edə bilməz, çünki enum ümumi sinif Enum <T> -nin defolt alt sinifidir , burada T ümumi sayma tipini təmsil edir. Java dilinin bütün enum növləri üçün ümumi baza sinifindən başqa bir şey deyil. Enumun sinfə çevrilməsi kompilyasiya zamanı Java kompilyatoru tərəfindən həyata keçirilir. Bu genişləndirmə kodda açıq şəkildə göstərilmir, lakin həmişə görünməz şəkildə mövcuddur.

69. Obyekt instansiyaları olmadan Enum yaratmaq mümkündürmü?

Mənə gəlincə, sual bir az qəribədir, ya da tam başa düşmədim. Mənim iki şərhim var: 1. Dəyərləri olmayan bir nömrə ola bilərmi - bəli, əlbəttə ki, boş sinif kimi bir şey olardı - mənasızdır:
public enum Role {
}
Və zəng edir:
var s = Role.values();
System.out.println(s);
Konsolda alacağıq:
[Lflyweight.Role;@9f70c54
( Rol dəyərlərinin boş massivi ) 2. Yeni operator olmadan enum yaratmaq mümkündürmü - bəli, əlbəttə. Yuxarıda dediyim kimi, enum dəyərləri (sadalamalar) üçün yeni operatordan istifadə etmək lazım deyil , çünki bunlar statik dəyərlərdir.

70. Enum üçün toString() metodunu ləğv edə bilərikmi?

Bəli, əlbəttə ki, siz toString metodunu çağırarkən nömrənizi göstərməyin xüsusi yolunu müəyyən etmək üçün toString() metodunu ləğv edə bilərsiniz ( enumu adi sətirə çevirərkən , məsələn, konsola və ya jurnala çıxış üçün).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Выбрана роль - " + super.toString();
   }
}
Hamısı bu gün, növbəti hissəyə qədər!Java tərtibatçısı üçün müsahibələrdən alınan sualların və cavabların təhlili.  7-6 hissə
Seriyadakı digər materiallar:
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION