Java Интервью Вопросы

Java интервью вопросы

1. Вступление

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

2. Core-Java Language Вопросы для начинающих

Q1. Данные передаются по ссылке или по значению в Java?

Хотя ответ на этот вопрос довольно прост, этот вопрос может сбить с толку новичков. Во-первых, давайте проясним, о чем идет речь:

  1. Passing by value – означает, что мы передаемa copy of an object в качестве параметра в метод.

  2. Passing by reference – означает, что мы передаемa reference to an object в качестве параметра в метод.

Чтобы ответить на вопрос, мы должны проанализировать два случая. Они представляют два типа данных, которые мы можем передать методу: примитив и объект.

Когда мы передаем примитивы методу, его значение копируется в новую переменную. Когда дело доходит до объектов, значение ссылки копируется в новую переменную. So we can say that Java is a strictly pass-by-value language.с

Мы можем узнать больше об этом в одной из наших статей:Pass-By-Value as a Parameter Passing Mechanism in Java.

Q2. В чем разница между импортом и статическим импортом?

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

import java.util.ArrayList; //specific class
import java.util.*; //all classes in util package

Мы также можем использовать их для импорта открытых вложенных классов включающего класса:

import com.example.A.*

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

Есть также статический импорт, который позволяет нам импортировать статические члены или вложенные классы:

import static java.util.Collections.EMPTY_LIST;

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

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

ВJava есть четыре модификатора доступа:

  1. частный

  2. default (упаковка)

  3. защищенный

  4. общественности

The private modifier assures that class members won’t be accessible outside the class. Его можно применять к методам, свойствам, конструкторам, вложенным классам, но не к самим классам верхнего уровня.

В отличие от модификатораprivate, мы можем применить модификаторdefault ко всем типам членов класса и к самому классу. Мы можем применить видимостьdefault, вообще не добавляя никаких модификаторов доступа. If we use default visibility our class or its members will be accessible only inside the package of our class.  Следует помнить, что модификатор доступа по умолчанию не имеет ничего общего с ключевым словомdefault.

Подобно модификаторуdefault, все классы в одном пакете могут обращаться к членамprotected. What’s more, the protected modifier allows subclasses to access the protected members of a superclass, even if they are not within the same package. Мы не можем применять этот модификатор доступа к классам, только к членам класса.

Модификаторpublic можно использовать вместе с ключевым словом class и всеми членами класса. It makes classes and class members accessible in all packages and by all classes.

Мы можем узнать больше в статьеJava Access Modifiers.

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

В Java доступно пять других модификаторов:

  • статический

  • окончательный

  • Аннотация

  • синхронизированный

  • летучий

Они не контролируют видимость.

Прежде всего, мы можем применить ключевое словоstatic к полям и методам. Static fields or methods are class members, whereas non-static ones are object members. Членам класса не нужно вызывать никаких экземпляров. Они вызываются с именем класса вместо имени ссылки на объект. This article более подробно описывает ключевое словоstatic.

Затем у нас есть ключевое словоfinal. Мы можем использовать его с полями, методами и классами. When final is used on a field, it means that the field reference cannot be changed. Значит, его нельзя переназначить другому объекту. When final is applied to a class or a method, it assures us that that class or method cannot be extended or overridden. Ключевое словоfinal более подробно объясняется вthis article.

Следующее ключевое слово -abstract. Этот может описать классы и методы. When classes are abstract, they can’t be instantiated. Вместо этого они предназначены для подкласса. Когда методыabstract, они остаются без реализации и могут быть переопределены в подклассах.

Ключевое словоsynchronized может быть самым продвинутым. Мы можем использовать его как с экземпляром, так и со статическими методами и блоками кода. When we use this keyword, we make Java use a monitor lock to provide synchronization on a given code fragment. Более подробную информацию оsynchronized можно найти вthis article.

Последнее ключевое слово, которое мы собираемся обсудить, - этоvolatile. Мы можем использовать его только вместе с полями экземпляра. It declares that the field value must be read from and written to main memory – bypassing the CPU cache. Все операции чтения и записи изменчивой переменной являются атомарными. Ключевое слово volatile подробно объясняется вthis article.

Q5. В чем разница между JDK, JRE и JVM?

JDK означаетJava Development Kit, который представляет собой набор инструментов, необходимых разработчикам для написания приложений на Java. Существует три типа сред JDK:

  • Standard Edition - комплект разработчика для создания портативных настольных или серверных приложений

  • Enterprise Edition - расширение Standard Edition с поддержкой распределенных вычислений или веб-сервисов.

  • Micro Edition - платформа для разработки встраиваемых и мобильных приложений

