Пользователь Константин
Константин
36 уровень
Одесса

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

Статья из группы Random
Hello, hello! Сегодня Java-разработчики очень востребованы. Обеспечить вакансией я вас, конечно, не могу, но немного помочь в том, чтобы вы обрели новые знания и закрыли некоторые пробелы, попытаюсь. Так что продолжаем разбор 250+ вопросов с собеседований на Java-разработчика. Ссылки на предыдущие части разбора — в конце статьи.Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 1

39. Что такое модификаторы доступа в Java? Назовите их. Для чего они используются?

Ранее я уже описывал модификаторы доступа в вопросе об элементах Java, отвечающих за инкапсуляцию. Но все же напомню. Модификаторы доступа в Java — это ключевые слова, которые описывают предоставляемый уровень доступа к определенному компоненту Java. Модификаторы доступа могут быть:
  • public — элемент с данным модификатором будет общедоступным. Т.е. поля и методы, классы, объявленные с модификатором public, видны другим классам как из текущего пакета, так и из внешних пакетов;
  • protected — элемент с данным модификатором будет доступен из любого места в текущем классе текущего пакета или в классах-наследниках, даже если они находятся в других пакетах;
  • default, или отсутствующий модификатор — данный модификатор используется неявно, когда модификатор доступа не указывается вовсе. Он похож на предыдущий, кроме допустимости видимости в классах-наследниках, которые находятся в других пакетах;
  • private — самый закрытый из всех модификаторов, который допускает доступ к элементу только в пределах текущего класса.
Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 2

40. Назовите основную особенность статических и переменных методов

Весьма странная формулировка — “переменные методы”. Наверняка здесь имеются в виду обычные, нестатические методы. Так вот, основная разница в том, что статические методы принадлежат классу и, собственно, для них не нужно создавать экземпляр данного класса: его можно вызывать лишь используя тип класса. Например, у нас есть статический метод, чтобы погладить кота:

public class CatService {
   public static void petTheCat(Cat cat) {
       System.out.println("Погладить кота - " + cat.getName());
   }
Для его вызова нам не нужен экземпляр класса CatService:

Cat cat = new Cat(7, "Bobi");
CatService.petTheCat(cat);
В то время как обычные методы привязаны (принадлежат) объекту, и чтобы их вызвать, необходимо иметь экземпляр (объект), у которого и будет вызван метод. Например, у кота есть нестатический метод — мяукать:

class Cat {
   public void mew() {
       System.out.println("Meow! Meow! Meow!");
   }
Для вызова этого метода нам понадобится конкретный экземпляр кота:

Cat cat = new Cat(7, "Bobi");
cat.mew();

41. Какие основные ограничения действуют на статические и “переменные” методы?

Как я и сказал ранее, основное ограничение обычного метода в том, что всегда должен быть некоторый экземпляр, у которого данный метод будет вызываться. А вот статический метод этого не требует, но он и не может ссылаться на ссылку this — на элементы текущего объекта — поскольку текущего объекта для него не существует.

42. Что значит ключевое слово static? Может ли статический метод быть переопределен или перегружен?

Элемент, обозначенный ключевым словом static, принадлежит не объекту класса, а именно классу, и он загружается при загрузке самого класса. Статические элементы — единственные на всю программу, а обычные — единственные на конкретный объект. Статическими могут быть:
  • поля класса;
  • блок инициализации класса;
  • метод класса;
  • внутренние классы класса (однако, та ещё тавтология).
Статический метод нельзя переопределить: он принадлежит классу и не наследуется, но в то же время его можно перегрузить.

43. Может ли метод быть статическим и абстрактным одновременно?

В предыдущей статье я это уже упоминал: метод не может быть абстрактным и статическим одновременно. Абстрактность метода подразумевает, что он должен быть переопределен в наследнике. В то же время статический метод принадлежит классу, и его нельзя переопределить: это вызовет противоречие, которое увидит компилятор и начнет ругаться. Если у вас возникла такая ситуация, стоит всерьёз задуматься о правильности построения архитектуры вашего приложения (ведь с ней явно что-то не так).Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 3

44. Можно ли использовать статические методы в середине обычных? Наоборот? Почему?

Статические методы можно использовать в обычных, так как этому ничего не препятствует. В то же время обратная ситуация невозможна: статический метод не может использовать обычный метод, не имея ссылки на конкретный экземпляр данного класса. А как мы помним, для статических членов класса ссылка this недоступна: конкретных объектов класса может быть сколько угодно, и у каждого из них внутри будет ссылка на самого себя — this. И как тогда понять, какую именно ссылку this нужно взять? А никак. Поэтому и статические элементы не могут ссылаться на нестатические, без ссылки на конкретный объект. Собственно, статический метод может использовать не статический, только если имеет ссылку на конкретный объект. Например ту, которая пришла в качестве аргумента:

public static void petTheCat(Cat cat) {
   System.out.println("Погладить кота - " + cat.getName());
}
Тут мы видим, что в статическом методе petTheCat вызывается обычный, нестатический метод объекта CatgetName.

45. Что такое interface? Может ли быть final interface?

Как мы помним, в Java нет множественного наследования. Интерфейсы — это что-то вроде его альтернативы. Интерфейс похож на очень урезанный класс. Они определяют функционал без конкретной реализации, который реализуют классы, имплементирующие (реализующие) эти интерфейсы. Пример интерфейса:

public interface Animal {
    void voice();
}
Пример реализации интерфейса классом:

class Cat implements Animal {
 
