ООП в Java Flashcards

1
Q

Какие виды классов есть в java?

A
Top level class (Обычный класс): 
-Abstract class (Абстрактный класс); 
-Final class (Финализированный класс). Interfaces (Интерфейс).
Enum (Перечисление).
Nested class (Вложенный класс):
-Static nested class (Статический вложенный класс); 
-Member inner class (Простой внутренний класс); 
-Local inner class (Локальный класс);
-Anonymous inner class (Анонимный класс).
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Расскажите про вложенные классы. В каких случаях они применяются?

A

Класс называется вложенным (nested), если он определен внутри другого класса.
Вложенный класс создается для того, чтобы обслуживать окружающий его класс.
Это пример композиции. Внутренний класс это часть целого класса.
Вложенные классы - по сути, это более подробное описание каких-то деталей нашего внешнего класса.
Если класс полезен только для одного другого класса, то вполне логично встроить его в этот класс и хранить их вместе.
Использование вложенных классов увеличивает инкапсуляцию.
Вложенные классы применяются в тех случаях, когда нужно написать небольшой вспомогательный код для другого класса.
Вложенный класс создают также, чтобы скрыть его переменные и методы от внешнего мира.
Внутренние классы также есть смысл использовать, если предполагается, что они будут использовать элементы родителя, чтобы не передавать лишнего в конструкторах.

Особенности нестатических вложенных классов Java:
- Они существуют только у объектов, потому для их создания нужен объект.
- Внутри Java класса не может быть статических переменных. Если вам нужны какие-то константы или что-либо еще статическое, выносить их нужно во внешний класс. Это связано с тесной связью нестатического вложенного класса с внешним классом.
- У класса полный доступ ко всем приватным полям внешнего класса. Данная особенность работает в две стороны.
- Можно получить ссылку на экземпляр внешнего класса.
Статические классы внутри внешнего класса:

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

Статические классы используются для того, чтобы укомплектовать связанные классы рядом, чтобы с логической структурой было работать проще.

Количество классов уменьшилось.

Все классы внутри их класса-родителя.

https://javarush.ru/groups/posts/2181-vlozhennihe-vnutrennie-klassih

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Что такое «локальный класс»? Каковы его особенности?

A

Данные классы объявляются внутри других методов. По сути, они обладают всеми свойствами нестатического вложенного класса, только создавать их экземпляры можно только в методе, при чем метод не может быть статическим (для их создания нужен экземпляр внешнего класса, в нестатические методы неявно передается ссылка на экземпляр вызывающего объекта, а в статическом методе данной ссылки нет).

  • Локальные классы способны работать только с final переменными метода. Все дело в том, что экземпляры локальных классов способны сохраняться в «куче» после завершения работы метода, а переменная может быть стёрта. Если же переменная объявлена final, то компилятор может сохранить копию переменной для дальнейшего использования объектом. И еще: с 8+ версий Java можно использовать не final переменные в локальных классах, но только при условии, что они не будут изменяться.
  • Локальные классы нельзя объявлять с модификаторами доступа.
  • Локальные классы обладают доступом к переменным метода.

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

https://javarush.ru/groups/posts/2190-vnutrennie-klassih-v-lokaljhnom-metode

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Что такое «анонимные классы»? Где они применяются?

A

Анонимные классы – просто обычные нестатические вложенные классы. Их особенность в удобстве их использования. Можно написать свой класс прямо при создании экземпляра другого класса.

Мы просто совмещаем в одном месте две вещи: создание экземпляра одного класса и создание экземпляра его внутреннего-класса наследника. Иначе нам нужно создавать класс отдельно и использовать более длинные конструкции, чтобы добиться того же самого результата.
Использование анонимных классов оправдано во многих случаях, в частности когда:

  • тело класса является очень коротким;
  • нужен только один экземпляр класса;
  • класс используется в месте его создания или сразу после него;
  • имя класса не важно и не облегчает понимание кода.

Часто анонимные классы используются в графических интерфейсах для создания обработчиков событий. Например для создания кнопки и реакции на её нажатие.

https://javarush.ru/groups/posts/2193-anonimnihe-klassih

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Каким образом из вложенного класса получить доступ к полю внешнего
класса?

A

РодительскийКласс.this.Поле
Внутренний класс в локальном методе не может использовать локальные переменные внешнего метода до тех пор, пока локальная переменная не будет объявлена как финальная (final).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Что такое перечисления (enum)?

A

При задаче необходимости ограничения множества допустимых значений для некоторого типа данных в Java предусмотрен специальный тип данных – перечисление (enum)

