JavaRush /Java блогу /Random-KY /Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун...
Константин
Деңгээл

Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи. 14-бөлүк

Группада жарыяланган
Фейерверк! Дүйнө тынымсыз жылып, биз тынымсыз кыймылдап жатабыз. Мурда Java иштеп чыгуучусу болуу үчүн бир аз Java синтаксисин билүү жетиштүү болчу, калганы келет. Убакыттын өтүшү менен Java иштеп чыгуучусу болуу үчүн талап кылынган бorмдин деңгээли, ошондой эле талап кылынган бorмдин төмөнкү тилкесин өйдө көздөй түртүп жаткан атаандаштык бир топ өстү. Эгер сиз чындап эле иштеп чыгуучу болгуңуз келсе, анда сиз сыяктуу жаңы баштагандардын арасында өзгөчөлөнүү үчүн аны кадимкидей кабыл алып, кылдат даярданыңыз. Бүгүн биз эмне кылабыз, тактап айтканда, биз 250+Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-1-бөлүк суроолорду талдоону улантабыз . Мурунку макалаларда биз кенже класстын бардык суроолорун карап чыктык, бүгүн орто деңгээлдеги суроолорго жооп беребиз. Булар 100% орто деңгээлдеги суроолор эмес экенин белгилейм, бирок алардын көбү менен кенже деңгээлдеги интервьюда жолугууга болот, анткени дал ушундай интервьюларда сиздин теориялык базаңыз деталдуу изилденет, ал эми орто студент үчүн суроолор анын тажрыйбасын изилдөөгө көбүрөөк багытталган. Бирок, көпкө созулбай, баштайлы. Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-2-бөлүк

Орто

Жалпы

1. Процедуралык/функционалдык программалоо менен салыштырганда OOPтун кандай артыкчылыктары жана кемчorктери бар?

Жуиниордун суроолорун талдоодо ушул суроо бар болчу, ошого жараша мен буга чейин жооп бергем. Бул суроону жана анын жообун макаланын ушул бөлүгүндөгү 16 жана 17-суроолордон издеңиз .

2. Агрегация составдан эмнеси менен айырмаланат?

OOPде an objectилердин ортосундагы өз ара аракеттенүүнүн бир нече түрлөрү бар, алар "бар-А байланышы" деген жалпы түшүнүккө бириккен. Бул байланыш бир an objectтин башка an objectинин компоненти экендигин көрсөтөт. Ошол эле учурда бул байланыштын эки түрү бар: Композиция – бир an object башка an objectти жаратат жана башка an objectинин жашоо мөөнөтү жаратуучунун өмүрүнө көз каранды. Агрегация - an object куруу процессинде башка an objectке шилтемени (көрсөткүчтү) алат (бул учурда башка an objectинин иштөө мөөнөтү жаратуучунун өмүрүнө көз каранды эмес). Жакшыраак түшүнүү үчүн, келгиле, конкреттүү мисалды карап көрөлү. Бизде белгилүү бир унаа классы бар - Car , ал өз кезегинде типтеги ички талааларга ээ - Мотор жана жүргүнчүлөрдүн тизмеси - List<Passenger> , ошондой эле кыймылды баштоо ыкмасы бар - startMoving() :
public class Car {

 private Engine engine;
 private List<Passenger> passengers;

 public Car(final List<Passenger> passengers) {
   this.engine = new Engine();
   this.passengers = passengers;
 }

 public void addPassenger(Passenger passenger) {
   passengers.add(passenger);
 }

 public void removePassengerByIndex(Long index) {
   passengers.remove(index);
 }

 public void startMoving() {
   engine.start();
   System.out.println("Машина начала своё движение");
   for (Passenger passenger : passengers) {
     System.out.println("В машине есть пассажир - " + passenger.getName());
   }
 }
}
Бул учурда, Композиция Автоунаа менен Кыймылдаткычтын ортосундагы байланыш болуп саналат , анткени машинанын иштеши кыймылдаткыч an objectинин болушуна түздөн-түз көз каранды, анткени эгерде engine = null болсо, анда биз NullPointerException алабыз . Өз кезегинде кыймылдаткыч машинасыз жашай алbyte (эмне үчүн бизге машинасыз кыймылдаткыч керек?) жана бир убакта бир нече машинага тиешелүү боло алbyte. Бул Car an objectин жок кылсак , Engine an objectисине шилтемелер калбай турганын жана ал жакында таштанды жыйноочу тарабынан жок кылынарын билдирет . Көрүнүп тургандай, бул мамиле абдан катуу (күчтүү). Агрегация - бул Автоунаа менен Жүргүнчүнүн ортосундагы байланыш , анткени Автоунаанын иштеши Жүргүнчү түрүндөгү an objectтерге жана алардын санына эч кандай көз каранды эмес . Алар унааны таштап кете алышат - removePassengerByIndex(Long index) же жаңысын киргизе алышат - addPassenger(Passenger пассажир) , буга карабастан, унаа туура иштей берет. Өз кезегинде, Жүргүнчү an objectтери Car an objectисиз да болушу мүмкүн . Сиз түшүнгөндөй, бул биз курамында көргөндөн алда канча алсыз байланыш. Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-3-бөлүкБирок муну менен бүтпөйт, биригүү жолу менен башка an objectи менен байланышкан an object, ошондой эле ошол эле учурда башка an objectтер менен берилген байланышка ээ болушу мүмкүн. Мисалы, сиз, Java студенти катары, англис тor, OOP жана логарифмдер курстарына ошол эле учурда катталып жатасыз, бирок ошол эле учурда сиз алардын маанилүү бөлүгү эмессиз, ансыз нормалдуу иштеши мүмкүн эмес (мисалы, Мугалим).

3. Сиз иш жүзүндө кандай GoF үлгүлөрүн колдондуңуз? Мисалдар келтиргиле.

Мен буга чейин бул суроого жооп бергем, андыктан анализге шилтеме калтырам , биринчи суроону караңыз. Мен ошондой эле дизайн үлгүлөрү боюнча укмуштуудай алдамчылык баракчасын таптым , мен аны колумда сактоону сунуш кылам.

4. Прокси an objectи деген эмне? Мисалдар келтиргиле

Прокси – бул реалдуу an objectтердин ордуна атайын алмаштыруучу an objectтерди, же башкача айтканда прокси an objectтерди алмаштырууга мүмкүндүк берүүчү структуралык дизайн үлгүсү. Бул прокси an objectтери оригиналдуу an objectке чалууларды токтотуп, кандайдыр бир логиканы чалуу оригиналга өткөнгө чейин же андан кийин киргизүүгө мүмкүндүк берет . Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-4-бөлүкПрокси an objectисин колдонуу мисалдары:
  • Алыскы прокси катары - локалдык түрдө көрсөтүлүшү керек болгон алыскы an object (башка дарек мейкиндигиндеги an object) керек болгондо колдонулат. Бул учурда прокси байланышты түзүү, codeдоо, деcodeдоо ж.б. аткарат, ал эми кардар аны жергorктүү мейкиндикте жайгашкан баштапкы an object катары колдонот.

  • Виртуалдык прокси катары - ресурсту көп талап кылган an object керек болгондо колдонулат. Бул учурда, прокси an objectи иш жүзүндө али жок реалдуу an objectтин элеси сыяктуу бир нерсе катары кызмат кылат. Бул an objectке чыныгы суроо-талап (ыкма чакыруу) жөнөтүлгөндө, андан кийин гана баштапкы an object жүктөлөт жана метод аткарылат. Бул ыкма жалкоо инициализация деп да аталат, ал абдан ыңгайлуу болушу мүмкүн, анткени кээ бир учурларда баштапкы an object пайдалуу болбой калышы мүмкүн, андан кийин аны түзүү үчүн эч кандай чыгым болбойт.

  • Коопсуздук прокси катары - кардардын укуктарынын негизинде кандайдыр бир an objectке кирүүнү көзөмөлдөө керек болгондо колдонулат. Башкача айтканда, кирүү укугу жок кардар баштапкы an objectке кирүүгө аракет кылса, прокси аны кармап калат жана ага уруксат бербейт.

Виртуалдык проксидин мисалын карап көрөлү: Бизде бир нече иштеткич интерфейси бар:
public interface Processor {
 void process();
}
Аны ишке ашыруу өтө көп ресурстарды колдонот, бирок ошол эле учурда ал тиркеме ишке кирген сайын колдонулбай калышы мүмкүн:
public class HiperDifficultProcessor implements Processor {
 @Override
 public void process() {
   // некоторый сверхсложная обработка данных
 }
}
Прокси классы:
public class HiperDifficultProcessorProxy implements Processor {
private HiperDifficultProcessor processor;

 @Override
 public void process() {
   if (processor == null) {
     processor = new HiperDifficultProcessor();
   }
   processor.process();
 }
}
Келгиле, аны негизги иштетели :
Processor processor = new HiperDifficultProcessorProxy();
// тут тяжеловсеного оригинального an object, ещё не сущетсвует
// но при этом есть an object, который его представляет и у которого можно вызывать его методы
processor.process(); // лишь теперь, an object оригинал был создан
Мен көптөгөн алHowтарда проксисин колдонушат жана жаз үчүн бул негизги үлгү болуп саналат (Жаз анын ичинде жана сыртында тигилген). Бул үлгү жөнүндө бул жерден окуңуз . Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-5-бөлүк

5. Java 8де кандай жаңылыктар жарыяланды?

