JavaRush /Java Blog /Random-TL /Pagsusuri ng mga tanong at sagot mula sa mga panayam para...

Pagsusuri ng mga tanong at sagot mula sa mga panayam para sa developer ng Java. Bahagi 15

Nai-publish sa grupo
Hi Hi! Magkano ang kailangang malaman ng isang developer ng Java? Maaari kang magtaltalan ng mahabang panahon sa isyung ito, ngunit ang katotohanan ay na sa panayam ikaw ay hinihimok sa sagad sa pamamagitan ng teorya. Kahit na sa mga lugar ng kaalaman na hindi ka magkakaroon ng pagkakataong gamitin sa iyong trabaho. Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 15 - 1Well, kung ikaw ay isang baguhan, ang iyong teoretikal na kaalaman ay sineseryoso. Dahil wala pang karanasan at magagandang tagumpay, ang natitira na lang ay suriin ang lakas ng base ng kaalaman. Ngayon ay patuloy naming palalakasin ang mismong base na ito sa pamamagitan ng pagsusuri sa pinakasikat na mga tanong sa panayam para sa mga developer ng Java. Lumipad tayo!

Java Core

9. Ano ang pagkakaiba sa pagitan ng static at dynamic na binding sa Java?

Nasagot ko na ang tanong na ito sa artikulong ito sa tanong 18 tungkol sa static at dynamic na polymorphism, ipinapayo ko sa iyo na basahin ito.

10. Posible bang gumamit ng pribado o protektadong mga variable sa isang interface?

Hindi hindi mo kaya. Dahil kapag nagdeklara ka ng interface, awtomatikong idinaragdag ng Java compiler ang pampubliko at abstract na mga keyword bago ang mga pamamaraan ng interface at ang pampublikong , static at huling mga keyword bago ang mga miyembro ng data. Sa totoo lang, kung magdaragdag ka ng pribado o protektado , may lalabas na salungatan, at magrereklamo ang compiler tungkol sa access modifier na may mensaheng: "Hindi pinapayagan dito ang modifier '<selected modifier>'." Bakit nagdaragdag ang compiler ng public , static at final mga variable sa interface? Alamin natin ito:
  • pampubliko - pinapayagan ng interface ang kliyente na makipag-ugnayan sa bagay. Kung ang mga variable ay hindi pampubliko, ang mga kliyente ay walang access sa kanila.
  • static - hindi malikha ang mga interface (o sa halip, ang kanilang mga bagay), kaya static ang variable.
  • pangwakas - dahil ang interface ay ginagamit upang makamit ang 100% abstraction, ang variable ay may panghuling anyo nito (at hindi mababago).

11. Ano ang Classloader at para saan ito ginagamit?

Classloader - o Class Loader - nagbibigay ng paglo-load ng mga klase ng Java. Mas tiyak, ang paglo-load ay sinisiguro ng mga inapo nito - mga partikular na loader ng klase, dahil Ang ClassLoader mismo ay abstract. Sa tuwing maglo-load ang isang .class na file, halimbawa, pagkatapos tumawag ng constructor o static na paraan ng kaukulang klase, ang aksyon na ito ay ginagawa ng isa sa mga inapo ng ClassLoader class . May tatlong uri ng tagapagmana:
  1. Bootstrap ClassLoader — базовый загрузчик, реализован на уровне JVM и не имеет обратной связи со средой выполнения, так How является частью ядра JVM и написан в машинном codeе. Данный загрузчик служит родительским элементом для всех других экземпляров ClassLoader.

    В основном отвечает за загрузку внутренних классов JDK, обычно rt.jar и других основных библиотек, расположенных в каталоге $ JAVA_HOME / jre / lib. У разных платформ могут быть разные реализации этого загрузчика классов.

  2. Extension Classloader — загрузчик расширений, потомок класса базового загрузчика. Заботится о загрузке расширения стандартных базовых классов Java. Загружается из каталога расширений JDK, обычно — $ JAVA_HOME / lib / ext or любого другого каталога, упомянутого в системном свойстве java.ext.dirs (с помощью данной опции можно управлять загрузкой расширений).

  3. System ClassLoader — системный загрузчик, реализованный на уровне JRE, который заботится о загрузке всех классов уровня applications в JVM. Он загружает файлы, найденные в переменном окружении классов -classpath or -cp опции командной строки.

Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 15 - 2Загрузчики классов — это часть среды выполнения Java. В тот момент когда JVM запрашивает класс, загрузчик классов пытается найти класс и загрузить определение класса в среду выполнения, используя полное Name класса. Метод java.lang.ClassLoader.loadClass() отвечает за загрузку определения класса во время выполнения. Он пытается загрузить класс на основе полного имени. Если класс еще не загружен, он делегирует request загрузчику родительского класса. Этот процесс происходит рекурсивно выглядит так:
  1. System Classloader пытается найти класс в своем кеше.

    • 1.1. Если класс найден, загрузка успешно завершена.

    • 1.2. Если класс не найден, загрузка делегируется к Extension Classloader-у.

  2. Extension Classloader пытается найти класс в собственном кеше.

    • 2.1. Если класс найден — успешно завершена.

    • 2.2. Если класс не найден, загрузка делегируется Bootstrap Classloader-у.

  3. Bootstrap Classloader пытается найти класс в собственном кеше.

    • 3.1. Если класс найден, загрузка успешно завершена.

    • 3.2. Если класс не найден, базовый Bootstrap Classloader попытается его загрузить.

  4. Если загрузка:

    • 4.1. Прошла успешно — загрузка класса завершена.

    • 4.2. Не прошла успешно — управление передается к Extension Classloader.

  5. 5. Extension Classloader пытается загрузить класс, и если загрузка:

    • 5.1. Прошла успешно — загрузка класса завершена.

    • 5.2. Не прошла успешно — управление передается к System Classloader.

  6. 6. System Classloader пытается загрузить класс, и если загрузка:

    • 6.1. Прошла успешно — загрузка класса завершена.

    • 6.2. Не прошла успешно — генерируется исключение — ClassNotFoundException.