Перечисление — это класс. Объявляя enum мы неявно создаем класс производный от java.lang.Enum
Элементы перечисления — экземпляры enum-класса, доступные статически

Их статическая доступность позволяет нам выполнять сравнение с помощью оператора сравнения ссылок (==)

По сравнению с обычными классами, на Enum наложили одно серьезное ограничение — от него невозможно наследоваться.

Кроме того, у перечислений есть характерные только для них методы:
values(): возвращает массив из всех хранящихся в Enum значений:
ordinal(): возвращает порядковый номер константы. Отсчет начинается с нуля:
valueOf(): возвращает объект Enum, соответствующий переданному имени:

Обрати внимание: мы указываем названия элементов Enum прописными буквами, поскольку это константы, а для них предусмотрена именно такая запись, а не camelCase.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Как проблема ромбовидного наследования решена в java?

A

в Java запрещено множественное наследование от классов. Java не поддерживает множественное наследование классов потому, что это может привести к ромбовидной проблеме.

В Java множественное наследование не поддерживается в классах, но оно поддерживается в интерфейсах. И один интерфейс может расширять множество других интерфейсов. Интерфейсы только объявляют методы, а реализация будет выполнена в классах, наследующих интерфейс.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Что такое конструктор по умолчанию?

A

Конструктор по умолчанию – это конструктор класса, который объявляется без параметров. Если класс не содержит явным образом определенный конструктор, тогда при создании объекта автоматически вызывается конструктор по умолчанию.

Этот конструктор пустой и не делает ничего, кроме вызова конструктора суперкласса.

Если в классе определен конструктор с параметрами, а перегруженного конструктора без параметров нет, то вызов конструктора без параметров является ошибкой.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Могут ли быть приватные конструкторы? Для чего они нужны?

A

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

В шаблоне проектирования, называемом Singleton, приватный конструктор используется, чтобы гарантировать, что всегда существует только один экземпляр класса. Класс Singleton предоставляет статический метод для получения этого уникального экземпляра.
Другое - это делегирование конструкторов; у вас может быть один конструктор, который принимает множество различных параметров, которые действительно являются деталями реализации, поэтому вы делаете их закрытыми. Но затем ваши остальные конструкторы делегируют ему.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Расскажите про классы-загрузчики и про динамическую загрузку классов.

A

Используется для поставки в JVM скомпилированного байт-кода, который, как правило, хранится в файлах с расширением .class, но может быть также получен из других источников, например, загружен по сети или же сгенерирован самим приложением.
Для того, чтобы получить загрузчик, которым был загружен класс А, необходимо воспользоваться методом A.class.getClassLoader().

Классы загружаются по мере надобности, за небольшим исключением. Некоторые базовые классы (java.lang.* в частности) загружаются при старте приложения. Классы расширений ($JAVA_HOME/lib/ext), пользовательские и большинство системных классов загружаются по мере их использования.
Различают 3-и вида загрузчиков в Java. Это — базовый загрузчик (bootstrap), системный загрузчик (System Classloader), загрузчик расширений (Extension Classloader).
- Bootstrap — реализован на уровне JVM и не имеет обратной связи со средой исполнения. Данным загрузчиком загружаются классы из директории $JAVA_HOME/lib. Т.е. всеми любимый rt.jar загружается именно базовым загрузчиком.

  • System Classloader — системный загрузчик, реализованный уже на уровне JRE. Этим загрузчиком загружаются классы, пути к которым указаны в переменной окружения CLASSPATH.
  • Extension Classloader — загрузчик расширений. Данный загрузчик загружает классы из директории $JAVA_HOME/lib/ext.
    Различают текущий загрузчик (Current Classloader) и загрузчик контекста (Context Classloader).
  • Current Classloader — это загрузчик класса, код которого в данный момент исполняется. Текущий загрузчик используется по умолчанию для загрузки классов в процессе исполнения. При любой декларации класса, ранее не загруженного.
  • Context Classloader — загрузчик контекста текущего потока. Загрузчик контекста устанавливается автоматически для каждого нового потока. При этом, используется загрузчик родительского потока.

Загрузчики классов образуют иерархию. Корневым является базовый (у него предка нет). Все остальные загрузчики при инициализации инстанциируют ссылку на родительский загрузчик. Такая иерархия необходима для модели делегирования загрузки.

https://javarush.ru/groups/posts/646-kak-proiskhodit-zagruzka-klassov-v-jvm

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Чем отличаются конструкторы по-умолчанию, конструктор копирования и
конструктор с параметрами?

A

