A: Модификаторы доступа Java — это ключевые слова для управления видимостью классов, методов и полей в программе. Они определяют из какой части програамы можно обращаться к тем или иным ресурсам. Всего в java есть 4 модификатора доступа:
- private - члены класса доступны только внутри класса
- default (package-private) - члены класса доступны только внутри того же пакета.
- protected - члены класса доступны внутри того же пакета, а также внутри любых дочерних классов.
- public - члены класса доступны из любого места программы.
A: Концептуально, интерфейс описывает только поведение объектов, а абстрактный класс описывает как поведение, так и состояние объектов. Технически:
- можно унаследовать только 1 абстрактный класс, когда интерфейсов можно реализовать целое множество
- в абстрактном классе поля и методы могут быть с любыми модификаторами доступа, когда в интерфейсе только public
- в абстрактном классе можно реализовать конструктор
A: fail-fast и fail-safe - это два типа интераторов которые по разному реагируют на изменение коллекции в момент прохода по ней. Итератор типа fail-fast сгенерирует исключение ConcurrentModificationException, если коллекция будет изменена во время итерации. Fail-safe никак не отреагирует на изменения, так как итерируется не по самой коллекции, а по ее копии.
Q: Что такое функциональный интерфейс, для чего он применятеся, какие стандартные функционльные интерфейсы есть в java.
A: Функциональный интерфейс в Java – это интерфейс, который содержит только 1 абстрактный метод. Основное назначение – использование в лямбда выражениях и method reference. Java имеет следующие стандартные функциональные интерфейсы:
- Predicate: boolean test(T t) - Функциональный интерфейс Predicate проверяет соблюдение некоторого условия. Если оно соблюдается, то возвращается значение true.
- UnaryOperator: T apply(T t) - UnaryOperator принимает в качестве параметра объект типа T, выполняет над ними операции и возвращает результат операций в виде объекта типа T.
- BinaryOperator: T apply(T t1, T t2) - BinaryOperator принимает в качестве параметра два объекта типа T, выполняет над ними бинарную операцию и возвращает ее результат также в виде объекта типа T.
- Function<T,R>: R apply(T t) - Функциональный интерфейс Function<T,R> представляет функцию перехода от объекта типа T к объекту типа R.
- Consumer: void accept(T t) - Consumer выполняет некоторое действие над объектом типа T, при этом ничего не возвращая.
- Supplier: T get() - Supplier не принимает никаких аргументов, но должен возвращать объект типа T.
A: Иерархия исключений имеет следующий вид:
- Throwable - общий предок для всех классов исключений.
- Error - Ошибки (Error) представляют собой более серьезные проблемы, которые, согласно спецификации Java, не следует пытаться обрабатывать в собственной программе, поскольку они связаны с проблемами уровня JVM.
- Exception - Исключения (Exceptions) являются результатом проблем в программе, которые, в принципе, решаемые и предсказуемые. В Java все исключения делятся на два типа: контролируемые исключения (checked) и неконтролируемые исключения (unchecked).
Контролируемые исключения представляют собой ошибки, которые можно и нужно обрабатывать в программе, они проверяются на этапе компиляции и должны быть помещены в блок catch или проброшены выше через ключевое слово throws.
- RunTimeException - неконтролируемые исключения (unchecked).
- IOException и все остальные - контролируемые исключения (checked).
A: Контракт методов equals() и hashCode():
- Для одонго и того же обхекта хэш-код всегда одинаков.
- Если объекты одинаковы, то хэш-код всегда одинаков.
- Если хэш-коды равны, то объекты не всегда равны.
- Если хэш-коды разные, то объекты гарантированно будут разными.
A: Свойства методов equals() и hashCode():
- Рефлексивность - для любой ссылки на значение x, выражение x.equals(x) должно возвращать true.
- Симметричность - для любых ссылок на значения x и y, выражение x.equals(y) должно вернуть true, тогда и только тогда, когда y.equaks(x) возаращает true.
- Транзитивность - для любых ссылок на значения x, y и z, если x.equals(y) = true и y.equals(z) = true, тогда и x.equals(z) = true.
- Непротиворечивость - для любых ссылок на значения x и y, выражение x.equals(y) должно всегда возвращать постоянное значение, при условии, что никакая информация, используемая при сравнении объектов не поменялась.
- Для любой ненулевой ссылки на значение x, выражение x.equals(null) должно возвращать false.
A: Алгоритм добавления элемента в коллекцию HashMap имеет следующий вид:
- Вычислить значение хэша у ключа.
- Вычислить ячейку массива для хранения значения. Номер ячейки определяется по остатку от деления хэша на количество ячеек или с помощью бинарного сдвига.
- Если ячейка пустая, то туда добавляется элемент
- Если ячейка не пустая, то все элементы ранее помещенные туда формируют связанный список и необходимо пройтись по всему этому списку сравнивая ключ добавляемого элемента и ключ элемента из списка по хеш-коду.
- Если хэши не равны - идем дальше
- Если хэши равны - сравниваем ключи по equals
- Если ключи равны по equals, то перезаписываем значние по этому ключу
- Если ключи не равны по equals, то идея дальше
- Если в списке не был найден элемент с нужным ключом, то новый элемент добавляется в конец списка.
Q: На чем основывается алгоритм бинарного поиска, в чем его суть, какие преимущества и недостатки алгоритма.
A: Алгоритм основывается на двоичном поиске, где на каждом шаге множество объектов делится на две части и в работе остаётся та часть множества, где находится искомый объект. Бинарный поиск служит для нахождения определенного значения в отсортированном массиве данных. Суть алгоритма в том, чтобы во всем массиве взять серединный элемент и сравнить его с искомым. Если серединный элемент меньше искомого, то верный ответ находится среди элементов расположенных левее, а если больше, то правее. После сравнения работа алгоритма продолжится с тем подмассивом где возможно находится искомый элемент. И так будет продолжаться либо пока подмассив не окажется пустым (искомого значения в массиве нет), либо пока искомый элемент не будет найдет. Плюсы - высокая скорость поиска O(log n), минусы - массив обязан быть предварительно отсортирован.
A: Алгоритм Дейкстры - типичный пример алгоритма поиска в ширину. Данный алгорит служит для нахождения минимального пути от точки А до точки Б во взвешенном графе. Преимущества алгоритма в его более высокой скорости поиска в сравнении с другими алгоритмами поиска в ширину. Недостатки - взвешенный граф не должен иметь отрицательных весов, иначе алгоритм попросту не сработает.