Java 8 алып келген инновациялар төмөнкүлөр:
  • Функционалдык интерфейстер кошулду, бул кандай жырткыч экенин бул жерден окуңуз .

  • Функционалдык интерфейстер менен тыгыз байланышта болгон Lambda туюнтмалары, алардын колдонулушу жөнүндө бул жерден көбүрөөк окуңуз .

  • Маалымат жыйнактарын ыңгайлуу иштетүү үчүн Stream API кошулду , кененирээк бул жерден окуңуз .

  • Методдорго шилтемелер кошулду .

  • forEach() ыкмасы Iterable интерфейсине кошулду .

  • Java.time пакетине жаңы дата жана убакыт API кошулду, бул жерде деталдуу талдоо .

  • Жакшыртылган Concurrent API .

  • Нөл маанилерди туура иштетүү үчүн колдонулган Кошумча орогуч классын кошуп , бул тема боюнча эң сонун макаланы бул жерден таба аласыз .

  • Интерфейстерге статикалык жана демейки ыкмаларды колдонуу мүмкүнчүлүгүн кошуу (бул, негизи, Javaны бир нече мураска жакындатат), бул жерде кененирээк маалымат .

  • Collection(removeIf(), spliterator()) классына жаңы ыкмалар кошулду .

  • Java Core үчүн кичине жакшыртуулар.

Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-6-бөлүк

6. Жогорку когезия жана төмөн бириктирүү деген эмне? Мисалдар келтиргиле.

Жогорку Когезия же Жогорку Когезия - бул белгилүү бир класста бири-бири менен тыгыз байланышта болгон жана алардын максаты үчүн бириктирилген элементтерди камтыган түшүнүк. Мисалы, User классындагы бардык ыкмалар колдонуучунун жүрүм-турумун чагылдырышы керек. Класс бири-бирине байланышпаган элементтерди камтыса, анын биримдиги төмөн болот. Мисалы, электрондук почта дарегин текшерүү ыкмасын камтыган Колдонуучу классы:
public class User {
private String name;
private String email;

 public String getName() {
   return this.name;
 }

 public void setName(final String name) {
   this.name = name;
 }

 public String getEmail() {
   return this.email;
 }

 public void setEmail(final String email) {
   this.email = email;
 }

 public boolean isValidEmail() {
   // некоторая логика валидации емейла
 }
}
Колдонуучу класс колдонуучунун электрондук почта дарегин сактоо үчүн жооптуу болушу мүмкүн, бирок аны текшерүү же электрондук кат жөнөтүү үчүн эмес. Ошондуктан, жогорку ырааттуулукка жетүү үчүн, биз валидация ыкмасын өзүнчө пайдалуу класска көчүрөбүз:
public class EmailUtil {
 public static boolean isValidEmail(String email) {
   // некоторая логика валидации емейла
 }
}
Жана биз аны зарылчылыкка жараша колдонобуз (мисалы, колдонуучуну сактап калуудан мурун). Low Coupling же Low Coupling программалык модулдардын ортосундагы төмөн көз карандылыкты сүрөттөгөн түшүнүк. Негизинен, өз ара көз карандылык - бул бирин өзгөртүү үчүн экинчисин өзгөртүү керек. Эки класстын бири-бири менен тыгыз байланышы бар болсо, анда күчтүү туташуу (же тыгыз байланыш) бар. Мисалы, бири-бирине шилтемелерди сактаган жана бири-биринин ыкмаларын чакырган эки конкреттүү класс. Эркин бириктирилген класстарды иштеп чыгуу жана сактоо оңой. Алар бири-биринен көз карандысыз болгондуктан, аларды параллелдүү иштеп чыгууга жана сынап көрүүгө болот. Мындан тышкары, алар бири-бирине таасир этпестен өзгөртүлүшү жана жаңыртылышы мүмкүн. Келгиле, күчтүү бириктирилген класстардын мисалын карап көрөлү. Бизде студенттик класс бар:
public class Student {
 private Long id;
 private String name;
 private List<Lesson> lesson;
}
Бул сабактардын тизмесин камтыйт:
public class Lesson {
 private Long id;
 private String name;
 private List<Student> students;
}
Ар бир сабакта катышуучуларга шилтеме бар. Укмуштай күчтүү кармаш, сиз ойлобойсузбу? Аны кантип азайтууга болот? Биринчиден, окуучуларда предметтердин тизмеси эмес, алардын идентификаторлорунун тизмеси болушуна ынаналы:
public class Student {
 private Long id;
 private String name;
 private List<Long> lessonIds;
}
Экинчиден, сабак классы бардык студенттер жөнүндө бorши керек эмес, ошондуктан алардын тизмесин толугу менен жок кылалы:
public class Lesson {
 private Long id;
 private String name;
}
Ошентип, бул бир топ жеңил болуп, байланыш бир топ алсыраган, сиз ойлобойсузбу? Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-7-бөлүк

OOP