Конструктор по умолчанию не принимает никаких параметров.
Конструктор копирования принимает в качестве параметра объект класса. Конструктор с параметрами принимает на вход параметры (обычно необходимые для инициализации полей класса).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Какие модификаторы доступа есть в Java? Какие применимы к классам?

A
  • private (закрытый) – доступ к члену класса не предоставляется никому, кроме методов этого класса. Другие классы того же пакета также не могут обращаться к private-членам.
  • default - доступ по умолчанию, когда никакой модификатор не присутствует – член класса считается открытым внутри своего собственного пакета, но не доступен для кода, расположенного вне этого пакета.
  • protected (защищённый) – доступ в пределах пакета и классов наследников. Доступ в классе из другого пакета будет к методам public и protected главного класса.
  • public (открытый) – доступ для всех из любого другого кода проекта
    Модификаторы в списке расположены по возрастающей видимости в программе.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Что означает модификатор static?

A

Модификатор static в Java напрямую связан с классом. Если поле статично, значит оно принадлежит классу, если метод статичный — аналогично: он принадлежит классу. Исходя из этого, можно обращаться к статическому методу или полю, используя имя класса.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Может ли статический метод быть переопределён или перегружен?

A

Перегружен - да. Всё работает точно так же как и с обычными методами - 2 статических метода могут иметь одинаковое имя, если количество их параметров или типов различается.
Переопределен - нет. Выбор вызываемого статического метода происходит при раннем связывании (на этапе компиляции, а не выполнения) и выполняться всегда будет родительский метод, хотя синтаксически переопределение статического метода это вполне корректная языковая конструкция.
В целом, к статическим полям и методам рекомендуется обращаться через имя класса, а не объект.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Могут ли нестатические методы перегрузить статические?

A

Да. В итоге получится два разных метода. Статический будет принадлежать классу и будет доступен через его имя, а нестатический будет принадлежать конкретному объекту и доступен через вызов метода этого объекта.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Можно ли сузить уровень доступа/тип возвращаемого значения при
переопределении метода?

A

Изменить можно, но при условии его расширения (package private -> protected -> public)

Нет смысла делать функцию в наследнике менее открытой, потому что она всё равно может быть вызвана через базовый класс.

Принцип подстановки Лисков. Там, где допустимо использовать тип Х, должно быть допустимо использовать и любой тип, наследующийся от него.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Как получить доступ к переопределенным методам родительского класса?

A

С помощью ключевого слова super мы можем обратиться к любому члену родительского класса - методу или полю, если они не определены с модификатором private.
super.method();

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Тип возвращаемого значения метода при перегрузке и
переопределении + модификаторы доступа.
Возможно ли при переопределении метода изменить: модификатор доступа, возвращаемый тип, тип аргумента или их количество, имена аргументов или их порядок; убирать, добавлять, изменять порядок следования элементов секции throws?

A

При переопределении метода сужать модификатор доступа не разрешается, т.к. это приведет к нарушению принципа подстановки Барбары Лисков. Расширение уровня доступа возможно.
Можно изменять все, что не мешает компилятору понять какой метод родительского класса имеется в виду:
Изменять тип возвращаемого значения при переопределении метода разрешено только в сторону сужения типа (вместо родительского класса - наследника).
При изменении типа, количества, порядка следования аргументов вместо переопределения будет происходить overloading (перегрузка) метода.
Секцию throws метода можно не указывать, но стоит помнить, что она остаётся действительной, если уже определена у метода родительского класса. Также, возможно добавлять новые исключения, являющиеся наследниками от уже объявленных или исключения RuntimeException. Порядок следования таких элементов при переопределении значения не имеет.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Что можно изменить в сигнатуре метода при переопределении? Можно ли

менять модификаторы (throws и тп)?

A

(override) В новом методе должны быть те же сигнатура и тип возвращаемого результата, что и у метода родительского класса. Сигнатура метода включает название метода и типы параметров в определенном порядке. Имя плюс типы параметров (упорядоченные). Возвращаемое значение не входит в сигнатуру, а порядок следования параметров – входит.

Переопределяться могут только наследованные методы, т.е. полиморфизм применим только к переопределению.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Могут ли классы быть статическими?

A

Статическим классом в java может быть только вложенный класс - есть вложенные(static) и внутрение классы.
Объекты которых можно создавать, не создавая инстанса класса в котором он лежит.
Статический класс не имеет ссылки не внешний,
static имеет доступ только к статичным полям.
Но можно имитировать статический класс (через final private static).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

О чем говорит ключевое слово final?

A