Тема загрузчиков классов обширна и ею не стоит пренебрегать. Whatбы ознакомиться с ней подробнее, советую прочесть эту статью, а мы не будем задерживаться и пойдем дальше.

12. What такое Run-Time Data Areas?

Run-Time Data Ares — области данных среды выполнения JVM. JVM определяет некоторые области данных времени выполнения, необходимые во время выполнения программы. Одни из них создаются при запуске JVM. Другие являются локальными по отношению к потокам и создаются только при создании потока (и уничтожаются, когда поток уничтожается). Области данных среды выполнения JVM выглядят так: Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 15 - 3
  • PC Register — регистр ПК — локален для каждого потока и содержит address инструкции JVM, которую поток выполняет в данный момент.

  • JVM Stack — область памяти, которая используется How хранorще для локальных переменных и временных результатов. У каждого потока есть свой отдельный стек: How только поток завершается, этот стек также уничтожается. Стоит отметить, что преимуществом stack над heap является производительность, в то время How heap безусловно имеет преимущество в масштабе хранorща.

  • Native Method Stack — область данных для каждого потока, в которой хранятся элементы данных, аналогичные стеку JVM, для выполнения собственных (не Java) методов.

  • Heap — используется всеми потоками How хранorще которое содержит an objectы, метаданные классов, массивы и т. д., которые создаются во время выполнения. Данная область создается при запуске JVM и уничтожается при завершении ее работы.

  • Method area — область метода — эта область времени выполнения общая для всех потоков и создается при запуске JVM. Он хранит структуры для каждого класса, такие How пул констант (Runtime Constant Pool — пул для хранения констант), code для конструкторов и методов, данные метода и т. д.

13. What такое immutable object?

В данной части статьи в 14 и 15 вопросе уже есть ответ на этот вопрос, поэтому ознакамливаетесь не теряя времени зря.

14. В чем особенность класса String?

Ранее в разборе мы неоднократно говорor про те or иные особенности String (для этого был отдельный раздел). Now же подведем итог по особенностям String:
  1. Это самый популярный an object в Java, который применяют для разнообразных целей. По частоте использования он не уступает даже примитивным типам.

  2. Объект данного класса можно создать без использования ключевого слова new — непосредственно через кавычки String str = “строка”;.

  3. String — это immutable класс: при создании an object данного класса его данные нельзя изменить (когда вы к некоторой строке добавляете + “другую строку”, How результат вы получите новую, третью строку). Неизменность класса String делает его потокобезопасным.

  4. Класс String финализирован (имеет модификатор final), поэтому его наследование невозможно.

  5. У String есть свой пул строк, область памяти в heap, которая кеширует создаваемые строковые значения. В этой части серии, в 62 вопросе, я описывал строковой пул.

  6. В Java присутствуют аналоги String, также предназначенные для работы с строками — StringBuilder и StringBuffer, но с тем отличием, что они изменяемые. Подробнее о них вы можете почитать в этой статье.

Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 15 - 4

15. What такое ковариантность типов?

Для понимания ковариантности мы рассмотрим пример. Предположим, у нас есть класс животного:
public class Animal {
 void voice() {
   System.out.println("*тишина*");
 }
}
И некоторый расширяющий его класс Dog:
public class Dog extends Animal {

