ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 01.12.2023
Просмотров: 473
Скачиваний: 3
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
3. Переопределив equals, всегда переопределять и hashcode.
Для чего нужен метод hashCode()?
Метод hashCode() необходим для вычисления хеш-кода переданного в качестве входного параметра объекта. В Java это целое число, в более широком смысле – битовая строка фиксированной длины, полученная из массива произвольной длины. Этот метод реализован таким образом, что для одного и того же входного объекта хеш-код всегда будет одинаковым.
Следует понимать, что в Java множество возможных хеш-кодов ограничено типом int, а множество объектов ничем не ограничено. Из-за этого вполне возможна ситуация, что хеш- коды разных объектов могут совпасть:
•
если хеш-коды разные, то и объекты гарантированно разные;
•
если хеш-коды равны, то объекты могут не обязательно равны.
В случае, если hashCode() не переопределен, то будет выполнятся его реализация по умолчанию из класса Object: для разных объектов будет разный хеш-код.
Значение int может быть в диапазоне 2 32
, при переопределении хеш-кода можно использовать отрицательное значение.
Правила переопределения метода hashcode()
1. Если хеш-коды разные, то и входные объекты гарантированно разные.
2. Если хеш-коды равны, то входные объекты не всегда равны.
3. При вычислении хеш-кода следует использовать те же поля, которые сравниваются в equals и которые не вычисляются на основе других значений.
Есть ли какие-либо рекомендации о том, какие поля следует использовать
при подсчете hashCode()?
Следует выбирать поля, которые с большой долью вероятности будут различаться. Для этого необходимо использовать уникальные, лучше всего примитивные поля, например такие как id, uuid. При этом нужно следовать правилу: если поля задействованы при вычислении hashCode(), то они должны быть задействованы и при выполнении equals().
Могут ли у разных объектов быть одинаковые hashCode()?
Да, могут. Метод hashCode() не гарантирует уникальность возвращаемого значения.
Ситуация, когда у разных объектов одинаковые хеш-коды называется коллизией.
Вероятность возникновения коллизии зависит от используемого алгоритма генерации хеш- кода.
Почему нельзя реализовать hashcode(), который будет гарантированно
уникальным для каждого объекта?
В Java множество возможных хеш-кодов ограничено типом int, а множество объектов ничем не ограничено.
Из-за этого вполне возможна ситуация, что хеш-коды разных объектов могут совпасть.
Почему хеш-код в виде 31 * x + y предпочтительнее чем x + y?
•
множитель создает зависимость значения хеш-кода от очередности обработки полей, что в итоге порождает лучшую хеш-функцию;
•
31 можно легко сдвигать побитово;
•
в хеш-коде должны фигурировать поля, которые фигурируют в equals().
Чем a.getClass().equals(A.class) отличается от a instanceOf A.class?
getClass() получает только класс, а оператор instanceof проверяет, является ли объект экземпляром класса или его потомком.
instanceof
Оператор instanceof сравнивает объект и указанный тип. Его можно использовать для проверки, является ли данный объект экземпляром некоторого класса, либо экземпляром его дочернего класса, либо экземпляром класса, который реализует указанный интерфейс.
this.getClass() == that.getClass() проверяет два класса на идентичность, поэтому для корректной реализации контракта метода equals() необходимо использовать точное сравнение с помощью метода getClass().
Что такое исключение?
Исключение – это ошибка (является объектом), возникающая во время выполнения программы.
Опишите иерархию исключений
Исключения делятся на несколько классов, но все они имеют общего предка – класс
Throwable, потомками которого являются классы Exception и Error.
Ошибки (Errors) представляют собой более серьезные проблемы, которые, согласно спецификации Java, не следует обрабатывать в собственной программе, поскольку они связаны с проблемами уровня JVM. Например, исключения такого рода возникают, если закончилась память, доступная виртуальной машине.
Исключения (Exceptions) являются результатом проблем в программе, которые в принципе решаемы, предсказуемы и последствия которых возможно устранить внутри программы.
Например, произошло деление целого числа на ноль.
Расскажите про обрабатываемые и необрабатываемые исключения
В Java все исключения делятся на два типа:
•
checked (контролируемые/проверяемые исключения) должны обрабатываться блоком catch или описываться в сигнатуре метода (например throws IOException),
наличие такого обработчика/модификатора сигнатуры проверяются на этапе компиляции;
•
unchecked (неконтролируемые/непроверяемые исключения), к которым относятся ошибки Error (например OutOfMemoryError), обрабатывать которые не рекомендуется и исключения времени выполнения, представленные классом
RuntimeException и его наследниками (например NullPointerException), которые могут не обрабатываться блоком catch и не быть описанными в сигнатуре метода.
Можно ли обработать необрабатываемые исключения?
Можно, чтобы в некоторых случаях программа не прекратила работу. Отлавливаются в try- catch.
Какой оператор позволяет принудительно выбросить исключение?
Это оператор throw:
throw new Exception();
О чем говорит ключевое слово throws?
Модификатор throws прописывается в сигнатуре метода и указывает на то, что метод потенциально может выбросить исключение с указанным типом.
Передает обработку исключения вышестоящему методу. Используется в конструкторе,
методе, классе.
Как написать собственное («пользовательское») исключение?
Необходимо унаследоваться от базового класса требуемого типа исключений (например, от
Exception или RuntimeException)
и переопределить методы.
Какие существуют unchecked exception?
Наиболее часто встречающиеся:
ArithmeticException,
ClassCastException,
ConcurrentModificationException,
IllegalArgumentException,
IllegalStateException,
IndexOutOfBoundsException,
NoSuchElementException,
NullPointerException,
UnsupportedOperationException.
Что представляет из себя ошибки класса Error?
Ошибки класса Error представляют собой наиболее серьезные проблемы уровня JVM.
Например, исключения такого рода возникают, если закончилась память, доступная виртуальной машине. Обрабатывать такие ошибки не запрещается, но делать этого не рекомендуется.
Что вы знаете о OutOfMemoryError?
OutOfMemoryError выбрасывается, когда виртуальная машина Java не может создать
(разместить) объект из-за нехватки памяти, а сборщик мусора не может высвободить достаточное ее количество.
Область памяти, занимаемая java-процессом, состоит из нескольких частей. Тип
OutOfMemoryError зависит от того, в какой из них не хватило места:
•
java.lang.OutOfMemoryError: Java heap space: не хватает места в куче, а именно, в области памяти, в которую помещаются объекты, создаваемые в приложении программно. Обычно проблема кроется в утечке памяти. Размер задается параметрами -Xms и -Xmx.
•
java.lang.OutOfMemoryError: PermGen space (до версии Java 8): Данная ошибка возникает при нехватке места в Permanent-области, размер которой задается параметрами -XX:PermSize и -XX:MaxPermSize.
•
java.lang.OutOfMemoryError: GC overhead limit exceeded: Данная ошибка может возникнуть как при переполнении первой, так и второй областей. Связана она с тем, что памяти осталось мало и сборщик мусора постоянно работает, пытаясь высвободить немного места. Данную ошибку можно отключить с помощью параметра -XX:-UseGCOverheadLimit.
•
java.lang.OutOfMemoryError: unable to create new native thread: Выбрасывается,
когда нет возможности создавать новые потоки.
Опишите работу блока try-catch-finally
try – данное ключевое слово используется для отметки начала блока кода, который потенциально может привести к ошибке.
catch – ключевое слово для отметки начала блока кода, предназначенного для перехвата и обработки исключений в случае их возникновения.
finally – ключевое слово для отметки начала блока кода, который является дополнительным.
Этот блок помещается после последнего блока catch. Управление передается в блок finally в любом случае, было выброшено исключение или нет.
Общий вид конструкции для обработки исключительной ситуации выглядит следующим образом:
try {
//код, который потенциально может привести к исключительной ситуации
}
catch(SomeException e) { //в скобках указывается класс конкретной ожидаемой ошибки
//код обработки исключительной ситуации
}
finally {
//необязательный блок, код которого выполняется в любом случае
}
1 ... 5 6 7 8 9 10 11 12 ... 25
Возможно ли использование блока try-finally (без catch)?
Такая запись допустима, но смысла в такой записи не так много, все же лучше иметь блок catch, в котором будет обрабатываться необходимое исключение.
Работает точно так же: после выхода из блока try выполняется блок finally.
Может ли один блок catch отлавливать сразу несколько исключений?
В Java 7 стала доступна новая языковая конструкция, с помощью которой можно перехватывать несколько исключений одним блоком catch:
try {
//...
} catch(IOException | SQLException ex) {
//...
}
Всегда ли исполняется блок finally? Существуют ли ситуации, когда блок
finally не будет выполнен?
Да, кроме случаев завершения работы программы или JVM:
•
Finally может не выполниться в случае если в блоке try вызывает System.exit(0).
•
Runtime.getRuntime().exit(0), Runtime.getRuntime().halt(0) и если во время исполнения блока try виртуальная машина выполнила недопустимую операцию и будет закрыта.
•
В блоке try{} бесконечный цикл.
Может ли метод main() выбросить исключение во вне и если да, то где
будет происходить обработка данного исключения?
Может, исключение будет передано в виртуальную машину Java (JVM).
В каком порядке следует обрабатывать исключения в catch-блоках?
От наследника к предку.
Что такое механизм try-with-resources?
Данная конструкция, которая появилась в Java 7, позволяет использовать блок try-catch, не заботясь о закрытии ресурсов, используемых в данном сегменте кода. Ресурсы объявляются в скобках сразу после try, а компилятор уже сам неявно создает секцию finally, в которой и происходит освобождение занятых в блоке ресурсов. Под ресурсами подразумеваются сущности, реализующие интерфейс java.lang.Autocloseable.
Стоит заметить, что блоки catch и явный finally выполняются уже после того, как закрываются ресурсы в неявном finally.
Что произойдет, если исключение будет выброшено из блока catch, после
чего другое исключение будет выброшено из блока finally?
finally-секция может «перебить» throw/return при помощи другого throw/return.
Что произойдет, если исключение будет выброшено из блока catch, после
чего другое исключение будет выброшено из метода close() при
использовании try-with-resources?
В try-with-resources добавлена возможность хранения «подавленных» исключений, и брошенное try-блоком исключение имеет больший приоритет, чем исключения,
получившиеся во время закрытия.
Предположим, есть метод, который может выбросить IOException и
FileNotFoundException. В какой последовательности должны идти блоки
catch? Сколько блоков catch будет выполнено?
Общее правило: обрабатывать исключения нужно от младшего к старшему. Т. е. нельзя поставить в первый блок catch(Exception ex) {}, иначе все дальнейшие блоки catch() уже ничего не смогут обработать, т. к. любое исключение будет соответствовать обработчику catch(Exception ex).
Таким образом, исходя из факта, что FileNotFoundException extends IOException сначала нужно обработать FileNotFoundException, а затем уже IOException:
void method() {
try {
//...
} catch (FileNotFoundException ex) {
//...
} catch (IOException ex) {
//...
}
}
Что такое «сериализация» и как она реализована в Java?
Сериализация (Serialization) – процесс преобразования структуры данных в линейную последовательность байтов для дальнейшей передачи или сохранения. Сериализованные объекты можно затем восстановить (десериализовать).
В Java, согласно спецификации Java Object Serialization, существует два стандартных способа сериализации: стандартная сериализация через использование интерфейса
java.io.Serializable и «расширенная» сериализация – java.io.Externalizable.
Сериализация позволяет в определенных пределах изменять класс. Вот наиболее важные изменения, с которыми спецификация Java Object Serialization может справляться автоматически:
•
добавление в класс новых полей;
•
изменение полей из статических в нестатические;
•
изменение полей из транзитных в нетранзитные.
Обратные изменения (из нестатических полей в статические и из нетранзитных в транзитные) или удаление полей требуют определенной дополнительной обработки в зависимости от того, какая степень обратной совместимости необходима.
Для чего нужна сериализация?
Для компактного сохранения состояния объекта и считывание этого состояния.
Опишите процесс сериализации/десериализации с использованием
Serializable
При использовании Serializable применяется алгоритм сериализации, который с помощью рефлексии (Reflection API) выполняет:
•
запись в поток метаданных о классе, ассоциированном с объектом (имя класса,
идентификатор SerialVersionUID, идентификаторы полей класса);
•
рекурсивную запись в поток описания суперклассов до класса java.lang.Object (не включительно);
•
запись примитивных значений полей сериализуемого экземпляра, начиная с полей самого верхнего суперкласса;
•
рекурсивную запись объектов, которые являются полями сериализуемого объекта.
При этом ранее сериализованные объекты повторно не сериализуются, что позволяет алгоритму корректно работать с циклическими ссылками.
Для выполнения десериализации под объект выделяется память, после чего его поля заполняются значениями из потока. Конструктор объекта при этом не вызывается. Однако при десериализации будет вызван конструктор без параметров родительского несериализуемого класса, а его отсутствие повлечет ошибку десериализации.
Как изменить стандартное поведение сериализации/десериализации?
Реализовать интерфейс
java.io.Externalizable, который позволяет применение пользовательской логики сериализации. Способ сериализации и десериализации описывается в методах writeExternal() и readExternal(). Во время десериализации вызывается конструктор без параметров, а потом уже на созданном объекте вызывается метод readExternal.
Если у сериализуемого объекта реализован один из следующих методов, то механизм сериализации будет использовать его, а не метод по умолчанию :
•
writeObject() – запись объекта в поток;
•
readObject() – чтение объекта из потока;
•
writeReplace() – позволяет заменить себя экземпляром другого класса перед записью;
•
readResolve() – позволяет заменить на себя другой объект после чтения.
Какие поля не будут сериализованы при сериализации? Будет ли
сериализовано final-поле?
Поля с модификатором transient. В таком случае после восстановления его значение будет null.