Модификатор final может применяться к переменным, параметрам методов, полям и методам класса или самим классам.
● Класс не может иметь наследников; Это полезно при создании immutable (неизменяемых) объектов, например, класс String объявлен, как final.
● Метод не может быть переопределен в классах наследниках;
● Поле не может изменить свое значение после инициализации;
● Параметры методов не могут изменять своё значение внутри метода;
● Локальные переменные не могут быть изменены после присвоения им
значения.
Для ссылочных переменных это означает, что после присвоения объекта, нельзя изменить ссылку на данный объект. Это важно! Ссылку изменить нельзя, но состояние объекта изменять можно.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Где и для чего используется модификатор abstract?

A

Класс помеченный модификатором abstract называется абстрактным классом. Такие классы могут выступать только предками для других классов. Создавать экземпляры самого абстрактного класса не разрешается. При этом наследниками абстрактного класса могут быть как другие абстрактные классы, так и классы, допускающие создание объектов.
Метод помеченный ключевым словом abstract - абстрактный метод, т.е. метод, который не имеет реализации. Если в классе присутствует хотя бы один абстрактный метод, то весь класс должен быть объявлен абстрактным.
Использование абстрактных классов и методов позволяет описать некий шаблон объекта, который должен быть реализован в других классах. В них же самих описывается лишь некое общее для всех потомков поведение.
НА ЗАМЕТКУ!!!
Особенности абстрактных классов:
1) Может быть конструктор (для вызовов по цепочке из наследников)
2) Имплементят интерфейсы, но не обязаны реализовывать их методы
3) Не могут быть final
4) Могут содержать static методы
5) Нельзя создать объект
6) Абстрактные методы могут отсутствовать
7) Может содержать метод main()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

Может ли быть абстрактный класс без абстрактных методов?

A

Да, может. Абстрактный класс может содержать как обычные, так и абстрактные методы.

Может ли обычный класс иметь абстрактный метод? Ответ: не может. Абстрактный класс может иметь абстрактный и обычный метод, но обычный класс не может иметь абстрактный метод.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Могут ли быть конструкторы у абстрактных классов? Для чего они нужны?

A

Да, в абстрактном классе в Java можно объявить и определить конструкторы. Поскольку создавать экземпляры абстрактных классов нельзя, вызвать такой конструктор можно только при формировании цепочки конструкторов, то есть при создании экземпляра конкретного класса-реализации.

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

Даже если вы не объявили никакого конструктора, компилятор добавит в абстрактный класс конструктор по умолчанию без аргументов.

Абстрактные классы могут реализовывать интерфейсы с помощью ключевого слова implements. Поскольку они абстрактные, то не обязаны реализовывать все методы.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

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

A

Нет. В таком случае компилятор выдаст ошибку: “Illegal combination of modifiers: ‘abstract’ and ‘static’”. Модификатор abstract говорит, что метод будет реализован в другом классе, а static наоборот указывает, что этот метод будет доступен по имени класса.

26
Q

Дайте определение понятию «интерфейс». Какие модификаторы по умолчанию имеют поля и методы интерфейсов?

A

Ключевое слово interface используется для создания полностью абстрактных классов. Основное предназначение интерфейса - определять каким образом мы можем использовать класс, который его реализует. Создатель интерфейса определяет имена методов, списки аргументов и типы возвращаемых значений, но не реализует их поведение. Все методы неявно объявляются как public.
Начиная с Java 8 в интерфейсах разрешается размещать реализацию методов по умолчанию default и статических static методов.
Интерфейс также может содержать и поля. В этом случае они автоматически являются публичными public, статическими static и неизменяемыми final.

27
Q

Что такое интерфейсы? Какие модификаторы по умолчанию имеют поля и

методы интерфейсов?

A

Интерфейсы (interface) определяют некоторый функционал, не имеющий конкретной реализации, который затем реализуют классы, применяющие эти интерфейсы. И один класс может применить множество интерфейсов – механизм множественного наследования.

Все методы интерфейса не имеют модификаторов доступа, но фактически по умолчанию доступ public, так как цель интерфейса - определение функционала для реализации его классом. Поэтому весь функционал должен быть открыт для реализации.

28
Q

Что такое static метод интерфейса?

A

Статические методы интерфейса похожи на методы по умолчанию, за исключением того, что для них отсутствует возможность переопределения в классах, реализующих интерфейс.
Статические методы в интерфейсе являются частью интерфейса без возможности использовать их для объектов класса реализации;
Методы класса java.lang.Object нельзя переопределить как статические;
Статические методы в интерфейсе используются для обеспечения вспомогательных методов, например, проверки на null, сортировки коллекций и т.д.

29
Q

Как вызывать static метод интерфейса?

A