   @Override
   public void voice() {
       System.out.println("Meow! Meow! Meow!");
   }
}
Главное, что нужно знать об использовании интерфейсов:
  1. Методы интерфейса должны содержать только заголовок, без конкретного тела метода, т.е. должны быть абстрактными (но без применения ключевого слова abstract). Исключение из этого — статические и дефолтные методы, для которых необходимо иметь тело метода.
  2. Класс может реализовывать множество интерфейсов (как и говорил, это альтернатива множественному наследованию), которые прописываются через запятую: class Lion implements Animal, Wild.
  3. Интерфейсы создаются при помощи ключевого слова — interface.
  4. При реализации интерфейса классом используется ключевое слово — implements.
  5. Класс, который реализует определенный интерфейс, обязан реализовать все его абстрактные методы, либо должен объявить себя абстрактным.
  6. Основная цель использования интерфейсов — реализация полиморфизма (способность объектов принимать множество форм).
  7. В интерфейсе, как правило, не пишут модификаторы доступа для методов: они по умолчанию public, и другие модификаторы, отличные от public, задавать нельзя. Начиная с Java 9 можно использовать private модификаторы для методов.
  8. Переменные интерфейсов по умолчанию static final, иначе говоря — константы: их всегда нужно проинициализировать непосредственно в интерфейсе.
  9. Нельзя создать объект интерфейса.
Ответ на вопрос, могут ли быть интерфейсы финальными — конечно же, нет. Ведь сама суть интерфейсов в том, чтобы их реализовывали. А как мы все прекрасно помним, final на уровне класса делает его не наследуемым, и в случае с интерфейсом — не реализуемым. А зачем нам интерфейс, который нельзя реализовать и использовать? Верно — незачем! И компилятор так считает))Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 4Смысл разве что появился с введением статических методов в интерфейсы с Java 8, но это не изменило того факта, что интерфейс не может быть финальным. Про интерфейсы я рассказал, очень поверхностно, т.к. это обширная тема. Подробнее об этом — в статьях об интерфейсах в Java и разнице между абстрактными классами и интерфейсами.

46. Где можно инициализировать статические поля?

Статические поля можно инициализировать:
  • непосредственно при объявлении, через знак равенства =;
  • в статическом блоке инициализации;
  • в нестатическом блоке инициализации, но при этом вы должны понимать что при каждом создании объекта данное поле будет перезаписываться этим блоком инициализации;
  • в конструкторе класса. При каждом вызове данного конструктора (т.е. при создании объекта через этот конструктор) данное поле будет перезаписываться;
  • в статических методах;
  • в нестатических методах;
  • во внутренних статических и нестатических, локальных и анонимных классах.

47. Что такое анонимные классы?

Анонимные классы — это классы, у которых нет собственного типа. О чем это я? Когда мы говорили об интерфейсах, я упомянул, что нельзя создать объект интерфейса: можно лишь создать объект класса, который реализует интерфейс. А что если вы не хотите реализовывать интерфейс в каком-то классе, но при этом вам нужен объект типа интерфейса? И скорее всего, это будет единичный случай использования данного объекта. И у вас нет нужды создавать полноценный класс реализацию. Как вы это сделаете? Правильно! Через анонимный класс!Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 5Предположим, у нас есть некоторый интерфейс Animal:

public final interface Animal {
   public void voice();
}
Если мы хотим создать экземпляр данного интерфейса через анонимный класс:

Animal cat = new Animal() {
   @Override
   public void voice() {
       System.out.println("Meow! Meow! Meow!");
   }
};
И далее вы можете спокойной использовать данный объект и его реализованный метод — voice. То есть анонимный класс реализует данный интерфейс и все его абстрактные методы прямо здесь и сейчас. Иначе нам не создать объект интерфейса/абстрактного класса, так как присутствуют не реализованные/абстрактные методы. Как я упомянул, анонимные классы используются не только для реализации абстрактных методов интерфейса, но и для реализации абстрактных методов абстрактного класса. Данный подход хорош для ситуаций, когда объект используется разово или данная реализация методов нужна только единожды, и нет нужды создавать отдельный класс, который будет реализовывать необходимый абстрактный класс/интерфейс. Но также отмечу, что использование анонимных классов — редкое явление в работе: как правило предпочтение все же отдается обычным классам. Подробнее об анонимных классах можно почитать вот в этой статье.

48. Что такое примитивные классы?

Как по мне, это весьма странный вопрос и, возможно, это такой вопрос-ловушка, ведь в Java нет такого понятия как примитивные классы: разве что есть понятие примитивные типы, которое мы уже рассматривали ранее. Как мы помним, в Java есть 8 примитивных типов — byte, short, int, long, float, double, char, boolean.Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 6

49. Что такое класс «обертка» (wrapper)?

Главная проблема использования примитивных типов в Java — это то, что они все же не классы, а Java — всё же ООП язык. То есть программы, написанные на этом языке, сводятся к взаимодействию между объектами. Ну а примитивы — это не объекты. У них нет методов, даже стандартных от класса Object. Ну а если нам понадобилось использовать примитив как ключ в Map? Тогда у него нужно вызвать метод hashCode. Также там можно вызвать метод equals. Что тогда? Моментов, где должен быть именно класс, а не примитив, может быть очень и очень много, что делает примитивы неиспользуемыми и нежелательными элементами в программе, ведь это рушит саму идею ООП. Но не всё так плохо, как кажется. Ведь в Java есть понятие обертки примитивов. У каждого примитивного типа есть класс-аналог:
  • byte -> Byte.class
  • short -> Short.class
  • int -> Integer.class
  • long -> Long.class
  • float -> Float.class
  • double -> Double.class
  • char -> Character.class
  • boolean -> Boolean.class
Это представление простых типов, но в виде полноценных классов с кучей разнообразных и функциональных методов. Для удобного использования этих классов ввели понятия autoboxing и unboxing. Autoboxing — автоматическое преобразование примитивного типа в класс-аналог при надобности (например, int в Integer). Unboxing — процесс, обратный предыдущему: автоматическое преобразование класса-обертки примитива к примитивному типу (например, Integer к int). Благодаря введению классов-оберток примитивов и процессов autoboxing-а и unboxing-а, примитивные типы смогли стать полноценными членами ООП языка — Java.Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 7Чтобы ознакомиться с этой темой подробнее, настойчиво рекомендую почитать вот эту статью.

50. Что такое Nested class? Когда он используется?

Nested class — внутренний класс, который является членом другого класса. В Java существует 4 вида таких внутренних классов: 1. Внутренний класс Данный вид классов объявляется непосредственно в теле другого класса. Вложенный внутренний класс может получить доступ к любому приватному полю или методу экземпляра внешнего класса. В качестве примера, создадим зоопарк, в котором у нас будет животное — зебра:

public class Zoo {
   class Zebra {
       public void toFeed(String food) {
           System.out.println("Дать зебре - " + food);
       }
   }
}
Ничего сложного, не так ли? Давайте взглянем на пример создания объекта внутреннего класса:

Zoo.Zebra zebra = new Zoo().new Zebra();
zebra.toFeed("яблоко");
Как вы уже увидели, обязательно нужно создавать объект обрамляющего класса, на основе ссылки которого можно создать объект внутреннего класса. Также хотелось бы отметить, что вложенный внутренний класс не может иметь в себе статических методов или статических полей. Именно потому, что внутренний класс неявно связан с объектом своего внешнего класса, и он не может объявлять никаких статических методов внутри себя. 2. Статические вложенные классы Данный класс схож с предыдущим, только у него модификатор доступа static возле объявления класса. Так как у этого вида классов нет доступа к не статическим полям внешнего класса, он больше похож на статическую часть внешнего класса, чем на внутренний класс. При этом у данных класса есть доступ ко всем статическим членам внешнего класса, даже к приватным. Пример статического вложенного класса:

public class Zoo {
   static class Zebra {
       public void toFeed(String food) {
           System.out.println("Дать зебре - " + food);
       }
   }
}
Способ создания немного отличается от предыдущего:

Zoo.Zebra zebra = new Zoo.Zebra();
zebra.toFeed("яблоко");
Тут нам не нужен объект внешнего класса для создания объекта вложенного статического класса. От внешнего класса нам нужен только его тип, чтобы можно было найти расположение вложенного класса. 3. Локальные классы Локальные классы — это классы, объявленные внутри тела метода, при этом создание и использование объекта локального класса возможно исключительно в пределах этого метода. Пример:

public class Zoo {
   public void toFeed(String animal, String food) {
       switch(animal){
           case "зебра":
               class Zebra {
                   void toFeedZebra(String food) {
                       System.out.println("Дать зебре - " + food);
                   }
               }
               Zebra zebra = new Zebra();
               zebra.toFeedZebra(food);
               ...
Пример использования:

Zoo zoo = new Zoo();
zoo.toFeed("зебра", "яблоко");
Не видя код метода toFeed, вы бы и не заподозрили о существовании локального класса, не так ли? Локальный класс не может быть static или transient, но его можно пометить как abstract или final (только ИЛИ, т.к. использование этих двух модификаторов приведет к конфликту). 4. Анонимные классы Про анонимные классы мы уже говорили выше, и как вы помните, их можно создать из двух источников — интерфейсы и классы. Причины использования Внутренние статические и не статические классы используют потому, что иногда лучше встроить небольшие классы в более общие и хранить их вместе: так у них будет более высокая связанность и общая цель. Собственно, использование вложенных классов увеличивает инкапсуляцию кода. Причиной выбора локальных классов может послужить то, что данный класс используется исключительно в пределах одного метода. Нужно ли в таком случае размазывать код по приложению? Нет. Но при этом добавлю, что в своей практике я ни разу не видел использование локальных классов, т.к. потребность в них весьма спорная. Ну а причиной использования анонимных классов может быть то, что конкретная реализация интерфейса или абстрактного класса будет необходима лишь единожды, поэтому нет нужды создавать под это отдельный, полноценный класс с реализацией. Взамен — по-простому — реализовали нужный нам метод(ы) через анонимный класс, использовали этот объект и забыли о нем (ну а Garbage collector о нем вспомнил).Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 8Изучить внутренние классы подробнее вам помогут эта и эта статьи.

51. Какие модификаторы доступа могут быть у класса?

Как мы помним, существуют разные виды классов и для них применимы разные модификаторы доступа:
  • внешний класс может иметь модификатор доступа public или быть без модификатора (модификатор по умолчанию);
  • внутренний класс поддерживает все 4 модификатора доступа;
  • вложенный статический класс поддерживает все модификаторы доступа, кроме protected, т.к. данный модификатор подразумевает наследование, что противоречит статическому члену класса (статические элементы не наследуются);
  • локальный класс может быть только с модификатором по умолчанию (т.е. без модификатора вовсе);
  • анонимный класс: отсутствует объявление типа класса, то и модификаторы доступа отсутствуют вовсе.
На этом мы сегодня и сделаем остановочку. See you soon!Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 9Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 5 - 10
Другие материалы серии:
Комментарии (3)
Чтобы просмотреть все комментарии или оставить свой,
перейдите в полную версию
Илья 29 уровень, Дзержинск
11 апреля 2021
И вновь благодарю за статью! Всё кратко и по делу)
Николай 41 уровень, Москва
6 апреля 2021
Хотел бы вставить свои пять копеек.

Предположим, у нас есть некоторый интерфейс Animal:
 
public final interface Animal {
   public void voice();
}
Интерфейс не может быть "final", чуть выше об этом говориться. А так очень даже полезная и познавательная статья. Спасибо!
Justinian 41 уровень, Mega City One Master
6 апреля 2021
Хороший цикл статей, с удовольствием читаю, но надеюсь автор простит за небольшие уточнения.

Весьма странная формулировка — “переменные методы”.
В статье, ссылка на которую прилагается (250 вопросов) - вопрос сформулирован так:

Назовите основную особенность статических переменных и методов.
Видно буква И мигрировала при транспортировке и внесла легкий хаос :) Тоже самое касается и

 Какие основные ограничения действуют на статические и “переменные” методы?
буква И снова убежала не туда, в оригинале вопрос звучит как

 Какие основные ограничения действуют на статические переменные и методы?
А вот в другом вопросе про примитивные классы и правда с вопросом беда.

Как мы помним, в Java нет множественного наследования.
В Джава есть множественное наследование, об этом прямо пишут и Хорстманн и ко (которые кстати продолжают активную работу над jdk) и в принципе это общепринятая сообществом позиция. В джаве нету множественного наследования классов, вот здесь да.

Nested class — внутренний класс, который является членом другого класса. В Java существует 4 вида таких внутренних классов:
Nested class это вложенный класс. Inner class это внутренний класс Их часто путают в литературе, но иерархию и терминологический аппарат задает JLS, она в этом вопросе однозначна. Иерархия на картинке: nested classes То есть внутренний класс (inner class) это нестатический вложенный класс. Статических внутренних классов в джава не существует. Какую-то логику искать сложно, так как nested и inner синонимы, просто запомнить.