В JDK есть множество инструментов, которыеhelp programmers with writing, debugging or maintaining applications. Наиболее популярные из них - компилятор (javac), интерпретатор (java), архиватор (jar) и генератор документации (javadoc).

JRE - этоJava Runtime Environment. Это часть JDK, ноit contains the minimum functionality to run Java applications. Он состоит изJava Virtual Machine, основных классов и вспомогательных файлов. Например, у него нет компилятора.

JVM - это аббревиатураJava Virtual Machine, которая представляет собой виртуальную машину, способную запускать программы, скомпилированные в байт-код. Это описано в спецификации JVM, поскольку важно обеспечить совместимость между различными реализациями. The most important function of a JVM is to enable users to deploy the same Java application into different operating systems and environments without worrying about what lies underneath.

Дополнительную информацию можно найти в статьеDifference Between JVM, JRE, and JDK.

Q6. Какая разница между стеком и кучей?

Есть две части памяти, где все переменные и объекты хранятся в JVM. Первый -stack, а второй -heap.

stack is a place where the JVM reserves blocks for local variables and additional data. Стек представляет собой структуруLIFO (последний пришел - первый ушел). Это означает, что всякий раз, когда вызывается метод, новый блок резервируется для локальных переменных и ссылок на объекты. Каждый новый вызов метода резервирует следующий блок. Когда методы заканчивают свое выполнение, блоки освобождаются в обратном порядке, в котором они были запущены.

Каждый новый поток имеет свой собственный стек.

Мы должны знать, что в стеке гораздо меньше места, чем в куче. И когда стек заполнен, JVM выдастStackOverflowError. Это может произойти, когда есть плохой рекурсивный вызов, и рекурсия заходит слишком глубоко.

Every new object is created on the Java heap which is used for a dynamic allocation. Существуетgarbage collector, который отвечает за стирание неиспользуемых объектов, которые делятся на молодые (детские) и старые пространства. Доступ к памяти в куче медленнее, чем доступ к стеку. JVM выдаетOutOfMemoryError, когда куча заполнена.

Мы можем найти более подробную информацию в статьеStack Memory and Heap Space in Java.

Q7. В чем разница между интерфейсамиComparable andComparator?

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

Сначала посмотрим на интерфейсComparable:

public interface Comparable {
    int compareTo(T var1);
}

Мы должны реализовать этот интерфейс с помощью класса, чьи объекты мы хотим отсортировать.

Он имеет методcompareTo() и возвращает целое число. Он может возвращать три значения: -1, 0 и 1, что означает, что этот объект меньше, равен или больше сравниваемого объекта.

Стоит отметить, что переопределенный методcompareT0() должен согласовываться с методомequals().

С другой стороны, мы можем использовать интерфейсComparator. Его можно передать методамsort() интерфейсаCollection или при создании экземпляров отсортированных коллекций. Вот почему он в основном используется для создания одноразовой стратегии сортировки.

Более того, это также полезно, когда мы используем сторонний класс, который не реализует интерфейс Comparable.

Подобно методуcompareTo(), переопределенные методыcompare() должны соответствовать методуequals(), но они могут дополнительно разрешать сравнение с нулями.

Посетите статьюComparator and Comparable in Java для получения дополнительной информации.

Q8. Что такое типvoid и когда мы его используем?

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

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

Q9. Каковы методы класса объекта и что они делают?

Важно знать, какие методы содержит классObject и как они работают. Это также очень полезно, когда мы хотим переопределить эти методы:

  • clone() - возвращает копию этого объекта

  • equals() - возвращаетtrue, когда этот объект равен объекту, переданному в качестве параметра

  • finalize() - сборщик мусора вызывает этот метод во время очистки памяти

  • getClass() - возвращает класс времени выполнения этого объекта

  • hashCode() - возвращает хеш-код этого объекта. We should be aware that it should be consistent with the equals() method

  • notify() - отправляет уведомление одному потоку, ожидающему монитора объекта

  • notifyAll() - отправляет уведомление всем потокам, ожидающим монитора объекта

  • toString() - возвращает строковое представление этого объекта

  • wait() - существует три перегруженных версии этого метода. Он заставляет текущий поток ждать указанное количество времени, пока другой поток не вызоветnotify() илиnotifyAll() для этого объекта.

Q10. Что такое Enum и как мы можем его использовать?