Используя имя интерфейса: Paper.show();

30
Q

Чем интерфейсы отличаются от абстрактных классов? В каких случаях следует
использовать абстрактный класс, а в каких интерфейс?

A
  • Интерфейс описывает только поведение. У него нет состояния. А у абстрактного класса состояние есть: он описывает и то, и другое.
  • Абстрактный класс связывает между собой и объединяет классы, имеющие очень близкую связь. В то же время, один и тот же интерфейс могут реализовать классы, у которых вообще нет ничего общего.
  • Классы могут реализовывать сколько угодно интерфейсов, но наследоваться можно только от одного класса.
    Интерфейс только описывает поведение. Соответственно, мы не сможем реализовать внутри интерфейса геттеры и сеттеры. Такова природа интерфейса: он нужен для работы с поведением, а не состоянием.

Интерфейс связывает между собой множество разных классов, у которых часто нет ничего общего (has a), а абстрактный класс создается для группы очень близких друг другу классов. Поэтому логично, что наследоваться можно только от одного такого класса. Абстрактный класс описывает отношения (is a).

Интерфейсы необходимы для слабой связанности.

Интерфейс описывает поведение, которым должны обладать классы, реализующие этот интерфейс. «Поведение» — это совокупность методов.

31
Q

Может ли один интерфейс наследоваться от другого? От двух других?

A

От интерфейса может наследоваться только другой интерфейс, при чем он может наследоваться сразу от нескольких интерфейсов.

Конкретные и абстрактные классы наследоваться от интерфейса не могут (могут только от классов).

32
Q

Что такое дефолтные методы интерфейсов? Для чего они нужны?

A

в Java8 появилось дополнение — методы по умолчанию (default method). Например, в твоем интерфейсе есть 10 методов. 9 из них реализованы по-разному в разных классах, но один реализован одинаково у всех.

Используя ключевое слово default, мы создали в интерфейсе метод с реализацией по умолчанию. Два других метода, eat() и run(), нам необходимо будет реализовать самим во всех классах, которые будут имплементировать Swimmable. С методом swim() этого делать не нужно: реализация будет во всех классах одинаковой.

33
Q

Как решается проблема ромбовидного наследования при наследовании
интерфейсов при наличии default методов?

A

Поскольку в разных интерфейсах используются одинаковые методы, то компилятор не может решить, что использовать, поэтому разработчик сам должен переопределить метод(@Override) и реализовать его.

Наличие default метода - это просто возможность использовать такой метод без необходимости его обязательного переопределения (при условии, что нет имплементации интерфейсов с точно такими же методами).

34
Q

К каким конструкциям Java применим модификатор static?

A
● полям;
● методам;
● вложенным классам;
● членам секции import.
● блоки инициализации
35
Q

В чем разница между членом экземпляра класса и статическим членом класса?

A

● Модификатор static говорит о том, что данный метод или поле принадлежат самому классу и доступ к ним возможен даже без создания экземпляра класса. Поля помеченные static инициализируются при инициализации класса. На методы, объявленные как static, накладывается ряд ограничений:
● Они могут вызывать только другие статические методы.
● Они должны осуществлять доступ только к статическим переменным.
● Они не могут ссылаться на члены типа this или super.
● В отличии от статических, поля экземпляра класса принадлежат
конкретному объекту и могут иметь разные значения для каждого. Вызов метода экземпляра возможен только после предварительного создания объекта класса.

36
Q

Где разрешена инициализация статических/нестатических полей?

A

Статические поля можно инициализировать при объявлении, в статическом или нестатическом блоке инициализации.
Нестатические поля можно инициализировать при объявлении, в нестатическом блоке инициализации или в конструкторе.
НА ЗАМЕТКУ!!!
Особенности Enum классов:
1) Конструктор всегда private или default
2) Могут имплементировать интерфейсы
3) Не могут наследовать класс
4) Можем переопределить toString()
5) Нет public конструктора, поэтому нельзя создать экземпляр вне Enum
6) При equals() выполняется ==
7) ordinal() возвращает порядок элементов
8) Может использоваться в TreeSet и TreeMap т.к. Enum имплементирует
Comparable
9) compareTo() имитирует порядок элементов предоставляемый ordinal()
10) Можно использовать в Switch Case
11) values() возвращает массив всех констант
12) Легко создать потокобезопасный синглтон без double check volatile
переменных.

37
Q

instanceof

A

Оператор instanceof сравнивает объект и указанный тип. Его можно использовать для проверки является ли данный объект экземпляром некоторого класса, либо экземпляром его дочернего класса, либо экземпляром класса, который реализует указанный интерфейс. this.getClass() == that.getClass() проверяет два класса на идентичность, поэтому для корректной реализации контракта метода equals() необходимо использовать точное сравнение с помощью метода getClass().

38
Q

Каков порядок вызова конструкторов и блоков инициализации с учётом
иерархии классов?

A

Сначала вызываются все статические блоки в очередности от первого статического блока корневого предка и выше по цепочке иерархии до статических блоков самого класса.

Затем вызываются нестатические блоки инициализации корневого предка, конструктор корневого предка и так далее вплоть до нестатических блоков и конструктора самого класса.

39
Q

Блоки инициализации.

A

Блоки инициализации представляют собой код, заключенный в фигурные скобки и размещаемый внутри класса вне объявления методов или конструкторов.
Существуют статические и нестатические блоки инициализации.
Блок инициализации выполняется перед инициализацией класса загрузчиком классов или созданием объекта класса с помощью конструктора.
Несколько блоков инициализации выполняются в порядке следования в коде класса.
Блок инициализации способен генерировать исключения, если их объявления перечислены в throws всех конструкторов класса.
Блок инициализации возможно создать и в анонимном классе.

40
Q

Для чего в Java используются статические блоки инициализации?

A

Статические блоки инициализация используются для выполнения кода, который должен выполняться один раз при инициализации класса загрузчиком классов, в момент предшествующий созданию объектов этого класса при помощи конструктора. Такой блок (в отличие от нестатических, принадлежащих конкретном объекту класса) принадлежит только самому классу (объекту метакласса Class).

41
Q

Что произойдет, если в блоке инициализации возникнет исключительная ситуация?

A

Для нестатических блоков инициализации, если выбрасывание исключения прописано явным образом требуется, чтобы объявления этих исключений были перечислены в throws всех конструкторов класса. Иначе будет ошибка компиляции. Для статического блока выбрасывание исключения в явном виде, приводит к ошибке компиляции.
В остальных случаях, взаимодействие с исключениями будет проходить так же как и в любом другом месте. Класс не будет инициализирован, если ошибка происходит в статическом блоке и объект класса не будет создан, если ошибка возникает в нестатическом блоке.

42
Q

Какое исключение выбрасывается при возникновении ошибки в блоке инициализации класса?

A

Если возникшее исключение - наследник RuntimeException:
● для статических блоков инициализации будет выброшено
java.lang.ExceptionInInitializerError;
● для нестатических будет проброшено исключение-источник.
Если возникшее исключение - наследник Error, то в обоих случаях будет выброшено java.lang.Error. Исключение: java.lang.ThreadDeath - смерть потока. В этом случае никакое исключение выброшено не будет.

43
Q

Зачем нужны и какие бывают блоки инициализации?

A

Блоки инициализации представляют собой код, заключенный в фигурные скобки и размещаемый внутри класса вне объявления методов или конструкторов.

Существуют статические и нестатические блоки инициализации.

Блок инициализации выполняется перед инициализацией класса загрузчиком классов или созданием объекта класса с помощью конструктора.

Несколько блоков инициализации выполняются в порядке следования в коде класса.

Блок инициализации способен генерировать исключения, если их объявления перечислены в throws всех конструкторов класса.

Блок инициализации возможно создать и в анонимном классе.

44
Q

Для чего в Java используются статические блоки инициализации?

A

Статические блоки инициализация используются для выполнения кода, который должен выполняться один раз при инициализации класса загрузчиком классов, в момент, предшествующий созданию объектов этого класса при помощи конструктора. Такой блок (в отличие от нестатических, принадлежащих конкретном объекту класса) принадлежит только самому классу (объекту метакласса Class).

45
Q

Что произойдет, если в блоке инициализации возникнет исключительная
ситуация?

A

Для нестатических блоков инициализации, если выбрасывание исключения прописано явным образом требуется, чтобы объявления этих исключений были перечислены в throws всех конструкторов класса. Иначе будет ошибка компиляции. Для статического блока выбрасывание исключения в явном виде, приводит к ошибке компиляции.

В остальных случаях, взаимодействие с исключениями будет проходить так же как и в любом другом месте. Класс не будет инициализирован, если ошибка происходит в статическом блоке и объект класса не будет создан, если ошибка возникает в нестатическом блоке.

46
Q

Какое исключение выбрасывается при возникновении ошибки в блоке
инициализации класса?

A

Если возникшее исключение - наследник RuntimeException:

для статических блоков инициализации будет выброшено java.lang.ExceptionInInitializerError;

для нестатических будет проброшено исключение-источник.