7. Java'да бир нече мурасты кантип ишке ашыра аласыз?

Бир нече тукум куучулук – бул an objectке багытталган концепциянын өзгөчөлүгү, мында класс бирден ашык ата-энелик класстын касиеттерин мурастай алат. Проблема супер класста да, субкласста да бирдей кол тамгасы бар ыкмалар болгондо пайда болот. Методду чакырганда, компилятор кайсы класстын методун чакыруу керектигин аныктай алbyte, атүгүл артыкчылыктуу класс ыкмасын чакырганда да. Ошондуктан, Java бир нече мурасты колдобойт! Бирок бул жерде кандайдыр бир жылчык бар, ал жөнүндө кийинки сөз болот. Мен мурда айтылгандай, Java 8дин чыгышы менен интерфейстерге демейки ыкмаларга ээ болуу мүмкүнчүлүгү кошулду . Эгерде интерфейсти ишке ашыруучу класс бул ыкманы жокко чыгарбаса, анда бул демейки ишке ашыруу колдонулат (абстрактуу ыкманы ишке ашыруу сыяктуу демейки ыкманы жокко чыгаруунун кереги жок). Бул учурда, бир класста ар кандай интерфейстерди ишке ашырууга жана алардын демейки ыкмаларын колдонууга болот. Келгиле, бир мисал карап көрөлү. Бизде демейки fly() ыкмасы менен флайер интерфейси бар :
public interface Flyer {
 default void fly() {
   System.out.println("Я лечу!!!");
 }
}
Walker интерфейси, демейки walk() ыкмасы менен :
public interface Walker {
 default void walk() {
   System.out.println("Я хожу!!!");
 }
}
Swimmer интерфейси, swim() ыкмасы менен :
public interface Swimmer {
 default void swim() {
   System.out.println("Я плыву!!!");
 }
}
Эми мунун баарын бир өрдөк классында ишке ашыралы:
public class Duck implements Flyer, Swimmer, Walker {
}
Ал эми биздин өрдөктүн бардык ыкмаларын иштетели:
Duck donald = new Duck();
donald.walk();
donald.fly();
donald.swim();
Консолдо биз төмөнкүлөрдү алабыз:
Мен барам!!! Мен учуп жатам!!! Мен сүзүп жатам!!!
Бул бир нече мурасты туура чагылдырганыбызды билдирет, бирок бул андай эмес. Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-8-бөлүкОшондой эле, эгерде класс ушул методдордо бирдей аталыштарга жана аргументтерге ээ болгон демейки методдор менен интерфейстерди ишке ашырса, анда компилятор шайкеш келбегендигине нааразы боло баштайт, анткени ал чынында кайсы методду колдонуу керектигин түшүнбөйт. чыгуунун бир нече жолдору бар:
  • Интерфейстеги методдорду бири-биринен айырмаланып тургандай кылып өзгөртүңүз.
  • Ишке ашыруу классында мындай талаштуу ыкмаларды жокко чыгарыңыз.
  • Бул талаштуу ыкмаларды ишке ашырган класстан мураска алыңыз (анда сиздин классыңыз аны ишке ашырууну так колдонот).

8. Final, final жана finalize() методдорунун ортосунда кандай айырма бар?

Final - класска, ыкмага же өзгөрмөгө чектөө коюу үчүн колдонулган ачкыч сөз, чектөө мааниси:
  • Өзгөрмө үчүн - инициализациялангандан кийин өзгөрмө кайра аныкталbyte.
  • Метод үчүн подкласста (мураскор класста) методду жокко чыгарууга болбойт.
  • Класс үчүн - классты мурастоого болбойт.
акырында бул code блогунун алдындагы ачкыч сөз, өзгөчө учурларды иштетүүдө, try блогу менен бирге жана catch блогу менен бирге (же алмаштырылышы мүмкүн). Бул блоктогу code кандайдыр бир өзгөчөлүк ыргытылганбы же жокпу, карабастан аткарылат. Макаланын бул бөлүгүндө , 104-суроодо, бул блок аткарылбай турган өзгөчө кырдаалдар талкууланат. finalize() - бул Object классынын ыкмасы , ар бир an object таштанды жыйноочу тарабынан жок кылынганга чейин чакырылат, бул ыкма (акыркы) деп аталат жана ээлеген ресурстарды тазалоо үчүн колдонулат. Ар бир an object мураска алган Object классынын ыкмалары жөнүндө көбүрөөк маалымат алуу үчүн макаланын ушул бөлүгүндөгү 11-суроону караңыз. Ооба, бүгүн биз ушуну менен бүтөбүз. Кийинки бөлүмдө көрүшкөнчө! Java иштеп чыгуучусу үчүн интервьюдан алынган суроолордун жана жооптордун анализи.  14-9-бөлүк
Сериядагы башка материалдар:
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION