JAVA CORE » История » Редакция 5
Редакция 4 (Александр Александров, 19.04.2019 15:44) → Редакция 5/24 (Александр Александров, 19.04.2019 15:50)
h1. JAVA CORE h2. Вопросы # Чем отличается JRE, JVM и JDK? # Опишите модификаторы доступа в Java. # Что такое package level access. # Чем абстрактный клас отличается от интерфейса? В каких случаях Вы бы использовали абстрактный класс, а в каких интерфейс? # Может ли объект получить доступ к private-переменной класса? Если, да, то каким образом? # Для чего в джаве статические блоки? # Можно ли перегрузить static метод? # Расскажите про внутренние классы. Когда вы их будете использовать? # В чем разница между переменной экземпляра и статической переменной? Приведите пример. # Приведите пример когда можно использовать статический метод? # Расскажите про классы- загрузчики и про динамическую зарузку классов. # Что такое статическая и что такое динамическая загрузка класса? # Для чего нужен оператор "assert" в джава? # Почему в некоторых интерфейсах вообще не определяют методов? # Какая основная разница между String, StringBuffer, StringBuilder? # Расскажите про потоки ввода-вывода Java. # Что такое Heap и Stack память в Java? # Какая разница между Stack и Heap памятью в Java? # Расскажите про модель памяти в джава? # Как работает сборщик мусора (garbage collector)? # Расскажите про приведение типов. Что такое понижение и повышение типа? Когда вы получаете ClassCastException? # Что такое статический класс, какие особенности его использования? # Каким образом из вложенного класса получить доступ к полю внешнего класса. # Какие существуют типы вложенных классов? Для чего они используются? # Возможно ли при переопределении (override) метода изменить: ## Модификатор доступа ## Возвращаемый тип ## Тип аргумента или количество ## Имя аргументов # Изменять порядок, количество или вовсе убрать секцию throws? # Что такое autoboxing? # Что такое Generics? # Какова истинная цель использования обобщенных типов в Java? # Каким образом передаются переменные в методы, по значению или по ссылке? # Какие методы есть у класса Object? # Правила переопределения метода Object.equals(). # Если вы хотите переопределить equals(), какие условия должны удовлетворяться для переопределенного метода? # Какая связь между hashCode и equals? # Каким образом реализованы методы hashCode и equals в классе Object? # Что будет, если переопределить equals не переопределяя hashCode? Какие могут возникнуть проблемы? # Есть ли какие-либо рекомендации о том, какие поля следует использовать при подсчете hashCode? # Для чего нужен метод hashCode()? # Правила переопределения метода Object.hashCode(). # Расскажите про клонирование объектов. В чем отличие между поверхностным и глубоким клонированием? # Правила переопределения метода Object.clone(). # Где и как вы можете использовать закрытый конструктор? # Что такое конструктор по умолчанию? # Опишите метод Object.finalize(). # Чем отличаются слова final, finally и finalize? # Опишите иерархию исключений. # Какие виды исключений в Java вы знаете, чем они отличаются? # Что такое checked и unchecked Exception? # Как создать свой unchecked Exception? # Какие есть Unchecke exeption? # Что такое Error? # Опишите работу блока try-catch-finally. # Возможно ли использование блока try-finally (без catch)? # Всегда ли исполняется блок finally? # Какие есть особенности класса String? что делает метод intern(). # Можно ли наследовать строковый тип, почему? # Почему строка является популярным ключом в HashMap в Java? # Дайте определение понятию конкатенация строк. # Как перевернуть строку? # Как сравнить значение двух строк? # Как обрезать пробелы в начале и конце строки? # Дайте определение понятию "пул строк". # Можно ли синхронизировать доступ к строке? # Как правильно сравнить значения строк двух различных объектов типа String и StringBuffer? # Почему строка неизменная и финализированная в Java? # Напишите метод удаления данного символа из строки. # Что такое рефлексия? # Что произойдет со сборщиком мусора (GC), если во время выполнения метода finalize() некоторого объекта произойдет исключение? # Что такое интернационализация, локализация? # Что такое Аннотации в Java? # Какие функции выполняет Аннотации? # Какие встроенные аннотации в Java вы знаете? # Что делают аннотации @Retention, @Documented, @Target и @Inherited? # Что делают аннотации @Override, @Deprecated, @SafeVarargs и @SuppressWarnings? # Какой жизненный цикл аннотации можно указать с помощью @Retention? # К каким элементам можно применять аннотацию, как это указать? # Как создать свою Аннотацию? # Атрибуты каких типов допустимы в аннотациях? # Что такое JMX? # Какие выгоды предлагает JMX? # Что еще умеет JMX кроме дистанционного управления? # Что такое MBean? # Какие типы MBeans существуют? # Что такое MBean Server? # Какие механизмы обеспечивают безопасность в технологии Java? # Назовите несколько видов проверок которые выполняет верификатор байт-кода Java? # Что вы знаете о "диспетчере защиты" в Java? # Что такое JAAS? # Что такое Рефакторинг? h2. Ответы h3. Чем отличается JRE, JVM и JDK? JRE кратко - для работы. Java Runtime Environment (сокр. JRE) - минимальная реализация виртуальной машины, необходимая для исполнения Java-приложений, без компилятора и других средств разработки. Состоит из виртуальной машины - Java Virtual Machine и библиотеки Java-классов. JDK кратко - для программирования. Java Development Kit (сокращенно JDK) - бесплатно распространяемый компанией Oracle Corporation (ранее Sun Microsystems) комплект разработчика приложений на языке Java, включающий в себя компилятор Java (javac), стандартные библиотеки классов Java, примеры, документацию, различные утилиты и исполнительную систему Java (JRE). Java Virtual Machine (сокращенно Java VM, JVM) - виртуальная машина Java - основная часть исполняющей системы Java, так называемой Java Runtime Environmen (JRE). Виртуальная машина Java интерпретирует Байт-код Java, предварительно созданный из исходного текста Java-программы компилятором Java (javac). JVM может также использоваться для выполнения программ, написанных на других языках программирования. h3. Опишите модификаторы доступа в Java. В Java существуют следующие модификаторы доступа: * private: (используется конструкторах, внутренних классах, методах и полях класса) - Доступ разрешен только в текущем классе. * default (package-private): (используется в классах, конструкторах, интерфейсах, внутренних классах, методах и полях класса) - Доступ на уровне пакета. Если класс будет так объявлен он будет доступен только внутри пакета. * protected: (используется конструкторах, внутренних классах, методах и полях класса) Модификатор доступа на уровне пакета и в иерархии наследования. * public: (используется в классах, конструкторах, интерфейсах, внутренних классах, методах и полях класса) - Модификатор доступа общественный, доступен всем. Последовательность модификаторов по убыванию уровня закрытости: private, default ,protected, public) h3. Что такое package level access. Доступ из классов одного package-а в классы другого package-a. h3. Чем абстрактный клас отличается от интерфейса? В каких случаях Вы бы использовали абстрактный класс, а в каких интерфейс? Абстрактный класс это класс, который помечен как "abstract", он может содержать абстрактные методы, а может их и не содержать. Экземпляр абстрактного класса нельзя создать. Класс, который наследуется от абстрактного класса может реализовывать абстрактные методы, а может и не реализовывать, тогда класс наследник должен быть тоже абстрактным. Также если класс наследник переопределяет реализованный в абстрактном классе родители метод, его можно переопределить с модификатором абстракт! Т.е отказаться от реализации. Соответственно данный класс должен быть также абстрактным также. Что касается интерфейса, то в нем находятся только абстрактные методы и константы, так было до выхода Java 8. Начиная с Java 8 кроме абстрактных методов мы также можем использовать в интерфейсах стандартные методы (default methods) и статические методы (static methods). * Default метод в интерфейсе - это метод в интерфейсе с по умолчанию реализованной логикой, который не требуется обязательно определять в реализации этого интерфейса. * Static методы в интерфейсе - это по существу то же самое, что static-методы в абстрактном классе. При реализации интерфейса, класс обязан реализовать все методы интерфейса. Иначе класс должен быть помечен как абстрактный. Интерфейс также может содержать внутренние классы. И не абстрактные методы в них. Что же использовать Интерфейс или Абстрактный класс? Абстрактный класс используется когда нам нужна какая-то реализация по умолчанию. Интерфейс используется когда классу нужно указать конкретное поведение. Часто интерфейс и абстрактный класс комбинируют, т.е. имплементируют интерфейс в абстрактном классе, чтоб указать поведение и реализацию по умолчанию. Это хорошо видно на примере свига: <pre><code class="java"> class AbstractTableModel implements TableModel { } class MyTableModel extends AbstractTableModel { } </code></pre> Мы создаем свою модель таблицы с определенным поведением и уже с реализацией по умолчанию. *ВАЖНО!* При реализации интерфейса, необходимо реализовать все его методы, иначе будет Fatal error, так же это можно избежать, присвоив слово abstract. Пример: <pre><code class="java"> interface I { public void F(); public void say(); } public abstract class A implements I { @Override public void say() { System.out.println("Hello!"); } // public void F(); - not implenented } </code></pre> h3. Может ли объект получить доступ к private-переменной класса? Если, да, то каким образом? Вообще доступ у приватной переменной класса можно получить только внутри класса, в котором она объявлена. Также доступ к приватным переменным можно осуществить через механизм _Java Reflection API._ h3. Для чего в java статические блоки? Статические блоки в java выполняются до выполнения конструктора, с помощью них инициализируют статические поля к примеру. <pre><code class="java"> static final int i; static { i = 10; } </code></pre> Еще один ньюанс, блок статической инициализации может создаваться сам при компиляции программы. Например: <pre><code class="java"> public static int MAX = 100; </code></pre> Будет создан код: <pre><code class="java"> public static int MAX; static { MAX = 100; } </code></pre> h3. Можно ли перегрузить static метод? Статические методы могут перегружаться нестатическими и наоборот - без ограничений. А вот в переопределении статического метода смысла нет. h3. Расскажите про внутренние классы. Когда вы их будете использовать? Внутренний класс - это класс, который находится внутри класса или интерфейса. При этом он получает доступ ко всем полям и методам своего внешнего класса. Для чего он может применятся? Например чтоб обеспечить какую-то дополнительную логику класса. Хотя использование внутренних классов усложняет программу, рекомендуется избегать их использование. h3. В чем разница между переменной экземпляра и статической переменной? Приведите пример. Статические переменные инициализируются при загрузке класса класслодером, и не зависят от объекта. Переменная экземпляра инициализируется при создании класса. Пример: Например нам нужна глобальная переменная для всех объектов класс, например число посещений пользователей определенной статьи в интернете. При каждом новом посещении статьи создается новый объект и инкрементируется переменная посещений. h3. Приведите пример когда можно использовать статический метод? Статические методы могут быть использованы для инициализации статических переменных. Часто статические методы используются в классах утилитах, таких как Collections, Math, Arrrays h3. Расскажите про классы- загрузчики и про динамическую загрузку классов. Любой класс, используемый в джава программу так или иначе был загружен в контекст программы каким-то загрузчиком. Все виртуальные машины джава включают хотябы один загрузчик классов, так называем базовый загрузчик. Он загружает все основные классы, это классы из rt.jar. Интересно то, что этот загрузчик никак не связан с программой, тоесть мы не можем получить например у java.lang.Object имя зарузчика, метод getClassLoader() вернет нам null. Следующий загрузчик - это загрузчик расширений, он загружает классы из $JAVA_HOME/lib/ext. Далее по иерархии идет системный загрузчик, он загружает классы, путь к которым указан в переменно класпас. Для примера предположим что у нас есть некий пользовательский класс MyClass и мы его используем. Как идет его загрузка : Сначала системный загрузчик пытается найти его в своем кэше загрузок его, если найден - класс успешно загружается, иначе управление загрузкой передается загрузчику расширений, он также проверяет свой кэш загрузок и в случае неудачи передает задачу базовому загрузчику. Тот проверяет кэш и в случае неудачи пытается его загрузить, если загрузка прошла успешно - загрузка закончена. Если нет - передает управление загрузчику расширений. Загрузчик расширений пытается загрузить класс и в случае неудачи передает это дело системному загрузчику. Системный загрузчик пытается загрузить класс и в случае неудачи возбуждается исключение java.lang.ClassNotFoundException. Вот так работает загрузка классов в джава. Так называемое делегирование загрузки. Если в системе присутствуют пользовательские загрузики, то они должны быть унаследованы от класса java.lang.ClassLoader . h3. Что такое статическая и что такое динамическая загрузка класса? Статическая загрузка класса происходит при использовании оператора "new". Динамическая загрузка происходит "на лету" в ходе выполнения программы с помощью статического метода класса Class.forName(имя класса). Для чего нужна динамическая загрузка? Например мы не знаем какой класс нам понадобится и принимаем решение в ходе выполнения программы передавая имя класса в статический метод forName(). h3. Для чего нужен оператор "assert" в джава? Это так называемый оператор утверждений. Он проверяет некое условие, если оно ложно, то генерируется AssertationError assert status: "message error"; Тут проверяется булевская переменная "status". h3. Почему в некоторых интерфейсах вообще не определяют методов? Это так называемые интерфейсы - маркеры. Они просто указывают что класс относится к определенной группе классов. Например интерфейс Clonable указывает на то, что класс поддерживает механизм клонирования. Степень абстракции в данном случае доведен до абсолюта. В интерфейсе вообще нет никаких объявлений. Интерфейси-маркери в Java: * Searilizable interface * Cloneable interface * Remote interface * ThreadSafe interface h3. Какая основная разница между String, StringBuffer, StringBuilder? String - неизменяемый класс, то есть для для добавление данных в уже существующую строку, создается новый объект строки. StringBuffer и StringBuilder могут изменятся и добавление строки не такое дорогостоющее с точки зрения памяти. Первый - синхронизированный, второй - нет. Это их единственное различие. Правда если нам нужно сделать подстроку строки, то лучше использовать String, так как ее массив символов не меняется и не создается заново для новой строки. А вот в StringBuffer и StringBuilder для создания подстроки создается новый массив символов. h3. Расскажите про потоки ввода-вывода Java. Потоки ввода-вывода бывают двух видов: * байтовый поток(InputStream и OutputStream); * символьный поток(Reader и Writer); Это все абстрактные классы - декораторы, которым можно добавлять дополнительный функционал, например: <pre><code class="java"> InputStream in = new FileInputStream(new File("File.txt")); </code></pre> h3. Что такое Heap и Stack память в Java? Java Heap (куча) - динамически распределяемая область памяти, создаваемая при старте JVM. Используется Java Runtime для выделения памяти под объекты и JRE классы. Создание нового объекта также происходит в куче. Здесь работает сборщик мусора: освобождает память путем удаления объектов, на которые нет каких-либо ссылок. Любой объект, созданный в куче, имеет глобальный доступ и на него могут ссылаться с любой части приложения. Строгими тезами: * Все объекты обитают в куче и попадают туда при создании. * Объект состоит из полей класса и методов. * В куче выделяется место под сам объект, количество выделенной памяти зависит от полей, если у тебя полем класса, к примеру, служит интовая переменная, то не важно, инициализируешь ты ее как "0" или как "1000000" - объект займет в куче свои биты, + столько байт сколько вмещает тип int(+32 бита), и так с каждым полем. Стековая память в Java работает по схеме LIFO (Последний-зашел-Первый-вышел). Всякий раз, когда вызывается метод, в памяти стека создается новый блок, который содержит примитивы и ссылки на другие объекты в методе расположение в RAM и достижение процессору через указатель стека. Как только метод заканчивает работу, блок также перестает использоваться, тем самым предоставляя доступ для следующего метода. Размер стековой памяти намного меньше объема памяти в куче. Строгими тезами: * Все методы обитают в стеке и попадают туда при вызове. * Переменные в методах так же имеют стековую память, по скольку они локальные. * Если в методе создается объект, то он помещается в кучу, но его ссылка все еще будет находится в стеке и после того как метод покинет стек - объект станет жертвой сборщика мусора, так как ссылка на него утеряна, и из главного стека программы невозможно будет добраться до такого объекта. h3. Какая разница между Stack и Heap памятью в Java? Приведем следующие различия между Heap и Stack памятью в Java. * Куча используется всеми частями приложения в то время как стек используется только одним потоком исполнения программы. * Всякий раз, когда создается объект, он всегда хранится в куче, а в памяти стека содержится ссылка на него. Память стека содержит только локальные переменные примитивных типов и ссылки на объекты в куче. * Объекты в куче доступны с любой точки программы, в то время как стековая память не может быть доступна для других потоков. * Управление памятью в стеке осуществляется по схеме LIFO. * Стековая память существует лишь какое-то время работы программы, а память в куче живет с самого начала до конца работы программы. * Мы можем использовать -Xms и -Xmx опции JVM, чтобы определить начальный и максимальный размер памяти в куче. Для стека определить размер памяти можно с помощью опции -Xss . * Если память стека полностью занята, то Java Runtime бросает java.lang.StackOverflowError, а если память кучи заполнена, то бросается исключение java.lang.OutOfMemoryError: Java Heap Space. * Размер памяти стека намного меньше памяти в куче. Из-за простоты распределения памяти (LIFO), стековая память работает намного быстрее кучи. h3. Расскажите про модель памяти в java? {{dmsf_image(196)}} В Java память устроена следующим образом, есть два вида: * куча * стек Куча состоит из статического контекста и самой кучи/ Куча состоит из двух частей: * Новая куча * Старая куча Новая куча в свою очередь состоит из двух частей: * Eden(назовем ее первая) куча * Survival(выжившая) куча Краткое описание: * Eden Space (heap) - в этой области выделятся память под все создаваемые из программы объекты. Большая часть объектов живет недолго (итераторы, временные объекты, используемые внутри методов и т.п.), и удаляются при выполнении сборок мусора это области памяти, не перемещаются в другие области памяти. Когда данная область заполняется (т.е. количество выделенной памяти в этой области превышает некоторый заданный процент), GC выполняет быструю (minor collection) сборку мусора. По сравнению с полной сборкой мусора она занимает мало времени, и затрагивает только эту область памяти - очищает от устаревших объектов Eden Space и перемещает выжившие объекты в следующую область. * Survivor Space (heap) – сюда перемещаются объекты из предыдущей, после того, как они пережили хотя бы одну сборку мусора. Время от времени долгоживущие объекты из этой области перемещаются в Tenured Space. * Tenured (Old) Generation (heap) - Здесь скапливаются долгоживущие объекты (крупные высокоуровневые объекты, синглтоны, менеджеры ресурсов и проч.). Когда заполняется эта область, выполняется полная сборка мусора (full, major collection), которая обрабатывает все созданные JVM объекты. * Permanent Generation (non-heap) - Здесь хранится метаинформация, используемая JVM (используемые классы, методы и т.п.). h3. Как работает сборщик мусора (garbage collector)? Во-первых что стоит сказать, что у сборщика мусора есть несколько алгоритмов работы, он не один. Когда происходит очистка памяти? Если память в Первой куче полностью заполнена, то туда идет сборщик мусора и делает свою работу) Какую именно, зависит от обстоятельств… Например если в первой кучи много мусора(т.е. объектов с нулевой ссылкой), то сборщик мусора помечает эти объекты, далее те что остались объекты со ссылками он их переносит в Выжившую кучу, а в первой куче он просто все удаляет. Ситуация другая, в первой кучи мало мусора, но очень много рабочих объектов. Как поступает в этом случае сборщик мусора? Он помечает мусор, удаляет его и оставшиеся объекты компонует. Также следует заметить что при нехватке места в Выжившей куче, объекты переносятся в старую кучу, там хранятся как правило долго живущие объекты. Также следует заметить что сборщик мусора вызывается сам периодически, а не только когда памяти не хватает. h3. Расскажите про приведение типов. Что такое понижение и повышение типа? Когда вы получаете ClassCastException? Приведение типов это установка типа переменной или объекта отличного от текущего. В два есть два вида приведения: * автоматическое * не автоматическое Автоматическое происходит например: <pre> byte-> short->int->long->float->double </pre> то-есть если мы расширяем тип, то явное преобразование не требуется, приведение происходит автоматически. Если же мы сужаем, то необходимо явно указывать приведение типа. В случае же с объектами, то мы можем сделать автоматическое приведение от наследника к родителю, но никак не наоборот, тогда вылетит ClassCastException. h3. Что такое статический класс, какие особенности его использования? Статическим классом может быть только внутренний класс (определение класса размещается внутри другого класса). В объекте обычного внутреннего класса хранится ссылка на объект внешнего класса. Внутри статического внутреннего класса такой ссылки нет. То есть: Для создания объекта статического внутреннего класса не нужен объект внешнего класса. Из объекта статического вложенного класса нельзя обращаться к нестатическим членам внешнего класса напрямую. И еще обычные внутренние классы не могут содержать статические методы и члены. *Зачем вообще нужны внутренние классы?* Каждый внутренний класс способен независимо наследовать определенную реализацию. Таким образом внутренний класс не ограничен при наследовании в ситуациях, когда внешний класс уже наследует реализацию. То есть это как бы вариант решения проблемы множественного наследования. h3. Каким образом из вложенного класса получить доступ к полю внешнего класса. Если класс внутренний то: Внешний класс.this. Поле внешнего класса Если класс статический внутренний(вложенный),то в методе нужно создать объект внешнего класса, и получить доступ к его полю.Или второй вариант объявить это поле внешнего класса как static h3. Какие существуют типы вложенных классов? Для чего они используются? Вложенные классы существуют внутри других классов. Нормальный класс - полноценный член пакета. Вложенные классы, которые стали доступны начиная с Java 1.1, могут быть четырех типов: * статические члены класса * члены класса * локальные классы * анонимные классы Статические члены классов (static nested classes) - как и любой другой статический метод, имеет доступ к любым статическим методам своего внешнего класса, в том числе и к приватным. К нестатическим полям и методам обрамляющего класса он не может обращаться напрямую. Он может использовать их только через ссылку на экземпляр класса родителя. Члены класса - локальные классы, объявленные внутри блока кода. Эти классы видны только внутри блока. Анонимные классы - Эти типы классов не имеют имени и видны только внутри блока. h3. Возможно ли при переопределении (override) метода изменить: Переопределение методов действует при наследовании классов, т.е. в классе наследнике объявлен метод с такой же сигнатурой что и в классе родителе. Значит этот метод переопределил метод своего суперкласса. Несколько нюансов по этому поводу: * Модификатор доступа в методе класса наследника должен быть НЕ уже чем в классе родителе, иначе будет ошибка компиляции. * Описание исключения в переопределенном методе класса наследника должен быть НЕ шире чем в классе родителе, иначе ошибка компиляции. * Метод обьявленный как "private" в классе родителе нельзя переопределить! h4. Модификатор доступа Да, если расширять <pre> package -> protected -> public </pre> h4. Возвращаемый тип Да, если выполняется Downcasting(понижающее преобразование, преобразование вниз по иерархии) то есть возвращаемый тип в переопределенном методе класса Integer) h4. Тип аргумента или количество Нет, в таком случае происходит Overload(перегрузка) h4. Имя аргументов Да h4. Изменять порядок, количество или вовсе убрать секцию throws? Возможно изменять порядок. Возможно вовсе убрать секцию throws в методе, так как она уже определена. Так же возможно добавлять новые исключения, которые наследуются от объявленных или исключения времени выполнения. h3. Что такое autoboxing? Autoboxing/Unboxing - автоматическое преобразование между скалярными типами Java и соответствующими типами-врапперами (например, между int - Integer). Наличие такой возможности сокращает код, поскольку исключает необходимость выполнения явных преобразований типов в очевидных случаях. h3. Что такое Generics? *Java Generics* - это технический термин, обозначающий набор свойств языка позволяющих определять и использовать обобщенные типы и методы. Обобщенные типы или методы отличаются от обычных тем, что имеют типизированные параметры. Примером дженериков или обобщенных типов может служить библитека с коллекциями в Java. Например, класс _LinkedList<E>_ - типичный обобщенный тип. Он содержит параметр E, который представляет тип элементов, которые будут храниться в коллекции. Вместо того, чтобы просто использовать _LinkedList_ , ничего не говоря о типе элемента в списке, мы можем использовать _LinkedList<String>_ или _LinkedList<Integer>_ . Создание объектов обобщенных типов происходит посредством замены параметризированных типов реальными типами данных. Класс типа _LinkedList<E>_ - обобщенный тип, который содержит параметр E. Создание объектов, типа _LinkedList<String>_ или _LinkedList<Integer>_ называются параметризированными типами, а String и Integer - реальные типы аргументов. h3. Какова истинная цель использования обобщенных типов в Java? Обобщенные типы в Java были изобретены, в первую очередь, для реализации обобщенных коллекций. h3. Каким образом передаются переменные в методы, по значению или по ссылке? В java параметры в методы передаются по значению, то-есть создаются копии параметров и с ними ведется работа в методе. В случае с примитивными типами, то при передачи параметра сама переменная не будет меняться так как в метод просто копируется ее значение. А вот при передачи объекта копируется ссылка на объект, то-есть если в методе мы поменяем состояние объекта, то и за методом состояние объекта тоже поменяется. Но если мы этой копии ссылки попытаемся присвоить новую ссылку на объект, то старая ссылка у нас не изменится. В случае передачи по значению параметр копируется. Изменение параметра не будет заметно на вызывающей стороне. В Java объекты всегда передаются по ссылке, а примитивы - по значению. h3. Какие методы есть у класса Object? Object это базовый класс для всех остальных объектов в Java. Каждый класс наследуется от Object. Соответственно все классы наследуют методы класса Object. Методы класса Object: * public final native Class getClass() * public native int hashCode() * public boolean equals(Object obj) * protected native Object clone() throws CloneNotSupportedException * public String toString() * public final native void notify() * public final native void notifyAll() * public final native void wait(long timeout) throws InterruptedException * public final void wait(long timeout, int nanos) throws InterruptedException * public final void wait() throws InterruptedException * protected void finalize() throws Throwable h3. Правила переопределения метода Object.equals(). # Используйте оператор == что бы проверить ссылки на объект, переданную в метод equals. Если ссылки совпадают - вернуть true. Это не обязательно, нужно скорее для оптимизации, но может сэкономить время в случае "тяжёлых" сравнений. # Используйте оператор instanceof для проверки типа аргумента. Если типы не совпадают, вернуть false. # Преобразуйте аргумент к корректному типу. Так как на предыдущем шаге мы выполнили проверку, преобразование корректно. # Пройтись по всем значимым полям объектов и сравнить их друг с другом. Если все поля равны - вернуть true. Для сравнения простых типов использовать ==. Для полей со ссылкой на объекты использовать equals. Float преобразовывать в int с помощью Float.FloatToIntBits и сравнить с помощью ==. double преобразовывать в long с помощью Double.doubleToLongBits и сравнить с помощью ==. Для коллекций вышеперечисленные правила применяются к каждому элементу коллекции. Нужно учитывать возможность null полей/объектов. Очерёдность сравнения полей может существенно влиять на производительность. # Закончив реализацию equals задайте себе вопрос, является ли метод симметричным, транзитивным и непротиворечивым. И ещё несколько дополнительных правил: * Переопределив equals, всегда переопределять hashCode. * Не использовать сложную семантику в equals (типа определения синонимов). equals должен сравнивать поля объектов, не более h3. Если вы хотите переопределить equals(), какие условия должны удовлетворяться для переопределенного метода? Метод equals() обозначает отношение эквивалентности объектов. Эквивалентным называется отношение, которое является симметричным, транзитивным и рефлексивным. * Рефлексивность: для любого ненулевого x, x.equals(x) вернет true; * Транзитивность: для любого ненулевого x, y и z, если x.equals(y) и y.eqals(z) вернет true, тогда и x.equals(z) вернет true; * Симметричность: для любого ненулевого x и y, x.equals(y) должно вернуть true, тогда и только тогда, когда y.equals(x) вернет true. Также для любого ненулевого x, x.equals(null) должно вернуть false. h3. Какая связь между hashCode и equals? Объекты равны, когда a.equals(b)=true и a.hashCode==b.hashcode -> true Но необязательно, чтобы два различных объекта возвращали различные хэш коды(такая ситуация называется коллизией). h3. Каким образом реализованы методы hashCode и equals в классе Object? Реализация метода equals в классе Object сводится к проверке на равенство двух ссылок: <pre><code class="java"> public boolean equals(Object obj) { return (this == obj); } </code></pre> Реализация же метода hashCode класса Object сделана нативной, т.е. определенной не с помощью Java-кода: <pre> public native int hashCode(); </pre> Он обычно возвращает адрес объекта в памяти. h3. Что будет, если переопределить equals не переопределяя hashCode? Какие могут возникнуть проблемы? Они будут неправильно хранится в контейнерах, использующих хэш коды, таких как HashMap, HashSet. Например HashSet хранит элементы в случайном (на первый взгляд) порядке. Дело в том, что для быстрого поиска HashSet расчитывает для каждлого элемента hashCode и именно по этому ключу ищет и упорядочивает элементы внутри себя. h3. Есть ли какие-либо рекомендации о том, какие поля следует использовать при подсчете hashCode? Есть. Необходимо использовать уникальные, лучше примитивные поля, такие как id, uuid, например. Причем, если эти поля задействованы при вычислении hashCode, то нужно их задействовать при выполнении equals. Общий совет: выбирать поля, которые с большой долью вероятности будут различаться. h3. Для чего нужен метод hashCode()? Существуют коллекции(HashMap, HashSet), которые используют хэш код, как основу при работе с объектами. А если хэш для равных объектов будет разным, то в HashMap будут два равных значения, что является ошибкой. Поэтому необходимо соответствующим образом переопределить метод hashCode(). * Х Хеширование - преобразование входного массива данных произвольной длины в выходную битовую строку фиксированной длины. Такие преобразования также хешем или хеш-кодом. * Хе Хеш-таблице - это структура данных, реализующая интерфейс ассоциативного массива, а именно, она позволяет хранить пары (ключ, значение) и выполнять три операции: операцию добавления новой пары, операцию поиска и операцию удаления пары по ключу. Выполнение операции в хеш-таблице начинается с вычисления хеш-функции от ключа. Получающееся хеш-значение i = hash(key) играет роль индекса в массиве H. Затем выполняемая операция (добавление, удаление или поиск) перенаправляется объекту, который хранится в соответствующей ячейке массива H[i]. Одним из методов построения хеш-функции есть метод деления с остатком (division method) состоит в том, что ключу k ставится в соответствие остаток от деления k на m, где m - число возможных хеш-значений. h3. Правила переопределения метода Object.hashCode(). При реализации hashCode используется несколько простых правил. Прежде всего, при вычислении хеш-кода следует использовать те же поля, которые сравниваются в equals. Это, во-первых, даст равенство хеш-кодов для равных обектов, во-вторых, распределено полученное значение будет точно так же, как и исходные данные. Теоретически, можно сделать так, чтобы хеш-код всегда был равен 0, и это будет абсолютно легальная реализация. Другое дело, что ее ценность будет равна тому же самому нулю. Далее. Несмотря на то, что хеш-коды равных объектов должны быть равны, обратное неверно! Два неравных объекта могут иметь равные хеш-коды. Решающее значение имеет не уникальность, а скорость вычисления, потому как это приходится делать очень часто. Потому, в некоторых случаях имеет смысл посчитать хеш-код заранее и просто выдавать его по запросу. Прежде всего это стоит делать тогда, когда вычисление трудоемко, а объект неизменен. h3. Расскажите про клонирование объектов. В чем отличие между поверхностным и глубоким клонированием? Чтобы объект можно было клонировать, он должен реализовать интерфейс Cloneable(маркер). Использование этого интерфейса влияет на поведение метода "clone" класс Object. Таким образом myObj.clone() создаст нам клон нашего объекта, но этот клон будет поверхностный. Что значит поверхностным? Это значит что клонируется только примитивные поля класса, ссылочные поля не клонируются! Для того, чтоб произвести глубокое клонирование, необходимо в клонируемом классе переопределить метод clone() и в нем произвести клонирование изменяемых полей h3. Правила переопределения метода Object.clone(). Метод clone() в Java используется для клонирования объектов. Т.к. Java работает с объектами с помощью ссылок, то простым присваиванием тут не обойдешься, ибо в таком случае копируется лишь адрес, и мы получим две ссылки на один и тот же объект, а это не то, что нам нужно. Механизм копирования обеспечивает метод clone() класса Object. clone() действует как конструктор копирования. Обычно он вызывает метод clone() суперкласса и т.д. пока не дойдет до Object. Метод clone() класса Object создает и возвращает копию объекта с такими же значениями полей. Object.clone() кидает исключение CloneNotSupportedException если вы пытаетесь клонировать объект не реализующий интерфейс Cloneable. Реализация по умолчанию метода Object.clone() выполняет неполное/поверхностное (shallow) копирование. Если вам нужно полное/глубокое (deep) копирование класса то в методе clone() этого класса, после получения клона суперкласса, необходимо скопировать нужные поля. Синтаксис вызова clone() следующий: <pre> Object copy = obj.clone(); </pre> или чаще: <pre> MyClass copy = (MyClass) obj.clone(); </pre> Один из недостатков метода clone(), это тот факт, что возвращается тип Object, поэтому требуется нисходящее преобразование типа. Однако начиная с версии Java 1.5 при переопределении метода вы можете сузить возвращаемый тип. Пару слов о clone() и final полях. Метод clone() несовместим с final полями. Если вы попробуете клонировать final поле компилятор остановит вас. Единственное решение - отказаться от final. Ну и пример использования clone(): <pre><code class="java"> class MyClass implements Cloneable { public Integer i = 10; public MyClass clone() throws CloneNotSuppotedException { MyClass obj = (MyClass) super.clone(); obj.i = i; return obj; } public String toString() { return i.toString(); } } public class Temp { public static void main(String args[]) throws CloneNotSupportedException { MyClass a = new MyClass(); a.i = 11; MyClass b = a.clone(); MyClass c = a; System.out.println("a: " + a + "b: " + b + "c: " +c); a.i = 12; System.out.println("a: " + a + "b: " + b + "c: " +c); } } </code></pre> Консоль: <pre> a: 11 b: 11 c: 11 a: 12 b: 11 c: 12 </pre> Как видите, изменение объекта a повлекло за собой изменение объекта c, а вот с b всё в порядке. h3. Где и как вы можете использовать закрытый конструктор? Например в качестве паттерна Синглетон. В том же классе создается статический метод. Где и создается экземпляр класса, конечно если он уже не создан, тогда он просто возвращается методом. h3. Что такое конструктор по умолчанию? В Java если нет явным образом опредёленных конструкторов в классе, то компилятор использует конструктор по умолчанию, опредёленный неявным способом, который аналогичен "чистому", конструктору по умолчанию. Конструктор по умолчанию - это довольно простая конструкция, которая сводится к созданию для типа конструктора без параметров. Так, например, если при объявлении нестатического класса не объявить пользовательский конструктор (не важно, с параметрами или без них), то компилятор самостоятельно сгенерирует конструктор без параметров. Некоторые программисты явным образом задают конструктор по умолчанию по привычке, чтобы не забыть в дальнейшем, но это не обязательно В Java если производный класс не вызывает явным образом конструктор базового класса (в Java используя super() в первой строчке), то конструктор по умолчанию вызывается неявно. Если базовый класс не имеет конструктора по умолчанию, то это считается ошибкой. h3. Опишите метод Object.finalize(). Метод Finalize(). Java обеспечивает механизм, который является аналогичным использованию деструкторов в С ++, который может использоваться для того, чтобы произвести процесс очистки перед возвращением управления операционной системе. Применяя метод Finalize(), можно определять специальные действия, которые будут выполняться тогда, когда объект будет использоваться сборщиком мусора. Данный метод вызывается при уничтожении объекта автоматическим сборщиком мусора (garbage collector). В классе Object он ничего не делает, однако в классе-наследнике позволяет описать все действия, необходимые для корректного удаления объекта, такие как закрытие соединений с БД, сетевых соединений, снятие блокировок на файлы и т.д. В обычном режиме напрямую этот метод вызывать не нужно, он отработает автоматически. Если необходимо, можно обратиться к нему явным образом. Его синтаксис: <pre> protected void Finalize( ) throws Throwable </pre> Ссылки не являются собранным мусором; только объекты - собранный мусор h3. Чем отличаются слова final, finally и finalize? *Final* - Нельзя наследоваться от файнал класса. Нельзя переопределить файнал метод. Нельзя изменить сначение файнал поля. *Finally* - используется при обработке ошибок, вызывается всегда, даже если произошла ошибка(кроме System.exit(0)). Удобно использовать для освобождения ресурсов. *Finalize()* - вызывается перед тем как сборщик мусора будет проводить освобождение памяти. Не рекомендуется использовать для освобождения системных ресурсов, так как не известно когда сборщик мусора будет производить свою очистку. Вообще данный метод мало кто использует. Единственно что можно использовать этот метод для закрытия ресурса что должен работать на протяжении всей работы программы и закрываться по ее окончанию. Еще можно использовать метод для защиты от так называемых «дураков», проверять, освобождены ли ресурсы, если нет, то закрыть их. h3. Опишите иерархию исключений. h3. Какие виды исключений в Java вы знаете, чем они отличаются? h3. Что такое checked и unchecked Exception? h3. Как создать свой unchecked Exception? h3. Какие есть Unchecke exeption? h3. Что такое Error? h3. Опишите работу блока try-catch-finally. h3. Возможно ли использование блока try-finally (без catch)? h3. Всегда ли исполняется блок finally? h3. Какие есть особенности класса String? что делает метод intern(). h3. Можно ли наследовать строковый тип, почему? h3. Почему строка является популярным ключом в HashMap в Java? h3. Дайте определение понятию конкатенация строк. h3. Как перевернуть строку? h3. Как сравнить значение двух строк? h3. Как обрезать пробелы в начале и конце строки? h3. Дайте определение понятию "пул строк". h3. Можно ли синхронизировать доступ к строке? h3. Как правильно сравнить значения строк двух различных объектов типа String и StringBuffer? h3. Почему строка неизменная и финализированная в Java? h3. Напишите метод удаления данного символа из строки. h3. Что такое рефлексия? h3. Что произойдет со сборщиком мусора (GC), если во время выполнения метода finalize() некоторого объекта произойдет исключение? h3. Что такое интернационализация, локализация? h3. Что такое Аннотации в Java? h3. Какие функции выполняет Аннотации? h3. Какие встроенные аннотации в Java вы знаете? h3. Что делают аннотации @Retention, @Documented, @Target и @Inherited? h3. Что делают аннотации @Override, @Deprecated, @SafeVarargs и @SuppressWarnings? h3. Какой жизненный цикл аннотации можно указать с помощью @Retention? h3. К каким элементам можно применять аннотацию, как это указать? h3. Как создать свою Аннотацию? h3. Атрибуты каких типов допустимы в аннотациях? h3. Что такое JMX? h3. Какие выгоды предлагает JMX? h3. Что еще умеет JMX кроме дистанционного управления? h3. Что такое MBean? h3. Какие типы MBeans существуют? h3. Что такое MBean Server? h3. Какие механизмы обеспечивают безопасность в технологии Java? h3. Назовите несколько видов проверок которые выполняет верификатор байт-кода Java? h3. Что вы знаете о "диспетчере защиты" в Java? h3. Что такое JAAS? h3. Что такое Рефакторинг?Go to top