Если возникшее исключение - наследник Error, то в обоих случаях будет выброшено java.lang.Error. Исключение: java.lang.ThreadDeath - смерть потока. В этом случае никакое исключение выброшено не будет.

47
Q

Порядок вызова конструкторов и блоков инициализации с

учётом иерархии классов.

A

Сначала вызываются все статические блоки в очередности от первого статического блока корневого предка и выше по цепочке иерархии до статических блоков самого класса.
Затем вызываются нестатические блоки инициализации корневого предка, конструктор корневого предка и так далее вплоть до нестатических блоков и конструктора самого класса.
Parent static block(s) → Child static block(s) → Grandchild static block(s) → Parent non-static block(s) → Parent constructor →
→ Child non-static block(s) → Child constructor →
→ Grandchild non-static block(s) → Grandchild constructor

48
Q

Что такое класс Object?

A

Object это базовый класс для всех остальных объектов в Java. Любой класс наследуется от Object и, соответственно, наследуют его методы:

49
Q

Какие методы есть у класса Object (перечислить все)? Что они делают?

A

public boolean equals(Object obj) – служит для сравнения объектов по значению;

int hashCode() – возвращает hash код для объекта;

String toString() – возвращает строковое представление объекта;

Class getClass() – возвращает класс объекта во время выполнения;

protected Object clone() – создает и возвращает копию объекта;

void notify() – возобновляет поток, ожидающий монитор;

void notifyAll() – возобновляет все потоки, ожидающие монитор;

void wait() – остановка вызвавшего метод потока до момента пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;

void wait(long timeout) – остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;

void wait(long timeout, int nanos) – остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;

protected void finalize() – может вызываться сборщиком мусора в момент удаления объекта при сборке мусора.

50
Q

Расскажите про equals и hashcode

A

Методы equals и hashCode тесно связаны друг с другом, и что оба этих метода желательно переопределять в своих классах согласованно.
Метод equals() необходим в Java для подтверждения или отрицания того факта, что два объекта одного происхождения являются логически равными. То есть, сравнивая два объекта, программисту необходимо понять, эквивалентны ли их значимые поля. Не обязательно все поля должны быть идентичны, так как метод equals() подразумевает именно логическое равенство.
Хэш — это некоторое число, генерируемое на основе объекта и описывающее его состояние в какой-то момент времени. Это число используется в Java преимущественно в хэш-таблицах, таких как HashMap. При этом хэш-функция получения числа на основе объекта должна быть реализована таким образом, чтобы обеспечить относительно равномерное распределение элементов по хэш-таблице. А также минимизировать вероятность появления коллизий, когда по разным ключам функция вернет одинаковое значение.

51
Q

Каким образом реализованы методы hashCode() и equals() в классе Object?

A
  • Реализация метода Object.equals() сводится к проверке на равенство двух ссылок.
  • Реализация метода Object.hashCode() описана как native, т.е. определенной не с помощью Java кода и обычно возвращает адрес объекта в памяти.
52
Q

Зачем нужен equals(). Чем он отличается от операции ==?

A

Метод equals() - определяет отношение эквивалентности объектов.

При сравнении объектов с помощью == сравнение происходит лишь между ссылками. При сравнении по переопределённому разработчиком equals() - по внутреннему состоянию объектов.

53
Q

Правила переопределения equals()

A
  • Использование оператора == для проверки, является ли аргумент ссылкой на указанный объект. Если является, возвращается true. Если сравниваемый объект == null, должно вернуться false.
  • Использование оператор instanceof и вызова метода getClass() для проверки, имеет ли аргумент правильный тип. Если не имеет, возвращается false.
  • Приведение аргумента к правильному типу. Поскольку эта операция следует за проверкой instanceof она гарантированно будет выполнена.
  • Обход всех значимых полей класса и проверка того, что значение поля в текущем объекте и значение того же поля в проверяемом на эквивалентность аргументе соответствуют друг другу. Если проверки для всех полей прошли успешно, возвращается результат true, в противном случае - false.
54
Q

Что будет, если переопределить equals() не переопределяя hashCode()? Какие
могут возникнуть проблемы?

A

Коллекции в Java перед тем как сравнить объекты с помощью equals всегда ищут/сравнивают их с помощью метода hashCode(). И если у одинаковых объектов будут разные hashCode, то объекты будут считаться разными — до сравнения с помощью equals просто не дойдет.
Своими словами: по умолчанию hashcode Object - это адрес в памяти. Т.е. два эквивалентных объекта будут иметь разные хэшкоды, а должны быть одинаковыми.

55
Q

Какой контракт между hashCode() и equals()?

