Java Core - 1 Flashcards
- Что такое ООП?
Объектно-ориентированное программирование (ООП) — методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
● объектно-ориентированное программирование использует в качестве основных логических
конструктивных элементов объекты, а не алгоритмы;
● каждый объект является экземпляром определенного класса
● классы образуют иерархии.
Согласно парадигме ООП программа состоит из объектов, обменивающихся сообщениями.
Объекты могут обладать состоянием, единственный способ изменить состояние объекта - послать ему сообщение, в ответ на которое, объект может изменить собственное состояние.
Какие преимущества у ООП?
Преимущества ООП:
- Возможность легкой модификации (при грамотном анализе и проектировании)
- Возможность отката при наличии версий
- Более легкая расширяемость
- «Более естественная» декомпозиция (разделение целого на части) программного
обеспечения, которая существенно облегчает его разработку «слабая связанность кода».
- Сокращение количества межмодульных вызовов и уменьшение объемов информации,
передаваемой между модулями.
- Увеличивается показатель повторного использования кода.
Какие недостатки у ООП?
Недостатки ООП:
- Требуется другая квалификация
- Резко увеличивается время на анализ и проектирование систем
- Увеличение времени выполнения
- Размер кода увеличивается :interrobang:
- Неэффективно с точки зрения памяти (мертвый код - тот, который не используется)
-Сложность распределения работ на начальном этапе
- Себестоимость больше
- Скорость
Назовите основные принципы ООП.
Инкапсуляция, наследование, полиморфизм, абстракция,
Что такое инкапсуляция? (с примером)
Это свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе и скрыть детали реализации от пользователя, открыв только то, что необходимо при последующем использовании.
Модификаторы доступа (Access modifiers: private, default (package visible), protected, public) Геттеры и Сеттеры (Getters and Setters)
Пример – кондиционер (берем пульт включаем холод - запускаются разные процессы, кот. не показываются пользователю), пользователю на пульте показывается температура воздуха на выходе, остальное все скрыто.
Цель инкапсуляции — уйти от зависимости внешнего интерфейса класса (то, что могут использовать другие классы) от реализации. Чтобы малейшее изменение в классе не влекло за собой изменение внешнего поведения класса.
Состояние объекта – это значение всех его полей. Объект не должен изменяться чем то из вне, кроме своих методов. Убрать возможность случайного/умышленного изменения объекта.
Что такое наследование?(С примером)
Наследование - свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью.
Наследование форма отношения «is a» (является). Класс наследника является классом предка, но класс предка не является классом наследника: собака – наследник животного, но животное не наследник собаки. Наследник – более «узкий» класс.
Пример: кондиционер наследуется от холодильной техники.
Есть одиночное и множественное наследование (класс наследуется от нескольких классов). В Jave множественное наследование ограничено. Проблема – ромбовидное наследование: у одного базового класса есть два наследника, а у наследника этих двух классов свой наследник, какая реализация попадет в последний – ХЗ.
Запретить наследование - public final class.
Делегирование – один класс вызывает другой класс, не связанный наследованием.
– это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью.
Класс, от которого производится наследование, называется предком, базовым или
родительским. Новый класс – потомком, наследником или производным классом.
class Employee extends Person {}
Что такое полиморфизм? (С примером
Полиморфизм - это свойство системы использовать объекты с одинаковым
интерфейсом без информации о типе и внутренней структуре объекта.
Все if –ы можно заменить на полиморфизм (способ рефакторинга).
Позволяет уменьшать размер программы.
Пример: интерфейс «охлаждать» имеет место в технике, холодное пиво)) и т.п.
Преимуществом полиморфизма является то, что он помогает снижать сложность программ,
разрешая использование одного и того же интерфейса для задания единого набора действий.
Выбор же конкретного действия, в зависимости от ситуации, возлагается на компилятор языка
программирования. Отсюда следует ключевая особенность полиморфизма - использование
объекта производного класса, вместо объекта базового (потомки могут изменять родительское
поведение, даже если обращение к ним будет производиться по ссылке родительского типа).
Unit ref = new Refrigerator(“ref”, 24);
Полиморфная переменная, это переменная, которая может принимать значения разных типов,
а полиморфная функция - функция у которой хотя бы один аргумент является полиморфной
переменной. Выделяют два вида полиморфных функций:
- ad hoc, функция ведет себя по разному для разных типов аргументов (например, функция
draw() — рисует по разному фигуры разных типов);
- параметрический, функция ведет себя одинаково для аргументов разных типов (например,
функция add() — одинаково кладет в контейнер элементы разных типов).
Абстрагирование – это способ выделить набор общих характеристик объекта, исключая из
рассмотрения частные и незначимые. Соответственно, абстракция – это набор всех таких
характеристик. (телефон звонил в 19 веке и в 21, функция выделена из разных сложных процессов).
Объект-класс-абстрактный класс-Интерфейс (макс. уровень абстракции).
Что такое ассоциация, агрегация и композиция?
Ассоциация обозначает связь между объектами. Композиция и агрегация – частные случаи ассоциации «часть-целое».
Агрегация предполагает, что объекты связаны взаимоотношением «part-of» (часть).
Композиция более строгий вариант агрегации. Дополнительно к требованию «part-of»
накладывается условие, что экземпляр «части» может входить только в одно целое (или
никуда не входить), в то время как в случае агрегации экземпляр «части» может входить в
несколько целых.
Расскажите про раннее (статическое) и позднее (динамическое) связывание.
Присоединение вызова метода к телу метода называется связыванием. Если связывание проводится компилятором (компоновщиком) перед запуском программы, то оно называется статическим или ранним связыванием (early binding).
В свою очередь, позднее связывание (late binding) – это связывание, проводимое непосредственно во время выполнения программы в зависимости от типа объекта. Позднее связывание также называют динамическим (dynamic), или связыванием на стадиивыполнения (runtime binding).
Для всех методов Java используется механизм позднего (динамического) связывания, если
только метод не был объявлен как final (приватные методы являются final по умолчанию).
SOLID
Принципы SOLID - это набор руководящих принципов, предложенных Робертом Мартином (также известным как Uncle Bob), которые помогают создавать более гибкие, понятные и легко поддерживаемые программные системы. Эти принципы спроектированы для облегчения разработки и сопровождения кода в объектно-ориентированных языках программирования. Вот основные принципы SOLID:
**Принцип единственной ответственности **(Single Responsibility Principle - SRP):
Каждый класс должен иметь только одну причину для изменения. Суть заключается в том, что класс должен быть ответственным только за один аспект функциональности.
Принцип открытости/закрытости (Open/Closed Principle - OCP):
Программные сущности, такие как классы, модули и функции, должны быть открыты для расширения, но закрыты для модификации. Это означает, что вы должны иметь возможность добавлять новую функциональность без изменения существующего кода.
Принцип подстановки Барбары Лисков (Liskov Substitution Principle - LSP):
Объекты базового класса должны быть заменяемыми объектами производного класса без изменения правильности программы. Если класс является подклассом другого класса, то его объекты должны вести себя так же, как объекты базового класса.
Принцип разделения интерфейса (Interface Segregation Principle - ISP):
Клиенты не должны зависеть от интерфейсов, которые они не используют. Это означает, что не следует насаждать классам зависимость от интерфейсов, которые они не используют.
Принцип инверсии зависимостей (Dependency Inversion Principle - DIP):
Модули верхнего уровня не должны зависеть от модулей нижнего уровня, а оба типа модулей должны зависеть от абстракций. Абстракции не должны зависеть от деталей; детали должны зависеть от абстракций. Это также подразумевает использование интерфейсов или абстрактных классов для определения общих концепций, а не зависимость от конкретных реализаций.
Соблюдение этих принципов помогает создавать более гибкий, расширяемый и поддерживаемый код, что особенно важно в больших и долгосрочных проектах.
Какая основная идея языка?
Кроссплатформенность, «написано/скомпилировано однажды, запускается везде» (compile once, run anywhere)
Приложения Java обычно транслируются в специальный байт-код, поэтому они могут работать на любой компьютерной архитектуре, для которой существует реализация виртуальной Java-машины.
Байт-код Java — набор инструкций, исполняемых виртуальной машиной Java. Каждый код операции байт-кода — один байт. Используются не все 256 возможных значений кодов операций. 51 из них зарезервированы для использования в будущем.
За счет чего обеспечивается кроссплатформенность?
Java Virtual Machine (JVM) — виртуальная машина Java — основная часть исполняющей системы Java, так называемой Java Runtime Environment (JRE). Виртуальная машина Java исполняет байт-код Java, предварительно созданный из исходного текста Java-программы компилятором Java (javac). JVM может также использоваться для выполнения программ, написанных на других языках программирования. Например, исходный код на языке Ada может
быть скомпилирован в байт-код Java, который затем может выполниться с помощью JVM.
Какие преимущества у java?
- Объектно-ориентированный: все является объектом. Дополнение может быть легко расширено
- Платформонезависимый
- Простой для понимания: основные концепции ООП
- Безопасным: методы проверки подлинности основаны на шифровании с открытым ключом.
- Архитектурно-нейтральным: компилятор генерирует архитектурно-нейтральные объекты формата файла, что делает скомпилированный код исполняемым на многих процессорах, с наличием системе Java Runtime.
- Портативный: архитектурно-нейтральный и не имеющий зависимости от реализации аспектов спецификаций — все это делает Java портативным. Компилятор в Java написан на ANSI C с чистой
переносимостью, который является подмножеством POSIX. - Прочный: прилагает усилия, чтобы устранить ошибки в различных ситуациях, делая упор в основном на время компиляции, проверку ошибок и проверку во время выполнения.
- Язык для распределенного программирования и комфортной удаленной совместной работы.
Специфическая для Java методология распределенных вычислений называется Remote Method Invocation (RMI). RMI позволяет использовать все преимущества Java: безопасность, независимость от платформы и объектно-ориентированное программирование для распределенных вычислений - Автоматическое управление памятью
- Многопоточность
- Стабильность и сообщество
Какие недостатки у Java?
- Платное коммерческое использование. Oracle с 2019 взимает плату за использование Java Standard Edition 8 в «коммерческих целях»
- Низкая производительность (из-за компиляции и абстракции с помощью виртуальной машины, очистки памяти, взаимная блокировка потоков)
- Отсутствие нативного дизайна для создания графического интерфейса пользователя (GUI). Есть Swing, SWT, JavaFX, JSF …но не катят.
- Многословный и сложный код. длинные, чрезмерно сложные предложения затрудняют чтение и просмотр кода. Как и естественные языки, многие языки программирования высокого уровня содержат лишнюю информацию.
- Что такое JDK? Что в него входит?
Комплект разработчика приложений на языке Java:
- компилятор Java (javac)
- стандартные библиотеки классов Java, примеры, документацию, утилиты (вспомогательная компьютерная программа в составе общего программного обеспечения для выполнения специализированных типовых задач, связанных с работой оборудования и операционной системы)
- исполнительную систему Java (JRE: Java Virtual Machine + библиотеки Java-классов).
Что такое JRE? что в него входит?
Java Runtime Environment (JRE среда выполнения для Java) — минимальная реализация виртуальной машины, необходимая для исполнения Java-приложений, без компилятора и других средств разработки: Java Virtual Machine + и библиотеки Java-классов.
- Что такое JVM?
Основная часть JRE. Исполняет байт-код Java, предварительно созданный из исходного текста Java-программы компилятором Java (javac). JVM может также использоваться для выполнения программ, написанных на других языках программирования. Например, исходный код на языке Ada может быть скомпилирован в байт-код Java, который затем может выполниться с помощью JVM
Что такое byte code?
Промежуточное представление кода, в которое может быть переведена компьютерная программа автоматическими средствами. Машинно-независимый код низкого уровня, генерируемый транслятором из исходного кода - набор валидных (соответствующих спецификации Java) команд.
Что такое загрузчик классов (classloader)?
Загрузчик классов является частью JRE, которая динамически закгружает Java классы в JVM. Обычно классы загружаются только по запросу. Система исполнения в Java не должна знать о файлах и файловых системах благодаря загрузчику классов. Делегирование является важной концепцией, которую выполняет загрузчик.
Загрузчик классов отвечает за поиск библиотек, чтение их содержимого и загрузку классов, содержащихся в библиотеках. Эта загрузка обычно выполняется «по требованию», поскольку она не происходит до тех пор, пока программа не вызовет класс. Класс с именем может быть загружен только один раз данным загрузчиком классов.
При запуске JVM, используются три загрузчика классов:
* Bootstrap class loader (Загрузчик класса Bootstrap)
* Extensions class loader (Загрузчик класса расширений)
* System class loader (Системный загрузчик классов)
Загрузчик класса Bootstrap загружает основные библиотеки Java, расположенные в
папке <JAVA_HOME>/jre/lib. Этот загрузчик является частью ядра JVM, написан на нативном коде.
Загрузчик класса расширений загружает код в каталоги расширений (<JAVA_HOME>/jre/lib/ext, или любой другой каталог, указанный системным свойством java.ext.dirs).
Системный загрузчик загружает код, найденный в java.class.path, который сопоставляется с переменной среды CLASSPATH. Это реализуется классом sun.misc.Launcher$AppClassLoader.
Загрузчик классов выполняет три основных действия в строгом порядке:
* Загрузка: находит и импортирует двоичные данные для типа.
* Связывание: выполняет проверку, подготовку и (необязательно) разрешение.
o Проверка: обеспечивает правильность импортируемого типа.
o Подготовка: выделяет память для переменных класса и инициализация памяти значениями по умолчанию.
o Разрешение: преобразует символические ссылки из типа в прямые ссылки.
* Инициализация: вызывает код Java, который инициализирует переменные класса их правильными начальными значениями.
Пользовательский загрузчик классов
Загрузчик классов написан на Java. Поэтому возможно создать свой собственный загрузчик классов, не понимая тонких деталей JVM. У каждого загрузчика классов Java есть родительский загрузчик классов, определенный при создании экземпляра нового загрузчика классов или в качестве системного загрузчика
классов по умолчанию для виртуальной машины.
Что делает возможным следующее:
* загружать или выгружать классы во время выполнения (например, динамически загружать библиотеки во время выполнения, даже из ресурса HTTP). Это важная особенность для:
o реализация скриптовых языков;
o использование bean builders;
o добавить пользовательскую расширение;
o позволяя нескольким пространствам имен общаться. Например, это одна из основ протоколов CORBA / RMI;
* изменить способ загрузки байт-кода (например, можно использовать зашифрованный байт-код
класса Java);
* модифицировать загруженный байт-код (например, для переплетения аспектов во время загрузки при использовании аспектно-ориентированного программирования);</JAVA_HOME></JAVA_HOME>
Что такое JIT?
JIT-компиляция (англ. Just-in-time compilation, компиляция «на лету»), динамическая
компиляция (англ. dynamic translation) — технология увеличения производительности программных систем, использующих байт-код, путём компиляции байт-кода в машинный код или в другой формат непосредственно во время работы программы
Что такое сборщик мусора? (Garbage collector)
Способ автоматического управления памятью.
Сборщик мусора (Garbage Collector) должен делать всего две вещи:
- Находить мусор - неиспользуемые объекты. (Объект считается неиспользуемым, если ни одна из сущностей в коде, выполняемом в данный момент, не содержит ссылок на него, либо цепочка ссылок, которая могла бы связать объект с некоторой сущностью приложения, обрывается);
- Освобождать память от мусора.
Работа сборщика мусора не бесплатная, она оплачивается ресурсами компьютера и задержками в выполнении программы.
Существует два подхода к обнаружению мусора:
* Reference counting;
* Tracing
Reference counting (подсчёт ссылок). Суть этого подхода состоит в том, что каждый объект имеет счетчик. Счетчик хранит информацию о том, сколько ссылок указывает на объект. Когда ссылка уничтожается, счетчик уменьшается. Если значение счетчика равно нулю, - объект можно считать мусором. Главным минусом такого подхода является сложность обеспечения точности
счетчика. Также при таком подходе сложно выявлять циклические зависимости (когда два объекта указывают друг на друга, но ни один живой объект на них не ссылается), что приводит к утечкам памяти.
Tracing (трассировка) - живыми могут считаться только те объекты, до которых мы можем добраться из корневых точек (GC Root) и те объекты, которые доступны с живого объекта. Всё остальное - мусор.
Существует 4 типа корневых точки:
* Локальные переменные и параметры методов;
* Потоки;
* Статические переменные;
* Ссылки из JNI.
Самое простое java приложение будет иметь корневые точки:
* Локальные переменные внутри main() метода и параметры main() метода;
* Поток который выполняет main();
* Статические переменные класса, внутри которого находится main() метод.
Таким образом, если мы представим все объекты и ссылки между ними как дерево, то нам нужно будет пройти с корневых узлов (точек) по всем рёбрам. При этом узлы, до которых мы сможем добраться - не мусор, все остальные - мусор. При таком подходе циклические зависимости легко выявляются. HotSpot VM использует именно такой подход.
Для очистки памяти от мусора существуют два основных метода:
* Copying collectors
* Mark-and-sweep
При copying collectors подходе память делится на две части «from-space» и «to-space», при этом сам принцип работы такой:
* Объекты создаются в «from-space»;
* Когда «from-space» заполняется, приложение приостанавливается;
* Запускается сборщик мусора. Находятся живые объекты в «from-space» и копируются в «to-space»;
* Когда все объекты скопированы «from-space» полностью очищается;
* «to-space» и «from-space» меняются местами.
Главный плюс такого подхода в том, что объекты плотно забивают память. Минусы подхода:
1. Приложение должно быть остановлено на время, необходимое для полного
прохождения цикла сборки мусора;
2. В худшем случае (когда все объекты живые) «form-space» и «to-space» будут
обязаны быть одинакового размера.
Алгоритм работы mark-and-sweep можно описать так:
* Объекты создаются в памяти;
* В момент, когда нужно запустить сборщик мусора приложение приостанавливается;
* Сборщик проходится по дереву объектов, помечая живые объекты;
* Сборщик проходится по всей памяти, находя все не отмеченные куски памяти и сохраняя их в «free list»;
* Когда новые объекты начинают создаваться они создаются в памяти доступной во «free list».
Минусы этого способа:
1. Приложение не работает пока происходит сборка мусора;
2. Время остановки напрямую зависит от размеров памяти и количества объектов;
3. Если не использовать «compacting» память будет использоваться не эффективно.
Сборщики мусора HotSpot VM используют комбинированный подход Generational Garbage Collection, который позволяет использовать разные алгоритмы для разных этапов сборки мусора.
Этот подход опирается на том, что:
* большинство создаваемых объектов быстро становятся мусором;
* существует мало связей между объектами, которые были созданы в прошлом и только что созданными объектами.
Как работает сборщик мусора?
Механизм сборки мусора - это процесс освобождения места в куче, для возможности добавления новых объектов.
Объекты создаются посредством оператора new, тем самым присваивая объекту ссылку. Для окончания работы с объектом достаточно просто перестать на него ссылаться, например, присвоив переменной ссылку на другой объект или значение null; прекратить выполнение метода, чтобы его
локальные переменные завершили свое существование естественным образом. Объекты, ссылки на которые отсутствуют, принято называть мусором (garbage), который будет удален.
Виртуальная машина Java, применяя механизм сборки мусора, гарантирует, что любой объект, обладающий ссылками, остается в памяти — все объекты, которые недостижимы из исполняемого кода, ввиду отсутствия ссылок на них, удаляются с высвобождением отведенной для них памяти.
Точнее говоря, объект не попадает в сферу действия процесса сборки мусора, если он достижим посредством цепочки ссылок, начиная с корневой (GC Root) ссылки, т.е. ссылки, непосредственно существующей в выполняемом коде.
Память освобождается сборщиком мусора по его собственному «усмотрению». Программа может успешно завершить работу, не исчерпав ресурсов свободной памяти или даже не приблизившись к этой черте и поэтому ей так и не потребуются «услуги» сборщика мусора.
Мусор собирается системой автоматически, без вмешательства пользователя или
программиста, но это не значит, что этот процесс не требует внимания вовсе. Необходимость создания и удаления большого количества объектов существенным образом сказывается на производительности приложений и если быстродействие программы является важным фактором, следует тщательно обдумывать решения, связанные с созданием объектов, — это, в свою очередь,
уменьшит и объем мусора, подлежащего утилизации.
Какие разновидности сборщиков мусора реализованы в виртуальной машине HotSpot?
Java HotSpot VM предоставляет разработчикам на выбор четыре различных сборщика мусора:
* Serial (последовательный) — самый простой вариант для приложений с небольшим объемом
данных и не требовательных к задержкам. На данный момент используется сравнительно редко, но на
слабых компьютерах может быть выбран виртуальной машиной в качестве сборщика по умолчанию.
Использование Serial GC включается опцией -XX:+UseSerialGC.
* Parallel (параллельный) — наследует подходы к сборке от последовательного сборщика, но добавляет параллелизм в некоторые операции, а также возможности по автоматической подстройке под требуемые параметры производительности. Параллельный сборщик включается опцией - XX:+UseParallelGC.
* Concurrent Mark Sweep (CMS) — нацелен на снижение максимальных задержек путем выполнения части работ по сборке мусора параллельно с основными потоками приложения. Подходит для работы с относительно большими объемами данных в памяти. Использование CMS GC включается опцией -XX:+UseConcMarkSweepGC.
* Garbage-First (G1) — создан для замены CMS, особенно в серверных приложениях, работающих на многопроцессорных серверах и оперирующих большими объемами данных. G1 включается опцией Java - XX:+UseG1GC.
Что такое Heap и Stack память в Java? Чем они отличаются?
Heap (куча) используется Java Runtime для выделения памяти под объекты и классы. Создание нового объекта также происходит в куче. Это же является областью работы сборщика мусора. Любой объект, созданный в куче, имеет глобальный доступ и на него могут ссылаться из любой части
приложения.
Stack (стек) это область хранения данных также находящееся в общей оперативной памяти (RAM) только для одного потока. Всякий раз, когда вызывается метод, в памяти стека создается новый блок, который содержит примитивы и ссылки на другие объекты в методе. Как только метод заканчивает работу, блок также перестает использоваться, тем самым предоставляя доступ для следующего
метода. Размер стековой памяти намного меньше объема памяти в куче. Стек в Java работает по схеме LIFO (Последний-зашел-Первый-вышел)
https://tproger.ru/translations/programming-concepts-stack-and-heap/
Различия между Heap и Stack памятью:
● Куча используется всеми частями приложения в то время как стек используется только одним потоком исполнения программы.
● Всякий раз, когда создается объект, он всегда хранится в куче, а в памяти стека содержится лишь ссылка на него. Память стека содержит только локальные переменные примитивных типов и
ссылки на объекты в куче.
● Объекты в куче доступны с любой точке программы, в то время как стековая память не может быть доступна для других потоков, только для одного потока.
● Стековая память существует лишь какое-то время работы программы, а память в куче живет с самого начала до конца работы программы.
● Если память стека полностью занята, то Java Runtime бросает исключение
java.lang.StackOverflowError. Если заполнена память кучи, то бросается исключение
java.lang.OutOfMemoryError: Java Heap Space.
● Размер памяти стека намного меньше памяти в куче.
● Из-за простоты распределения памяти, стековая память работает намного быстрее кучи.
Для определения начального и максимального размера памяти в куче используются -Xms и -Xmx опции JVM. Для стека определить размер памяти можно с помощью опции -Xss.
Размер стека задаётся при создании потока, и у каждой переменной есть максимальный размер, зависящий от типа данных, размер кучи ограничен оперативной памятью.
Верно ли утверждение, что примитивные типы данных всегда хранятся в стеке, а
экземпляры ссылочных типов данных в куче? Не совсем. Примитивное поле экземпляра класса хранится не в стеке, а в куче. Любой объект (всё,
что явно или неявно создаётся при помощи оператора new) хранится в куче.
Каким образом передаются переменные в методы, по значению или по ссылке?
В Java параметры всегда передаются только по значению, что определяется как «скопировать значение и передать копию». С примитивами это будет копия содержимого. Со ссылками - тоже копия содержимого, т.е. копия ссылки. При этом внутренние члены ссылочных типов через такую копию изменить возможно, а вот саму ссылку, указывающую на экземпляр - нет.
Какие примитивные типы данных есть в Java?
boolean, char, byte, short, int, long, float, double
boolean 1 bit NA false boolean bool = true;
char 16 bits Символы Unicode ‘\u0000′ или 0 char c = ‘A’;
byte 8 bits [-128,127] или [-2^7 to 2^7-1] 0 byte b = 10; byte b = 0b010;
short 16 bits [-32768,32767] 0 short s = 32; short s = ‘A’;
int 32 bits [-2147483648,2147483647] 0 int i = 10; int i = ‘A’;
long 64 bits [-2^63,2^63-1] 0 long l = 3200L; long l = 3200;
float 32 bits [-3.4E38, 3.4E38] 0.0f float f = (float) 12.34; float f = 12.34f;
double 64 bits [-1.7E308, 1.7E308] 0.0 double d = 12.34;
Что такое char? по умолчанию?
char — \u0000;
char - 16-разрядное беззнаковое целое, представляющее собой символ UTF-16 (буквы и
цифры)
Сколько памяти занимает boolean?
32 бита - булеан
Что такое классы-обертки?
Значение примитива становится объектом, чтобы выполнять различные операции ( .parseInt()). Примитивы не имеют методов. Объекты классов-оберток являются неизменяемыми (Immutable).
Что такое автоупаковка и автораспаковка?
Для присваивания ссылок-примитивов объектам их классов-оберток (и наоборот) не требуется ничего делать, все происходит автоматически int x = 7; Integer y = 111;
x = y; // автораспаковка y = x * 123; // автоупаковка Автоупаковка и распаковка не работают для массивов.
Автоупаковка - это механизм неявной инициализации объектов классов-оберток (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 нужно
использовать явное приведение? примеры
Каждое выражение и каждая переменная имеет строго определенный тип уже на момент компиляции. Механизм приведения типов (casting) - способ преобразования значения переменной одного типа в значение другого типа:
Неявные – выполняются автоматически (расширяющие преобразования, сужающие с потерей данных: int->float, long->float, long->double).
byte b = 7;
int d = b; // преобразование от byte к int
Явные – надо указывать тип (сужающие преобразования от типа с большей разрядностью к типу с меньшей разрядностью). Потеря данных (старшие биты будут потеряны).
Разновидности приведения:
- Тождественное (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;
}
Что такое пул интов?
Для более эффективного использования памяти, в джаве используются так называемые пулы.
Есть строковый пул, Integer pool итд. Когда мы создаем объект не используя операцию new, объект
помещается в пул, и в последствии, если мы захотим создать такой же объект (опять не используя
new), новый объект создан не будет, а мы просто получим ссылку на наш объект из пула.
Особенность Integer-пула — он хранит только числа, которые помещаются в тип данных byte:
от -128 до 127. Для остальных чисел пул не работает.
Integer i1 = 127;
Integer i2 = 127;
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i1==i2);//true
System.out.println(i3==i4);//false
Какие нюансы у строк в Java?
● Это неизменяемый (immutable) (не меняется после создания) и финализированный (без
потомков) тип данных; потокобезопасный может использоваться в многопоточке
● Все объекты класса String JVM хранит в пуле строк;
● Объект класса String можно получить используя двойные кавычки;
● Можно использовать оператор + для конкатенации строк;
● Начиная с Java 7 строки можно использовать в конструкции switch.
* Каждый объект можно привести к строке .toString
Cтроки представляют собой массив символов (так было до Java 9).
Начиная с Java 9 строки хранятся как массив байт.
Что такое пул строк?
Стринг хранит под капотом в виде массива байтов
Пул строк – это набор строк хранящийся в Heap.
Пул строк возможен благодаря неизменяемости строк в Java и реализации идеи
интернирования строк;
Пул строк помогает экономить память, но по этой же причине создание строки занимает большевремени; Когда для создания строки используются “, то сначала ищется строка в пуле с таким же значением, если находится, то просто возвращается ссылка, иначе создается новая строка в пуле, а затем возвращается ссылка на неё;
String habr = “habrahabr”; - “строковый литерал”
При использовании оператора new создается новый объект String. Затем при помощи метода intern() эту строку можно поместить в пул или же получить из пула ссылку на другой объект String с таким же значением;
Пул строк является примером паттерна «Приспособленец» (Flyweight).
Почему не рекомендуется изменять строки в цикле? Что рекомендуется
использовать?
Применить StringBuilder до цикла, в цикле .append
String s5 = “I’m “;
String s6 = “ + Java developer”;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 8; i++) {
System.out.println(sb.append(s5).append(s6));
}
Почему строки не рекомендуется использовать для хранения паролей?
С момента создания строка остается в пуле, до тех пор пока не будет удалена сборщиком мусора. Поэтому, даже после окончания использования пароля, он некоторое время продолжает оставаться доступным в памяти и способа избежать этого не существует. Это представляет определённый риск для безопасности, поскольку кто-либо, имеющий доступ к памяти сможет найти пароль в виде текста. В случае использования массива символов для хранения пароля имеется
возможность очистить его сразу по окончанию работы с паролем, позволяя избежать риска безопасности, свойственного строке.
Почему String неизменяемый и финализированный класс?
Пул строк возможен только потому, что строка неизменяемая, таким образом виртуальная машина сохраняет больше свободного места в Heap, поскольку разные строковые переменные указывают на одну и ту же переменную в пуле. Если бы строка была изменяемой, то интернирование строк не было бы возможным, потому что изменение значения одной переменной отразилось бы также и на остальных переменных, ссылающихся на эту строку.
* Если строка будет изменяемой, тогда это станет серьезной угрозой безопасности приложения. Например, имя пользователя базы данных и пароль передаются строкой для получения соединения с базой данных и в программировании сокетов реквизиты хоста и порта передаются строкой. Так как строка неизменяемая, её значение не может быть изменено, в противном случае злоумышленник
может изменить значение ссылки и вызвать проблемы в безопасности приложения.
* Неизменяемость позволяет избежать синхронизации: строки безопасны для многопоточности и один экземпляр строки может быть совместно использован различными потоками.
* Строки используются classloader-ом и неизменность обеспечивает правильность загрузки класса.
* Поскольку строка неизменяемая, её hashCode() кэшируется в момент создания и нет необходимости рассчитывать его снова. Это делает строку отличным кандидатом для ключа в HashMap т.к. егообработка происходит быстрее.
Почему строка является популярным ключом в HashMap в Java?
Поскольку строка неизменяемая, её hashCode() кэшируется в момент создания и нет необходимости рассчитывать его снова. Это делает строку отличным кандидатом для ключа в HashMap т.к. его обработка происходит быстрее.
Что делает метод intern() в классе String?
Метод intern() используется для сохранения строки в пуле строк или получения ссылки, если
такая строка уже находится в пуле.
String q = “I’m”;
String w = “I’m”;
String r = new String(“I’m”);
String t = r.intern();
System.out.println(“q==w: “+(q==w)); //true
System.out.println(“q==r: “+(q==r)); //false
System.out.println(“q==t: “+(q==t)); //true
Можно ли использовать строки в конструкции switch?
Да, начиная с Java 7 в операторе switch можно использовать строки, ранние версии Java не поддерживают этого. При этом:
- участвующие строки чувствительны к регистру;
- используется метод equals() для сравнения полученного значения со значениями case, поэтому во избежание NullPointerException стоит предусмотреть проверку на null.
- согласно документации Java 7 для строк в switch, компилятор Java формирует более эффективный байткод для строк в конструкции switch, чем для сцепленных условий if-else.
Какая основная разница между String, StringBuffer, StringBuilder?
Класс String является неизменяемым (immutable) - модифицировать объект такого класса нельзя, можно лишь заменить его созданием нового экземпляра.
Класс StringBuffer изменяемый - использовать StringBuffer следует тогда, когда необходимо часто модифицировать содержимое. Потокобезопасный. Синхронизированные методы работают медленнее не сихнронизированных.
Класс StringBuilder был добавлен в Java 5 и он во всем идентичен классу StringBuffer за исключением того, что он не синхронизирован и поэтому его методы выполняются значительно быстрей.
Класс StringJoiner используется, чтобы создать последовательность строк, разделенных разделителем с возможностью присоединить к полученной строке префикс и суффикс:
StringJoiner joiner = new StringJoiner(“.”, “prefix-“, “-suffix”);
for (String s : “Hello the brave world”.split(“ “)) {
joiner.add(s);
}
System.out.println(joiner); //prefix-Hello.the.brave.world-suffix
Существуют ли в java многомерные массивы?
Да, смотря как понимать
понятие, пусть многомерный массив в Джава - массив в массиве (зубчатый массив),
могут раскиданы по памяти, влияет на производительность.
Какими значениями инициируются переменные по умолчанию?
Числа инициализируются 0 или 0.0;
char — \u0000;
boolean — false;
Объекты (в том числе String) — null.
Что такое сигнатура метода?
Название метода и типы параметров в определенном порядке
public void method(double a, int b)
Контракт метода - эксепшены
Расскажите про метод main если местами поменять паблик и статик – все норм
запуститься? можно запускать без маина прогу.
Можно поменять, да запуститься.
Можно было запустить в Java 6 и более ранних версиях статическим блоком с exit(). Теперь нет.
Каким образом переменные передаются в методы, по значению или по ссылке?
int х = 3;
int у = х; “скопировать значение внутри х и записать эту копию в у”
Java передает параметры по значению. Всегда.
Cat A = new Cat ();
Cat B = A;
Ссылка А копируется в ссылку B. К объекту это не относится — у вас по прежнему всего одинобъект.
Но теперь у вас есть две различных ссылки, контролирующие один и тот же объект Cat.
Какие виды классов есть в java?
Top level class (Обычный класс):
- Abstract class (Абстрактный класс);
-Final class (Финализированный класс).
Interfaces (Интерфейс).
Enum (Перечисление).
Nested class (Вложенный класс):
-Static nested class (Статический вложенный класс);
-Member inner class (Простой внутренний класс);
-Local inner class (Локальный класс);
-Anonymous inner class (Анонимный вложенный класс).
К классам верхнего уровня модификатор static неприменим.
Расскажите про вложенные классы. В каких случаях они применяются?
Класс называется вложенным (Nested class), если он определен внутри другого класса.
Вложенный класс должен создаваться только для того, чтобы обслуживать обрамляющий его
класс. Если вложенный класс оказывается полезен в каком-либо ином контексте, он должен
стать классом верхнего уровня. Вложенные классы имеют доступ ко всем (в том числе
приватным) полям и методам внешнего класса, но не наоборот. Из-за этого разрешения
использование вложенных классов приводит к некоторому нарушению инкапсуляции.
Существуют четыре категории вложенных классов:
+ Static nested class (Статический вложенный класс);
+ Member inner class (Простой внутренний класс);
+ Local inner class (Локальный класс);
+ Anonymous inner class (Анонимный класс).
Такие категории классов, за исключением первого, также называют внутренними (Inner class).
Внутренние классы ассоциируются не с внешним классом, а с экземпляром внешнего.
Каждая из категорий имеет рекомендации по своему применению:
● Не статический: если вложенный класс должен быть виден за пределами одного метода или
он слишком длинный для того, чтобы его можно было удобно разместить в границах одного метода
и если каждому экземпляру такого класса необходима ссылка на включающий его экземпляр.
● Статический: если ссылка на обрамляющий класс не требуется.
Доступ к полям стат. и нестат. класса
● Локальный: если класс необходим только внутри какого-то метода и требуется создавать
экземпляры этого класса только в этом методе.
● Анонимный: если к тому же применение класса сводится к использованию лишь в одном
месте и уже существует тип, характеризующий этот класс.
Что такое «локальный класс»? Каковы его особенности?
Local inner class (Локальный класс) - это вложенный класс, который может быть декларированв любом блоке, в котором разрешается декларировать переменные. Как и простые внутренниеклассы (Member inner class) локальные классы имеют имена и могут использоваться многократно.
Как и анонимные классы, они имеют окружающий их экземпляр только тогда, когда применяются внестатическом контексте.
Локальные классы имеют следующие особенности:
● Видны только в пределах блока, в котором объявлены;
● Не могут быть объявлены как private/public/protected или static;
● Не могут иметь внутри себя статических объявлений (полей, методов, классов);
● Имеют доступ к полям и методам обрамляющего класса;
● Могут обращаться к локальным переменным и параметрам метода, если они объявлены с модификатором final.
Что такое «анонимные классы»? Где они применяются?
Это вложенный локальный класс без имени, который разрешено декларировать в любом месте обрамляющего класса, разрешающем размещение выражений. Создание экземпляра анонимного класса происходит одновременно с его объявлением. В зависимости от местоположения анонимный класс ведет себя как статический либо как нестатический вложенный класс - в нестатическом контексте появляется окружающий его экземпляр.
Анонимные классы имеют несколько ограничений:
● Их использование разрешено только в одном месте программы - месте его создания;
● Применение возможно только в том случае, если после порождения экземпляра нет необходимости на него ссылаться;
● Реализует лишь методы своего интерфейса или суперкласса, т.е. не может объявлять каких- либо новых методов, так как для доступа к ним нет поименованного типа.
Анонимные классы обычно применяются для:
● создания объекта функции (function object), например реализация интерфейса Comparator;
● создания объекта процесса (process object), такого как экземпляры классов Thread, Runnable и подобных;
● в статическом методе генерации;
● инициализации открытого статического поля final, которое соответствует сложному перечислению типов, когда для каждого экземпляра в перечислении требуется отдельный подкласс.
Каким образом из вложенного класса получить доступ к полю внешнего класса?
Статический вложенный класс имеет прямой доступ только к статическим полям
обрамляющего класса.
Простой внутренний класс, может обратиться к любому полю внешнего класса напрямую. В случае, если у вложенного класса уже существует поле с таким же литералом, то обращаться к такому полю следует через ссылку на его экземпляр. Например: Outer.this.field.
Что такое перечисления (enum)?
Перечисления представляют набор логически связанных констант. Объявление перечисления происходит с помощью оператора enum, после которого идет название перечисления. Затем идет список элементов перечисления через запятую. Каждый из них явно объявлен как открытый статический финальный член класса. values(). Он возвращает массив всех констант перечисления
Особенности Enum классов:
1) Конструктор всегда private или default
2) Могут имплементировать интерфейсы
3) Не могут наследовать класс
4) Можем переопределить toString()
5) Нет public конструктора, поэтому нельзя создать экземпляр вне Enum
6) При equals() выполняется ==
7) ordinal() возвращает порядок элементов
8) Может использоваться в TreeSet и TreeMap т.к. Enum имплементирует Comparable
9) compareTo() имитирует порядок элементов предоставляемый ordinal()
10) Можно использовать в Switch Case
11) values() возвращает массив всех констант
12) Легко создать потокобезопасный синглтон без double check volatile переменных.
Как проблема ромбовидного наследования решена в java?
Интерфейсы
Что такое конструктор по умолчанию?
Если у какого-либо класса не определить конструктор, то компилятор сгенерирует конструктор без аргументов - так называемый «конструктор по умолчанию».
Если вы создали сами конструктор, то конструктор по умолчанию использоваться не будет(если он не создан).
Могут ли быть приватные конструкторы? Для чего они нужны?
Приватный (помеченный ключевым словом private, скрытый) конструктор может
использоваться публичным статическим методом генерации объектов данного класса. Также доступ к нему разрешен вложенным классам и может использоваться для их нужд запрещает создание экземпляра класса вне методов самого класса, например, чтобы гарантировать существование только одного объекта определённого класса, предположим какого- то ресурса, например БД.