Enum - это тип класса, который позволяет разработчикам указывать набор предопределенных постоянных значений. Чтобы создать такой класс, мы должны использовать ключевое словоenum. Представим себе перечисление дней недели:

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

Чтобы перебрать все константы, мы можем использовать статический методvalues(). Более того, перечисления позволяют нам определять такие члены, как свойства и методы, такие как обычные классы.

Although it’s a special type of class, we can’t subclass it. Однако перечисление может реализовывать интерфейс.

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

Мы можем найти больше о Enums вone of our guides.

Q11. Что такое JARa?

JAR  - это ярлык дляJava archive. Это архивный файл, упакованный в формате ZIP. Мы можем использовать его для включения файлов классов и вспомогательных ресурсов, необходимых для приложений. У этого есть много особенностей:

  • Security – мы можем подписывать JAR файлы цифровой подписью

  • Compression – при использовании JAR, мы можем сжимать файлы для эффективного хранения

  • Portability – мы можем использовать один и тот же файл JAR на нескольких платформах

  • JAR-файлыVersioning – могут содержать метаданные о файлах, которые они содержат

  • Sealing – мы можем запечатать пакет в файле JAR. Это означает, что все классы из одного пакета должны быть включены в один файл JAR

  • Extensions – мы можем использовать формат файла JAR для упаковки модулей или расширений существующего программного обеспечения.

Q12. Что такоеaNullPointerException?

NullPointerException, вероятно, является наиболее частым исключением в мире Java. Это непроверенное исключение, поэтому оно расширяетRuntimeException. Мы не должны пытаться с этим справиться.

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

  • вызов метода нулевой ссылки

  • установка или получение поля нулевой ссылки

  • проверка длины ссылки на нулевой массив

  • установка или получение элемента ссылки на нулевой массив

  • бросаетnull

Q13. Что такое два типа приведения в Java? Какое исключение может быть брошено во время каста? Как мы можем избежать этого?

Мы можем выделить два типа приведения в Java. We can do upcasting which is casting an object to a supertype or downcasting which is casting an object to a subtype.с

Upcasting очень просто, так как мы всегда можем это сделать. Например, мы можем преобразовать экземплярString в типObject:

Object str = "string";

В качестве альтернативы мы можемdowncast переменную. Это не так безопасно, как повышение качества, поскольку предполагает проверку типа. Если мы неправильно приведем объект, JVM выдастClassCastExcpetion во время выполнения. Fortunately, we can use the instanceof keyword to prevent invalid casting:

Object o = "string";
String str = (String) o; // it's ok

Object o2 = new Object();
String str2 = (String) o2; // ClassCastException will be thrown

if (o2 instanceof String) { // returns false
    String str3 = (String) o2;
}

Мы можем узнать больше о приведении типовin this article.

3. Core-Java Language Вопросы для продвинутых программистов

Q1. Почему String является неизменным классом?

Мы должны знать, что объектыString обрабатываютсяJVM иначе, чем другие объекты. Одно отличие состоит в том, что объектыString неизменяемы. It means that we can’t change them once we have created them. Есть несколько причин, по которым они так себя ведут:

  1. Они хранятся вstring pool, который является специальной частью кучи. Он отвечает за экономию много места.

  2. Неизменность классаString гарантирует, что его хэш-код не изменится. Due to that fact, Strings can be effectively used as keys in hashing collections. Мы можем быть уверены, что не перезапишем какие-либо данные из-за изменения хэш-кодов.

  3. Их можно безопасно использовать в нескольких потоках. No thread can change the value of a String object, so we get thread safety for free.с

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

Мы можем узнать больше о неизменности Stringsin this article.

Q2. В чем разница между динамическим и статическим связыванием?

Связывание в Java - это процесс связывания вызова метода с правильным телом метода. Мы можем различить два типа привязки в Java: статическое и динамическое.

Основное различие между статической привязкой и динамической привязкой заключается в том, что статическая привязка происходит во время компиляции, а динамическая - во время выполнения.

Static binding использует информацию о классе для привязки. Он отвечает за определение членов класса, которые являются методами и переменнымиprivate илиstatic иfinal. Также статическое связывание связывает перегруженные методы.

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

Q3. Что такое JIT?

JIT означает «точно в срок». Это компонент JRE, который работает во время выполнения и увеличивает производительность приложения. Specifically, it’s a compiler which runs just after the program’s start.

Это отличается от обычного компилятора Java, который компилирует код задолго до запуска приложения. JIT может ускорить приложение по-разному.

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

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

Q4. Что такое отражение в Java?

Отражение - очень мощный механизм в Java. Reflection - это механизм языка Java, который позволяет программистам проверять или изменять внутреннее состояние программы (свойства, методы, классы и т. Д.) Во время выполнения. Пакет java.lang.reflect предоставляет все необходимые компоненты для использования отражения.

Используя эту функцию, мы можем получить доступ ко всем возможным полям, методам, конструкторам, которые включены в определение класса. Мы можем получить к ним доступ независимо от их модификатора доступа. Это означает, что, например, мы можем получить доступ к частным пользователям. Для этого нам необязательно знать их имена. Все, что нам нужно сделать, это использовать некоторые статические методыClass.

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

При работе с модулями, начиная с Java 9, мы должны знать, что по умолчанию мы не можем использовать отражение для классов, импортированных из другого модуля. Чтобы другие классы могли использовать отражение для доступа к закрытым членам пакета, мы должны предоставить разрешение «Отражение».

This article более подробно описывает Java Reflection.

Q5. Что такое загрузчик классовa?

classloader - один из наиболее важных компонентов Java. Это часть JRE.

Проще говоря, classloader отвечает за загрузку классов в JVM. Мы можем выделить три типа загрузчиков классов:

  • Bootstrap classloader – загружает основные классы Java. Они находятся в каталоге<JAVA_HOME>/jre/lib

  • Extension classloader – загружает классы, расположенные в<JAVA_HOME>/jre/lib/ext или по пути, определенному свойствомjava.ext.dirs

  • System classloader – загружает классы в путь к классам нашего приложения

Загрузчик классов загружает классы «по запросу». Это означает, что классы загружаются после их вызова программой. Более того, загрузчик классов может загрузить класс с заданным именем только один раз. Однако, если один и тот же класс загружается двумя разными загрузчиками классов, эти классы не проходят проверку на равенство.

Подробнее о загрузчиках классов читайте в статьеClass Loaders in Java.

Q6. В чем разница между статической и динамической загрузкой классов?

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

Под динамической загрузкой класса понимается ситуация, когда мы не можем предоставить определение класса во время компиляции. Тем не менее, мы можем сделать это во время выполнения. Чтобы создать экземпляр класса, мы должны использовать методClass.forName():

Class.forName("oracle.jdbc.driver.OracleDriver")

Q7. Какова цель интерфейсаSerializable?

We can use the Serializable interface to enable serializability of a class, using Java’s Serialization API. Сериализация - это механизм для сохранения состояния объекта в виде последовательности байтов, в то время как десериализация - это механизм для восстановления состояния объекта из последовательности байтов. Сериализованный вывод содержит состояние объекта и некоторые метаданные о типе объекта и типах его полей.

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

  • реализовать интерфейсSerializable

  • убедитесь, что в суперклассе присутствует конструктор без аргументов

Мы можем узнать больше о сериализации вone of our articles.

Q8. Есть ли деструктор в Java?

В Java сборщик мусора автоматически удаляет неиспользуемые объекты, чтобы освободить память. Разработчикам не нужно отмечать объекты для удаления, что подвержено ошибкам. So it’s sensible Java has no destructors available.с

Если объекты содержат открытые сокеты, открытые файлы или соединения с базой данных,the garbage collector is not able to reclaim those resources. Мы можем освободить ресурсы в методеclose  и использоватьtry-finally syntax для вызова метода позже, до Java 7, например, классы ввода-выводаFileInputStreamandFileOutputStream. As of Java 7, we can implement interface AutoCloseable and use try-with-resources statement to write shorter and cleaner code. Но возможно, что пользователи API забывают вызвать методclose , поэтому появляются методыfinalize  и классCleaner , которые действуют как страховочная сетка. But please be cautioned they are not equivalent to the destructor.с

It’s not assured both the finalize method and Cleaner class will run promptly. У них даже нет возможности запуститься до выхода из JVM. Хотя мы могли бы вызватьSystem.runFinalization to, предлагая JVM запускать методыfinalize  для любых объектов, ожидающих завершения, это все равно недетерминировано.

Более того, методfinalize может вызвать проблемы с производительностью, взаимоблокировки и т. Д. Дополнительную информацию можно найти в одной из наших статей:A Guide to the finalize Method in Java.

As of Java 9,Cleaner class is added to replace the finalize method из-за его недостатков. В результате мы лучше контролируем нить, которая выполняет очистительные действия.

Но спецификация java указывает на поведение очистителей во время реализацииSystem.exit is, а Java не дает никаких гарантий, будут ли вызваны действия очистки или нет.