Главная страница

ОглавлениеCore


Скачать 1.53 Mb.
НазваниеОглавлениеCore
Дата17.05.2023
Размер1.53 Mb.
Формат файлаpdf
Имя файлаpolnaya_metodichka (1).pdf
ТипДокументы
#1138113
страница6 из 25
1   2   3   4   5   6   7   8   9   ...   25

«возрождением»
объекта и считается антипаттерном. Главная проблема такого трюка в том, что
«возродить» объект можно только 1 раз.
Что произойдет со сборщиком мусора, если выполнение метода finalize()
требует ощутимо много времени или в процессе выполнения будет
выброшено исключение?
Непосредственно вызов finalize() происходит в отдельном потоке Finalizer
(java.lang.ref.Finalizer.FinalizerThread), который создается при запуске виртуальной машины
(в статической секции при загрузке класса Finalizer). Методы finalize() вызываются последовательно в том порядке, в котором были добавлены в список сборщиком мусора.
Соответственно, если какой-то finalize() зависнет, он подвесит поток Finalizer, но не сборщик мусора. Это в частности означает, что объекты, не имеющие метода finalize(), будут исправно удаляться, а вот имеющие будут добавляться в очередь, пока поток Finalizer не освободится, не завершится приложение или не кончится память.
То же самое применимо и к выброшенным в процессе finalize() исключениям: метод runFinalizer() у потока Finalizer игнорирует все исключения, выброшенные в момент выполнения finalize(). Таким образом, возникновение исключительной ситуации никак не скажется на работоспособности сборщика мусора.
Чем отличаются final, finally и finalize()?
Модификатор final:

класс не может иметь наследников;

метод не может быть переопределен в классах наследниках;

поле не может изменить свое значение после инициализации;

локальные переменные не могут быть изменены после присвоения им значения;


параметры методов не могут изменять свое значение внутри метода.
Оператор finally гарантирует, что определенный в нем участок кода будет выполнен независимо от того, какие исключения были возбуждены и перехвачены в блоке try-catch.
Метод finalize() вызывается перед тем, как сборщик мусора будет проводить удаление объекта.
Что такое Heap- и Stack-память в Java? Какая разница между ними?
Heap (куча) используется Java Runtime для выделения памяти под объекты и классы.
Создание нового объекта также происходит в куче. Она же является областью работы сборщика мусора. Любой объект, созданный в куче, имеет глобальный доступ и на него могут ссылаться из любой части приложения.
Stack (стек) – это область хранения данных также находится в общей оперативной памяти
(RAM). Всякий раз, когда вызывается метод, в памяти стека создается новый блок, который содержит примитивы и ссылки на другие объекты в методе. Как только метод заканчивает работу, блок перестает использоваться, тем самым предоставляя доступ для следующего метода. Размер стековой памяти намного меньше объема памяти в куче. Стек в Java работает по схеме LIFO (последний-зашел-первый-вышел).
Различия между Heap и Stack памятью:
 куча используется всеми частями приложения, в то время как стек используется только одним потоком исполнения программы;
 всякий раз, когда создается объект, он всегда хранится в куче, а в памяти стека содержится лишь ссылка на него, память стека содержит только локальные переменные примитивных типов и ссылки на объекты в куче;
 объекты в куче доступны из любой точки программы, в то время как стековая память не может быть доступна для других потоков;
 стековая память существует лишь какое-то время работы программы, а память в куче живет с самого начала до конца работы программы;
 если память стека полностью занята, то Java Runtime бросает исключение
java.lang.StackOverflowError, если заполнена память кучи, то бросается исключение
java.lang.OutOfMemoryError: Java Heap Space;
 размер памяти стека намного меньше памяти в куче;
 из-за простоты распределения памяти стековая память работает намного быстрее кучи.
Для определения начального и максимального размера памяти в куче используются опции
JVM -Xms и -Xmx. Для стека определить размер памяти можно с помощью опции -Xss.
Верно ли утверждение, что примитивные типы данных всегда хранятся в
стеке, а экземпляры ссылочных типов данных – в куче?
Не совсем. Примитивное поле экземпляра класса хранится не в стеке, а в куче. Любой объект (все, что явно или неявно создается при помощи оператора new) хранится в куче.

