Java core Flashcards
Чем различаются JRE, JVM и JDK?
JVM, Java Virtual Machine (Виртуальная машина Java) — основная часть среды времени исполнения Java (JRE). Виртуальная машина Java исполняет байт-код Java, предварительно созданный из исходного текста Java-программы компилятором Java. JVM может также использоваться для выполнения программ, написанных на других языках программирования.
JRE, Java Runtime Environment (Среда времени выполнения Java) - минимально-необходимая реализация виртуальной машины для исполнения Java-приложений. Состоит из JVM и стандартного набора библиотек классов Java.
JDK, Java Development Kit (Комплект разработки на Java) - JRE и набор инструментов разработчика приложений на языке Java, включающий в себя компилятор Java, стандартные библиотеки классов Java, примеры, документацию, различные утилиты.
Коротко: JDK - среда для разработки программ на Java, включающая в себя JRE - среду для обеспечения запуска Java программ, которая в свою очередь содержит JVM - интерпретатор кода Java программ.
Какие существуют модификаторы доступа?
private (приватный): члены класса доступны только внутри класса. Для обозначения используется служебное слово private.
default, package-private, package level (доступ на уровне пакета): видимость класса/членов класса только внутри пакета. Является модификатором доступа по умолчанию - специальное обозначение не требуется.
protected (защищённый): члены класса доступны внутри пакета и в наследниках. Для обозначения используется служебное слово protected.
public (публичный): класс/члены класса доступны всем. Для обозначения используется служебное слово public.
Последовательность модификаторов по возрастанию уровня закрытости: public, protected, default, private.
Во время наследования возможно изменения модификаторов доступа в сторону большей видимости (для поддержания соответствия принципу подстановки Барбары Лисков).
О чем говорит ключевое слово final?
Модификатор final может применяться к переменным, параметрам методов, полям и методам класса или самим классам.
- Класс не может иметь наследников;
- Метод не может быть переопределен в классах наследниках;
- Поле не может изменить свое значение после инициализации;
- Параметры методов не могут изменять своё значение внутри метода;
- Локальные переменные не могут быть изменены после присвоения им значения.
Какими значениями инициализируются переменные по умолчанию?
- Числа инициализируются 0 или 0.0;
- char — \u0000;
- boolean — false;
- Объекты (в том числе String) — null.
Что вы знаете о функции main()?
Метод main() — точка входа в программу. В приложении может быть несколько таких методов. Если метод отсутствует, то компиляция возможна, но при запуске будет получена ошибка Error: Main method not found
.
public static void main(String[] args) { }
Какие логические операции и операторы вы знаете?
- &: Логическое 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 в степени сдвига);
- «=: Сдвиг влево с присваиванием.
Где и для чего используется модификатор abstract?
Класс, помеченный модификатором abstract, называется абстрактным классом. Такие классы могут выступать только предками для других классов. Создавать экземпляры самого абстрактного класса не разрешается. При этом наследниками абстрактного класса могут быть как другие абстрактные классы, так и классы, допускающие создание объектов.
Метод, помеченный ключевым словом abstract - абстрактный метод, т.е. метод, который не имеет реализации. Если в классе присутствует хотя бы один абстрактный метод, то весь класс должен быть объявлен абстрактным.
Использование абстрактных классов и методов позволяет описать некий шаблон объекта, который должен быть реализован в других классах. В них же самих описывается лишь некое общее для всех потомков поведение.
Дайте определение понятию «интерфейс». Какие модификаторы по умолчанию имеют поля и методы интерфейсов?
Ключевое слово interface используется для создания полностью абстрактных классов. Основное предназначение интерфейса - определять каким образом мы можем использовать класс, который его реализует. Создатель интерфейса определяет имена методов, списки аргументов и типы возвращаемых значений, но не реализует их поведение. Все методы неявно объявляются как public.
Начиная с Java 8 в интерфейсах разрешается размещать реализацию методов по умолчанию default и статических static методов.
Интерфейс также может содержать и поля. В этом случае они автоматически являются публичными public, статическими static и неизменяемыми final.
Чем абстрактный класс отличается от интерфейса? В каких случаях следует использовать абстрактный класс, а в каких интерфейс?
- В Java класс может одновременно реализовать несколько интерфейсов, но наследоваться только от одного класса.
- Абстрактные классы используются только тогда, когда присутствует тип отношений «is a» (является). Интерфейсы могут реализоваться классами, которые не связаны друг с другом.
- Абстрактный класс - средство, позволяющее избежать написания повторяющегося кода, инструмент для частичной реализации поведения. Интерфейс - это средство выражения семантики класса, контракт, описывающий возможности. Все методы интерфейса неявно объявляются как public abstract или (начиная с Java 8) default - методами с реализацией по-умолчанию, а поля - public static final.
- Интерфейсы позволяют создавать структуры типов без иерархии.
- Наследуясь от абстрактного, класс «растворяет» собственную индивидуальность. Реализуя интерфейс, он расширяет собственную функциональность.
Абстрактные классы содержат частичную реализацию, которая дополняется или расширяется в подклассах. При этом все подклассы схожи между собой в части реализации, унаследованной от абстрактного класса, и отличаются лишь в части собственной реализации абстрактных методов родителя. Поэтому абстрактные классы применяются в случае построения иерархии однотипных, очень похожих друг на друга классов. В этом случае наследование от абстрактного класса, реализующего поведение объекта по умолчанию может быть полезно, так как позволяет избежать написания повторяющегося кода. Во всех остальных случаях лучше использовать интерфейсы.
Почему в некоторых интерфейсах вообще не определяют методов?
Это так называемые маркерные интерфейсы. Они просто указывают что класс относится к определенному типу. Примером может послужить интерфейс Clonable, который указывает на то, что класс поддерживает механизм клонирования.
Почему нельзя объявить метод интерфейса с модификатором final?
В случае интерфейсов указание модификатора final бессмысленно, т.к. все методы интерфейсов неявно объявляются как абстрактные, т.е. их невозможно выполнить, не реализовав где-то еще, а этого нельзя будет сделать, если у метода идентификатор final.
Что имеет более высокий уровень абстракции - класс, абстрактный класс или интерфейс?
Интерфейс
Может ли объект получить доступ к члену класса, объявленному как private? Если да, то каким образом?
- Внутри класса доступ к приватной переменной открыт без ограничений;
- Вложенный класс имеет полный доступ ко всем (в том числе и приватным) членам содержащего его класса;
- Доступ к приватным переменным извне может быть организован через отличные от приватных методов, которые предоставлены разработчиком класса. Например: getX() и setX().
- Через механизм рефлексии (Reflection API):
class Victim { private int field = 42; } //... Victim victim = new Victim(); Field field = Victim.class.getDeclaredField("field"); field.setAccessible(true); int fieldValue = (int) field.get(victim); //...
Каков порядок вызова конструкторов и блоков инициализации с учётом иерархии классов?
Сначала вызываются все статические блоки в очередности от первого статического блока корневого предка и выше по цепочке иерархии до статических блоков самого класса.
Затем вызываются нестатические блоки инициализации корневого предка, конструктор корневого предка и так далее вплоть до нестатических блоков и конструктора самого класса.
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
Пример 1:
public class MainClass { public static void main(String args[]) { System.out.println(TestClass.v); new TestClass().a(); } }
public class TestClass { public static String v = "Some val"; { System.out.println("!!! Non-static initializer"); } static { System.out.println("!!! Static initializer"); } public void a() { System.out.println("!!! a() called"); } }
Результат выполнения:
!!! Static initializer Some val !!! Non-static initializer !!! a() called
Пример 2:
public class MainClass { public static void main(String args[]) { new TestClass().a(); } }
public class TestClass { public static String v = "Some val"; { System.out.println("!!! Non-static initializer"); } static { System.out.println("!!! Static initializer"); } public void a() { System.out.println("!!! a() called"); } }
Результат выполнения:
!!! Static initializer !!! Non-static initializer !!! a() called
Зачем нужны и какие бывают блоки инициализации?
Блоки инициализации представляют собой код, заключенный в фигурные скобки и размещаемый внутри класса вне объявления методов или конструкторов.
- Существуют статические и нестатические блоки инициализации.
- Блок инициализации выполняется перед инициализацией класса загрузчиком классов или созданием объекта класса с помощью конструктора.
- Несколько блоков инициализации выполняются в порядке следования в коде класса.
- Блок инициализации способен генерировать исключения, если их объявления перечислены в throws всех конструкторов класса.
- Блок инициализации возможно создать и в анонимном классе.
К каким конструкциям Java применим модификатор static?
- полям;
- методам;
- вложенным классам;
- блокам инициализации;
- членам секции import.
Для чего в Java используются статические блоки инициализации?
Статические блоки инициализация используются для выполнения кода, который должен выполняться один раз при инициализации класса загрузчиком классов, в момент, предшествующий созданию объектов этого класса при помощи конструктора. Такой блок (в отличие от нестатических, принадлежащих конкретном объекту класса) принадлежит только самому классу (объекту метакласса Class).
Что произойдёт, если в блоке инициализации возникнет исключительная ситуация?
Для нестатических блоков инициализации, если выбрасывание исключения прописано явным образом требуется, чтобы объявления этих исключений были перечислены в throws всех конструкторов класса. Иначе будет ошибка компиляции. Для статического блока выбрасывание исключения в явном виде, приводит к ошибке компиляции.
В остальных случаях, взаимодействие с исключениями будет проходить так же, как и в любом другом месте. Класс не будет инициализирован, если ошибка происходит в статическом блоке и объект класса не будет создан, если ошибка возникает в нестатическом блоке.
Какое исключение выбрасывается при возникновении ошибки в блоке инициализации класса?
Если возникшее исключение - наследник RuntimeException:
- для статических блоков инициализации будет выброшено java.lang.ExceptionInInitializerError;
- для нестатических будет проброшено исключение-источник.
Если возникшее исключение - наследник Error, то в обоих случаях будет выброшено java.lang.Error. Исключение: java.lang.ThreadDeath - смерть потока. В этом случае никакое исключение выброшено не будет.
Может ли статический метод быть переопределён или перегружен?
Перегружен - да. Всё работает точно так же, как и с обычными методами - 2 статических метода могут иметь одинаковое имя, если количество их параметров или типов различается.
Переопределён - нет. Выбор вызываемого статического метода происходит при раннем связывании (на этапе компиляции, а не выполнения) и выполняться всегда будет родительский метод, хотя синтаксически переопределение статического метода - это вполне корректная языковая конструкция.
В целом, к статическим полям и методам рекомендуется обращаться через имя класса, а не объект.
Могут ли нестатические методы перегрузить статические?
Да. В итоге получится два разных метода. Статический будет принадлежать классу и будет доступен через его имя, а нестатический будет принадлежать конкретному объекту и доступен через вызов метода этого объекта.
Можно ли сузить уровень доступа/тип возвращаемого значения при переопределении метода?
- При переопределении метода нельзя сузить модификатор доступа к методу (например с public в MainClass до private в Class extends MainClass).
- Изменить тип возвращаемого значения при переопределении метода нельзя, будет ошибка attempting to use incompatible return type.
- Можно сузить возвращаемое значение, если они совместимы.
Например:
public class Animal { public Animal eat() { System.out.println("animal eat"); return null; } public Long calc() { return null; } } public class Dog extends Animal { public Dog eat() { return new Dog(); } /*attempting to use incompatible return type public Integer calc() { return null; } */ }