A

Если equals дает true, то и hashCode должны быть одинаковы.

Но если хеш коды одинаковы, то equals не обязательно должен быть true.

Контракт equals

При переопределении метода equals разработчик должен придерживаться основных правил, определенных в спецификации языка Java.

  • Рефлексивность

для любого заданного значения x, выражение x.equals(x) должно возвращать true.

Заданного — имеется в виду такого, что x != null

  • Симметричность

для любых заданных значений x и y, x.equals(y) должно возвращать true только в том случае, когда y.equals(x) возвращает true.

  • Транзитивность

для любых заданных значений x, y и z, если x.equals(y) возвращает true и y.equals(z) возвращает true, x.equals(z) должно вернуть значение true.

  • Согласованность

для любых заданных значений x и y повторный вызов x.equals(y) будет возвращать значение предыдущего вызова этого метода при условии, что поля, используемые для сравнения этих двух объектов, не изменялись между вызовами.

  • Сравнение null

для любого заданного значения x вызов x.equals(null) должен возвращать false.

56
Q

Для чего нужен метод hashCode()?

A

Метод hashCode() необходим для вычисления хэш кода переданного в качестве входного параметра объекта. В Java это целое число, в более широком смыле - битовая строка фиксированной длины, полученная из массива произвольной длины. Этот метод реализован таким образом, что для одного и того же входного объекта, хэш код всегда будет одинаковым. Следует понимать, что в Java множество возможных хэш кодов ограничено типом int, а множество объектов ничем не ограничено. Из-за этого, вполне возможна ситуация, что хэш коды разных объектов могут совпасть:
- если хэш коды разные, то и объекты гарантированно разные;

  • если хэш коды равны, то объекты могут не обязательно равны.
57
Q

Правила переопределения метода hashcode().

A

хэш-функция получения числа на основе объекта должна быть реализована таким образом, чтобы обеспечить относительно равномерное распределение элементов по хэш-таблице. А также минимизировать вероятность появления коллизий, когда по разным ключам функция вернет одинаковое значение.

Контракт hashCode

Для реализации хэш-функции в спецификации языка определены следующие правила:

  • вызов метода hashCode один и более раз над одним и тем же объектом должен возвращать одно и то же хэш-значение, при условии что поля объекта, участвующие в вычислении значения, не изменялись.
  • вызов метода hashCode над двумя объектами должен всегда возвращать одно и то же число, если эти объекты равны (вызов метода equals для этих объектов возвращает true).
  • вызов метода hashCode над двумя неравными между собой объектами должен возвращать разные хэш-значения. Хотя это требование и не является обязательным, следует учитывать, что его выполнение положительно повлияет на производительность работы хэш-таблиц.
58
Q

Есть ли какие-либо рекомендации о том, какие поля следует использовать при
подсчете hashCode()?

A

Вызов метода hashCode один и более раз над одним и тем же объектом должен возвращать одно и то же хэш-значение, при условии что поля объекта, участвующие в вычислении значения, не изменялись.

При подсчете хеш-кода необходимо использовать уникальные, лучше примитивные поля, такие как id или uuid. Причем, если эти поля задействованы при вычислении hashCode, их задействовать и при выполнении equals. Более общий совет: выбирать поля, которые с большой долью вероятности будут различаться. Хеш-код должен быть равномерно распределен на области возможных принимаемых значений.

Если у объекта, который используется в качестве ключа в hashMap изменится поле, которое участвует в определении хеш-кода, то могут возникнуть проблемы с поиском значения по ключу.

59
Q

Могут ли у разных объектов быть одинаковые hashCode()?

A

Да, могут. Метод hashCode() не гарантирует уникальность возвращаемого значения. Ситуация, когда у разных объектов одинаковые хэш коды называется коллизией. Вероятность возникновения коллизии зависит от используемого алгоритма генерации хэш кода.

60
Q

Почему нельзя реализовать hashcode() который будет гарантированно
уникальным для каждого объекта?

A

Поскольку в любом экземпляре виртуальной машины имеется всего 2 ^ 32 разных интервала, и может быть более 2 ^ 32 живых объектов, технически невозможно гарантировать уникальный хеш-код для каждого объекта.

61
Q

Есть класс Point{int x, y;}. Почему хэш-код в виде 31 * x + y предпочтительнее
чем x + y?

A

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

62
Q

Чем a.getClass().equals(A.class) отличается от a instanceOf A.class

A

this.getClass() == that.getClass() проверяет два класса на идентичность, поэтому для корректной реализации контракта метода equals() необходимо использовать точное сравнение с помощью метода getClass().