Ключевые слова
abstract
, assert, break, case, catch, class, const*, continue, default, do, else, enum, extends, final,
finally, for, goto*, if, implements, import, instanceof, interface, native, new, package, return, static,
strictfp, super, switch, synchronized, this, throw, throws, transi ent, try, void, volatile, while.
* – зарезервированное слово, не используется.
Для чего используется оператор assert?
Assert (утверждение) – это специальная конструкция, позволяющая проверять предположения о значениях произвольных данных в произвольном месте программы.
Утверждение может автоматически сигнализировать об обнаружении некорректных данных,
что обычно приводит к аварийному завершению программы с указанием места обнаружения некорректных данных.
Утверждения существенно упрощают локализацию ошибок в коде. Даже проверка результатов выполнения очевидного кода может оказаться полезной при последующем рефакторинге, после которого код может стать не настолько очевидным и в него может закрасться ошибка.
Обычно утверждения оставляют включенными во время разработки и тестирования программ, но отключают в релиз-версиях программ.
Т. к. утверждения могут быть удалены на этапе компиляции либо во время исполнения программы, они не должны менять поведение программы. Если в результате удаления утверждения поведение программы может измениться, то это явный признак неправильного использования assert. Таким образом, внутри assert нельзя вызывать методы, изменяющие состояние программы, либо внешнего окружения программы.
В Java проверка утверждений реализована с помощью оператора assert, который имеет форму:
assert [Выражение типа boolean]; или assert [Выражение типа boolean] : [Выражение
любого типа, кроме void];
Во время выполнения программы в том случае, если проверка утверждений включена,
вычисляется значение булевского выражения, и если его результат false, то генерируется исключение java.lang.AssertionError. В случае использования второй формы оператора assert выражение после двоеточия задает детальное сообщение о произошедшей ошибке
(вычисленное выражение будет преобразовано в строку и передано конструктору
AssertionError).
Какие примитивные типы данных есть в Java?
Числа инициализируются 0 или 0.0;
char – \u0000;
boolean – false;
Объекты (в том числе String) – null.

Что такое char?
16-разрядное беззнаковое целое, представляющее собой символ UTF-16 (буквы и цифры).
Сколько памяти занимает boolean?
Зависит от реализации JVM: минимум 1 байт в массивах, 4 байта в коде.
Логические операторы
&: Логическое AND (И);
&&: Сокращенное AND;
|: Логическое OR (ИЛИ);
||: Сокращенное OR;
^: Логическое XOR (исключающее OR (ИЛИ));
!: Логическое унарное NOT (НЕ);
&=: AND с присваиванием;
|=: OR с присваиванием;
^=: XOR с присваиванием;
==: Равно;
!=: Не равно;
?:: Тернарный (троичный) условный оператор.
Тернарный условный оператор
Оператор, которым можно заменить некоторые конструкции операторов if-then-else.
Выражение записывается в следующей форме:
условие ? выражение1 : выражение2
Если условие выполняется, то вычисляется выражение1 и его результат становится результатом выполнения всего оператора. Если же условие равно false, то вычисляется
выражение2 и его значение становится результатом работы оператора. Оба операнда выражение1 и выражение2 должны возвращать значение одинакового (или совместимого)
типа.
Какие побитовые операции вы знаете?

: Побитовый унарный оператор NOT;
&: Побитовый AND;

&=: Побитовый AND с присваиванием;
|: Побитовый OR;
|=: Побитовый OR с присваиванием;
^: Побитовый исключающее XOR;
^=: Побитовый исключающее XOR с присваиванием;
>>: Сдвиг вправо (деление на 2 в степени сдвига);
>>=: Сдвиг вправо с присваиванием;
>>>: Сдвиг вправо без учета знака;
>>>=: Сдвиг вправо без учета знака с присваиванием;
<<: Сдвиг влево (умножение на 2 в степени сдвига);
<<=: Сдвиг влево с присваиванием.
Что такое классы-обертки?
Обертка – это специальный класс, который хранит внутри себя значение примитива. Нужны для реализации дженериков (или коллекций), объектов.
Что такое автоупаковка и автораспаковка?
Автоупаковка – присвоение классу обертки значения примитивного типа.
Автораспаковка – присвоение переменной примитивного типа значение класса обертки.
Необходимы для присваивания ссылок-примитивов объектам их классов-оберток (и наоборот). Не требуется ничего делать, все происходит автоматически.
Автоупаковка – это механизм неявной инициализации объектов классов-оберток (Byte, Short,
Integer, Long, Float, Double, Character, Boolean) значениями соответствующих им исходных примитивных типов (byte, short, int...), без явного использования конструктора класса.
Автоупаковка происходит при прямом присваивании примитива классу-обертке (с помощью оператора =), либо при передаче примитива в параметры метода (типа класса-обертки).
Автоупаковке в классы-обертки могут быть подвергнуты как переменные примитивных типов,
так и константы времени компиляции (литералы и final-примитивы). При этом литералы должны быть синтаксически корректными для инициализации переменной исходного примитивного типа.
Автоупаковка переменных примитивных типов требует точного соответствия типа исходного примитива типу класса-обертки. Например, попытка упаковать переменную типа byte в Short без предварительного явного приведения byte в short вызовет ошибку компиляции.
Автоупаковка констант примитивных типов допускает более широкие границы соответствия.
В этом случае компилятор способен предварительно осуществлять неявное расширение/сужение типа примитивов:

неявное расширение/сужение исходного типа примитива до типа примитива соответствующего классу-обертке (для преобразования int в Byte сначала компилятор самостоятельно неявно сужает int к byte);


автоупаковку примитива в соответствующий класс-обертку. Однако, в этом случае существуют два дополнительных ограничения: a) присвоение примитива обертке может производится только оператором = (нельзя передать такой примитив в параметры метода без явного приведения типов) b) тип левого операнда не должен быть старше чем Character, тип правого не должен старше, чем int:
допустимо расширение/сужение byte в/из short, byte в/из char, short в/из char и только сужение byte из int, short из int, char из int. Все остальные варианты требуют явного приведения типов).
Дополнительной особенностью целочисленных классов-оберток, созданных автоупаковкой констант в диапазоне -128 ... +127, является то, что они кешируются JVM. Поэтому такие обертки с одинаковыми значениями будут являться ссылками на один объект.
Что такое явное и неявное приведение типов? В каких случаях в java нужно
использовать явное приведение?
Java является строго типизированным языком программирования, а это означает, что каждое выражение и каждая переменная имеет строго определенный тип уже на момент компиляции. Однако определен механизм приведения типов (casting) – способ преобразования значения переменной одного типа в значение другого типа.
В Java существуют несколько разновидностей приведения:
Тождественное (identity). Преобразование выражения любого типа к точно такому же типу всегда допустимо и происходит автоматически.
Расширение (повышение, upcasting) примитивного типа (widening primitive). Означает, что осуществляется переход от менее емкого типа к более емкому. Например, от типа byte
(длина 1 байт) к типу int (длина 4 байта). Такие преобразование безопасны в том смысле, что новый тип всегда гарантировано вмещает в себя все данные, которые хранились в старом типе, и таким образом не происходит потери данных. Этот тип приведения всегда допустим и происходит автоматически.
Сужение (понижение, downcasting) примитивного типа (narrowing primitive). Означает, что переход осуществляется от более емкого типа к менее емкому. При таком преобразовании есть риск потерять данные. Например, если число типа int было больше 127, то при приведении его к byte значения битов старше восьмого будут потеряны. В Java такое преобразование должно совершаться явным образом, при этом все старшие биты, не умещающиеся в новом типе, просто отбрасываются – никакого округления или других действий для получения более корректного результата не производится.
Расширение объектного типа (widening reference). Означает неявное восходящее приведение типов или переход от более конкретного типа к менее конкретному, т. е. переход от потомка к предку. Разрешено всегда и происходит автоматически.
Сужение объектного типа (narrowing reference). Означает нисходящее приведение, то есть приведение от предка к потомку (подтипу). Возможно только если исходная переменная является подтипом приводимого типа. При несоответствии типов в момент выполнения выбрасывается исключение ClassCastException. Требует явного указания типа.
Преобразование к строке (to String). Любой тип может быть приведен к строке, т. е. к экземпляру класса String.
Запрещенные преобразования (forbidden). Не все приведения между произвольными типами допустимы. Например, к запрещенным преобразованиям относятся приведения от
любого ссылочного типа к примитивному и наоборот (кроме преобразования к строке). Кроме того, невозможно привести друг к другу классы, находящиеся на разных ветвях дерева наследования и т. п.
При приведении ссылочных типов с самим объектом ничего не происходит, меняется лишь тип ссылки, через которую происходит обращение к объекту.
Для проверки возможности приведения нужно воспользоваться оператором instanceof:
Parent parent = new Child();
if (parent instanceof Child) {
Child child = (Child) parent;
}
Когда в приложении может быть выброшено исключение
ClassCastException?
ClassCastException (потомок RuntimeException) – исключение, которое будет выброшено при ошибке приведения типа.
Что такое пул интов?
В классе-обертке Integer есть внутренний класс IntegerCache – пул (pool) целых чисел в промежутке [-128; 127], так как это самый часто встречающийся диапазон. Он объявлен как private static. В этом внутреннем классе кешированные объекты находятся в массиве cache[].
Кеширование выполняется при первом использовании класса-обертки. После первого использования вместо создания нового экземпляра (кроме использования конструктора),
используются кешированные объекты, JVM берет их из пула.
Можно ли изменить размер пула int?
Не из кода, а в параметре JVM.
Какие еще есть пулы примитивов?
У всех целочисленных и char, но размеры изменять нельзя, можно только у int.
Какие есть особенности класса String?

это неизменяемый (immutable) и финализированный тип данных;

все объекты класса String JVM хранит в пуле строк;

объект класса String можно получить, используя двойные кавычки;

можно использовать оператор + для конкатенации строк;

начиная с Java 7, строки можно использовать в конструкции switch.
Что такое «пул строк»?
Пул строк – это набор строк, хранящийся в Heap.

пул строк возможен благодаря неизменяемости строк в Java и реализации идеи интернирования строк;


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

если для создания строки используются ", то сначала ищется строка в пуле с таким же значением, если находится, то просто возвращается ссылка, иначе создается новая строка в пуле, а затем возвращается ссылка на нее;

при использовании оператора new создается новый объект String, затем при помощи метода intern() эту строку можно поместить в пул или же получить из пула ссылку на другой объект String с таким же значением;

пул строк является примером паттерна «Приспособленец» (Flyweight).
Почему не рекомендуется изменять строки в цикле? Что рекомендуется
использовать?
Строка – неизменяемый класс, поэтому растет потребление ресурсов при редактировании,
т. к. при каждой итерации будет создаваться новый объект строки. Рекомендуется
использовать StringBuilder.
Почему char[] предпочтительнее String для хранения пароля?
С момента создания строка остается в пуле до тех пор, пока не будет удалена сборщиком мусора. Поэтому даже после окончания использования пароля он некоторое время продолжает оставаться доступным в памяти и способа избежать этого не существует. Это представляет определенный риск для безопасности, поскольку кто-либо, имеющий доступ к памяти, сможет найти пароль в виде текста. В случае использования массива символов для хранения пароля имеется возможность очистить его сразу по окончанию работы с паролем,
позволяя избежать риска безопасности, свойственного строке.
Почему String неизменяемый и финализированный класс?
Есть несколько преимуществ в неизменности строк:

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

Если строка будет изменяемой, тогда это станет серьезной угрозой
1   2   3   4   5   6   7   8   9   ...   25


написать администратору сайта