 @Override
 public void voice() {
   System.out.println("Гав, гав, гав!!!");
 }
}
Как мы помним, родительскому типу мы можем без проблем присваивать an objectы типа наследника:
Animal animal = new Dog();
Это у нас будет ничто иное How полиморфизм. Удобно, гибко не так ли? Ну а в случае со списком животных? Сможем ли мы задать списку с дженериком Animal список с an objectми Dog?
List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs;
В таком случае строка присвоения списку животных списка собак будет подчеркнута красным, т.е. компилятор не пропустит данный code. Несмотря на то, что вроде How это присваивание весьма логично (ведь переменной типа Animal мы можем присвоить an object Dog) его сделать нельзя. Это происходит потому, что если бы это было допустимо, в список, который изначально предназначен для Dog, мы сможем положить an object Animal, при этом думая, что в списке у нас только Dogs. И потом, к примеру, возьмём с помощью метода get() an object у того списка dogs, думая, что это собака, и вызовем у него некоторый метод an object Dog, которого нет у Animal. И How вы понимаете, это невозможно — упадет ошибка. Но, к счастью, компилятор не пропускает данную логическую ошибку с присвоением списка потомков, списку родителей (и наоборот). В Java возможно присвоение an objectов списков лишь переменным списков с совпадающими дженериками. Это и называется инвариацией. Если бы могли это сделать, это называлось бы и называлось ковариацией. То есть, ковариация — это если бы мы могли переменной типа List<Animal> задать an object типа ArrayList<Dog>. Получается что в Java ковариантность не поддерживается? Как бы не так! Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 15 - 5Но это делается своим, особым путем. Для этого используется конструкция ? extends Animal. Она ставится дженериком переменной, которой мы хотим задать an object списка, с дженериком потомка. Эта конструкция дженерика значит, что подойдёт любой тип, который является потомком типа Animal (и тип Animal также попадает под это обобщение). В свою очередь, Animal может быть не только классом, но и интерфейсом (и пусть вас не вводит в заблуждение ключевое слово extends). Наше предыдущее присваивание мы можем выполнить следующим образом:
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
В результате вы увидите в IDE, что компилятор не будет ругаться на данную конструкцию. Давайте проверим работоспособность данной конструкции. Предположим, у нас есть метод, который заставляет всех переданных ему животных издать звуки:
public static void animalsVoice(List<? extends Animal> animals) {
 for (Animal animal : animals) {
   animal.voice();
 }
}
Передадим ему список с собаками:
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
animalsVoice(dogs);
В консоли мы увидим следующий вывод:
Гав, гав, гав!!! Гав, гав, гав!!! Гав, гав, гав!!!
А значит данный подход к ковариантности успешно работает. Отмечу, что в список с данным дженериком ? extends Animal мы не можем вставить новые данные ниHowого типа: ни типа Dog, ни даже типа Animal:
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
animals.add(new Dog());
dogs.add(new Animal());
Собственно, в последних двух строках компилятор будет подчеркивать красным вставку an objectов. Это связано с тем, что мы не можем быть на сто процентов уверены, список с an objectми Howого типа будет присвоен списку с данных дженериком <? extends Animal>. Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 15 - 6Хотелось бы ещё рассказать про контравариантность, так How обычно это понятие идет всегда вместе с ковариантностью, и How правило спрашивают о них вместе. Это понятие — некоторая противоположность ковариантности, так How для данной конструкции используется тип наследника. Предположим, нам нужен список, которому можно будет присвоить список с типом an objectов, не являющихся предками an object Dog. При этом мы заранее не знаем, что это будут за конкретные типы. В таком случае нас может выручить конструкция вида ? super Dog, для которой подходят все типы — прародители класса Dog:
List<Animal> animals = new ArrayList<>();
List<? super Dog> dogs = animals;
dogs.add(new Dog());
dogs.add(new Dog());
Мы можем смело добавлять в список с таким дженериком an objectы типа Dog, ведь у него в любом случае присутствуют все реализованные методы любого его прародителя. Но мы не сможем добавить an object типа Animal, так How нет уверенности, что внутри будут именно an objectы этого типа, а не, например, Dog. Ведь мы можем requestить у element данного списка метод класса Dog, которого не будет в наличии у Animal. В таком случае возникнет ошибка компиляции. Также, если бы мы захотели реализовать предыдущий метод, но уже с данным дженериком:
public static void animalsVoice(List<? super Dog> dogs) {
 for (Dog dog : dogs) {
   dog.voice();
 }
}
мы бы получor ошибку компиляции в цикле for, так How мы не можем быть уверены, что пришедший список содержит an objectы типа Dog и свободно использовать его методы. Если у данного списка мы вызовем метод dogs.get(0); — мы получим an object типа Object. То есть для работы метода animalsVoice() нам How минимум нужно добавить небольшие манипуляции с сужением данных вида:
public static void animalsVoice(List<? super Dog> dogs) {
 for (Object obj : dogs) {
   if (obj instanceof Dog) {
     Dog dog = (Dog) obj;
     dog.voice();
   }
 }
}
Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 15 - 7

16. Как есть методы в классе Object?

В данной части серии, в 11 пункте, я уже ответил на данный вопрос, поэтому настоятельно советую ознакомиться, если вы до сих пор этого не сделали. На этом на сегодня и закончим. До встречи в следующей части! Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 15 - 8
Другие материалы серии:
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION