Основы ООП в Java
Глава 3. Наследование
Расширение классов с extends
Наследование — это механизм ООП, который позволяет создавать новый класс (подкласс или дочерний класс) на основе существующего (суперкласс или родительский класс). Подкласс "наследует" поля, методы и поведение суперкласса, добавляя или расширяя их. Это воплощает принцип "is-a" (является): например, "Собака является Животным".
Преимущества наследования:
Переиспользование кода: Не нужно дублировать общий код — подклассы используют то, что уже есть в суперклассе.
Иерархия: Позволяет строить иерархии классов, моделируя реальный мир (например, Животное → Млекопитающее → Собака).
Расширяемость: Подкласс может добавлять новые поля/методы или изменять поведение, не трогая суперкласс.
Полиморфизм: Наследование закладывает основу для полиморфизма (об этом в следующей главе).
В Java наследование реализуется с помощью ключевого слова extends. Java поддерживает только одиночное наследование (один суперкласс), но множественное — через интерфейсы.
Расширение классов с extends: Основы
Чтобы создать подкласс, используйте extends после имени класса, указав суперкласс.
Синтаксис:
Подкласс автоматически наследует все non-private поля и методы суперкласса.
Конструкторы не наследуются — их нужно определять заново, но можно вызывать конструктор суперкласса с super().
Пример базового суперкласса Animal:
Теперь подкласс Dog, расширяющий Animal:
Dog наследует name, eat() и getAge() от Animal.
super(name, age): Обязательно вызывает конструктор суперкласса (если он не по умолчанию). Должен быть первой строкой в конструкторе подкласса.
Новый метод bark(): Расширение поведения.
#Java #для_новичков #beginner #extends
Глава 3. Наследование
Расширение классов с extends
Наследование — это механизм ООП, который позволяет создавать новый класс (подкласс или дочерний класс) на основе существующего (суперкласс или родительский класс). Подкласс "наследует" поля, методы и поведение суперкласса, добавляя или расширяя их. Это воплощает принцип "is-a" (является): например, "Собака является Животным".
Преимущества наследования:
Переиспользование кода: Не нужно дублировать общий код — подклассы используют то, что уже есть в суперклассе.
Иерархия: Позволяет строить иерархии классов, моделируя реальный мир (например, Животное → Млекопитающее → Собака).
Расширяемость: Подкласс может добавлять новые поля/методы или изменять поведение, не трогая суперкласс.
Полиморфизм: Наследование закладывает основу для полиморфизма (об этом в следующей главе).
В Java наследование реализуется с помощью ключевого слова extends. Java поддерживает только одиночное наследование (один суперкласс), но множественное — через интерфейсы.
Расширение классов с extends: Основы
Чтобы создать подкласс, используйте extends после имени класса, указав суперкласс.
Синтаксис:
public class Подкласс extends Суперкласс {
// Дополнительные поля и методы
}
Подкласс автоматически наследует все non-private поля и методы суперкласса.
Конструкторы не наследуются — их нужно определять заново, но можно вызывать конструктор суперкласса с super().
Пример базового суперкласса Animal:
public class Animal {
protected String name; // Protected: доступно в подклассах
private int age; // Private: не видно в подклассах напрямую
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(name + " ест.");
}
// Геттер для age (чтобы подклассы могли читать)
public int getAge() {
return age;
}
}
Теперь подкласс Dog, расширяющий Animal:
public class Dog extends Animal {
private String breed; // Новое поле
// Конструктор: Вызывает суперкласс с super()
public Dog(String name, int age, String breed) {
super(name, age); // Вызов конструктора Animal
this.breed = breed;
}
// Новый метод
public void bark() {
System.out.println(name + " лает: Гав!");
}
// Наследованный метод eat() доступен автоматически
}
Dog наследует name, eat() и getAge() от Animal.
super(name, age): Обязательно вызывает конструктор суперкласса (если он не по умолчанию). Должен быть первой строкой в конструкторе подкласса.
Новый метод bark(): Расширение поведения.
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Шарик", 5, "Лабрадор");
dog.eat(); // Наследованный: Шарик ест.
dog.bark(); // Новый: Шарик лает: Гав!
System.out.println("Возраст: " + dog.getAge()); // Возраст: 5
}
}
#Java #для_новичков #beginner #extends
👍4
Все нюансы расширения классов
Модификаторы доступа и наследование:
public: Наследуется и доступно везде.
protected: Наследуется и доступно в подклассах (даже в других пакетах) и в пакете суперкласса.
default (без модификатора): Наследуется только в том же пакете.
private: Не наследуется напрямую — подкласс не видит private-поля/методы. Используйте геттеры/сеттеры для доступа.
В примере name protected, так что Dog может использовать this.name.
Конструкторы в наследовании:
Конструкторы не наследуются.
Если суперкласс имеет конструктор с параметрами, подкласс должен вызвать его с super(параметры).
Если суперкласс имеет только дефолтный конструктор, super() вызывается автоматически.
Нюанс: Если подкласс не вызывает super(), Java вставит super() без параметров. Если такого нет — ошибка компиляции.
Перегрузка: Подкласс может иметь несколько конструкторов, каждый вызывающий super().
Иерархия и класс Object:
Все классы в Java implicitly наследуют от java.lang.Object (если не указано extends).
Методы Object, такие как toString(), equals(), hashCode(), наследуются всеми классами.
Нюанс: Если вы extends другой класс, он уже наследует Object косвенно.
Одиночное наследование:
Java не поддерживает множественное наследование классов (extends A, B — ошибка). Это избегает "проблемы ромба" (конфликты при наследовании от двух классов с общим предком).
Для множественности используйте интерфейсы (об этом в главе об абстракции).
Final классы и методы:
Если суперкласс помечен final (final class Super {}), его нельзя extends — ошибка. (Например, String final.)
Нюанс: Это для immutable или secure классов.
Пакеты и видимость:
Если суперкласс в другом пакете, подкласс должен импортировать его (import package.Super;) или использовать полное имя.
Protected члены видимы в подклассах, даже в разных пакетах.
Ошибки и исключения:
Если подкласс пытается extends несуществующий класс — ошибка компиляции.
Циклическое наследование (A extends B, B extends A) — запрещено.
Подкласс может быть abstract, даже если суперкласс не abstract.
Производительность и дизайн:
Наследование — мощный инструмент, но не злоупотребляйте: предпочитайте композицию (has-a) над наследованием (is-a), если возможно, чтобы избежать жесткой связи.
Нюанс: Глубокие иерархии (много уровней) могут усложнить код — старайтесь держать 2-3 уровня.
Как создать это в IntelliJ IDEA
Создайте суперкласс:
New → Java Class → Animal.
Создайте подкласс:
New → Java Class → Dog.
IntelliJ предложит extends: В коде напишите extends Animal — IDE подскажет импорт.
Генерация конструктора:
В Dog: Generate → Constructor → Выберите поля, и укажите super.
Запустите: В Main создайте объект Dog и протестируйте.
Полезные советы для новичков
Используйте protected: Для полей/методов, которые нужны подклассам, но не внешнему коду.
Вызывайте super() первым: Всегда в начале конструктора — иначе ошибка.
Тестируйте наследование: Создавайте объекты подкласса и вызывайте наследованные методы.
Избегайте глубоких иерархий: Лучше плоская структура для простоты.
#Java #для_новичков #beginner #extends
Модификаторы доступа и наследование:
public: Наследуется и доступно везде.
protected: Наследуется и доступно в подклассах (даже в других пакетах) и в пакете суперкласса.
default (без модификатора): Наследуется только в том же пакете.
private: Не наследуется напрямую — подкласс не видит private-поля/методы. Используйте геттеры/сеттеры для доступа.
В примере name protected, так что Dog может использовать this.name.
Конструкторы в наследовании:
Конструкторы не наследуются.
Если суперкласс имеет конструктор с параметрами, подкласс должен вызвать его с super(параметры).
Если суперкласс имеет только дефолтный конструктор, super() вызывается автоматически.
Нюанс: Если подкласс не вызывает super(), Java вставит super() без параметров. Если такого нет — ошибка компиляции.
Перегрузка: Подкласс может иметь несколько конструкторов, каждый вызывающий super().
Иерархия и класс Object:
Все классы в Java implicitly наследуют от java.lang.Object (если не указано extends).
Методы Object, такие как toString(), equals(), hashCode(), наследуются всеми классами.
Нюанс: Если вы extends другой класс, он уже наследует Object косвенно.
Одиночное наследование:
Java не поддерживает множественное наследование классов (extends A, B — ошибка). Это избегает "проблемы ромба" (конфликты при наследовании от двух классов с общим предком).
Для множественности используйте интерфейсы (об этом в главе об абстракции).
Final классы и методы:
Если суперкласс помечен final (final class Super {}), его нельзя extends — ошибка. (Например, String final.)
Нюанс: Это для immutable или secure классов.
Пакеты и видимость:
Если суперкласс в другом пакете, подкласс должен импортировать его (import package.Super;) или использовать полное имя.
Protected члены видимы в подклассах, даже в разных пакетах.
Ошибки и исключения:
Если подкласс пытается extends несуществующий класс — ошибка компиляции.
Циклическое наследование (A extends B, B extends A) — запрещено.
Подкласс может быть abstract, даже если суперкласс не abstract.
Производительность и дизайн:
Наследование — мощный инструмент, но не злоупотребляйте: предпочитайте композицию (has-a) над наследованием (is-a), если возможно, чтобы избежать жесткой связи.
Нюанс: Глубокие иерархии (много уровней) могут усложнить код — старайтесь держать 2-3 уровня.
Как создать это в IntelliJ IDEA
Создайте суперкласс:
New → Java Class → Animal.
Создайте подкласс:
New → Java Class → Dog.
IntelliJ предложит extends: В коде напишите extends Animal — IDE подскажет импорт.
Генерация конструктора:
В Dog: Generate → Constructor → Выберите поля, и укажите super.
Запустите: В Main создайте объект Dog и протестируйте.
Полезные советы для новичков
Используйте protected: Для полей/методов, которые нужны подклассам, но не внешнему коду.
Вызывайте super() первым: Всегда в начале конструктора — иначе ошибка.
Тестируйте наследование: Создавайте объекты подкласса и вызывайте наследованные методы.
Избегайте глубоких иерархий: Лучше плоская структура для простоты.
#Java #для_новичков #beginner #extends
👍4
Как Вы считаете: есть ли сейчас возможность устроиться на позицию Junior, или лучше сразу идти на Middle?
Anonymous Poll
24%
Надо искать позицию Junior, чтобы развиваться постепенно и правильно. 🧑💻
22%
Я хотел бы устроиться правильным Junior, но вакансий нет 🤬
20%
Сейчас компаниям не нужны Junior, нужно искать вакансии сразу в Middle. 🙂
11%
Я вообще подготовлен как Middle (только реального опыта нет пока) и я вообще не пойду на Junior
16%
Мне пофиг на какой грейд идти, лишь бы деньги платили нормальные 🫰
7%
Я думаю сразу идти на Senior. Не ну а чо? 💃
👍1
Что выведет код?
#Tasks
class A270825 {
String value = "A";
void print() {
System.out.println(value);
}
}
class B270825 extends A270825 {
String value = "B";
}
public class Task270825 {
public static void main(String[] args) {
A270825 obj = new B270825();
obj.print();
System.out.println(obj.value);
}
}
#Tasks
👍2
👍2
Вопрос с собеседований
Что такое escape analysis в JVM?🤓
Ответ:
Escape analysis — оптимизация JIT-компилятора JVM, которая определяет, может ли объект "убежать" из метода (например, быть возвращенным или сохраненным в поле). Если объект не убегает, он может быть размещен на стеке вместо кучи, снижая нагрузку на GC. Пример: локальный объект в методе, не выходящий за его пределы.
Это улучшает производительность, но прозрачно для разработчика.
#собеседование
Что такое escape analysis в JVM?
Ответ:
Это улучшает производительность, но прозрачно для разработчика.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Джошуа Блох (англ. Joshua J. Bloch) (род. 28 августа 1961 г.) — архитектор Java-платформы (Collections, concurrency, API-дизайн), автор «Effective Java».
Ше́рил Ка́ра Сэ́ндберг (англ. Sheryl Kara Sandberg[2], род. 28 августа 1969, Вашингтон) — техно-топ-менеджер (Meta/Facebook), сыграла ключевую роль в масштабировании рекламной и бизнес-инфраструктуры.
Сатоси Тадзири (яп. 田尻智 Тадзири Сатоси, род. 28 августа 1965 года) — японский геймдизайнер, создатель серии игр, манги и сериала «Покемон». Он вошёл в список ста самых лучших геймдизайнеров по версии IGN.
2009 — прекращена служба AppleTalk — одно из первых сетевых решений Apple для локального обмена данными, признанное устаревшим.
#Biography #Birth_Date #Events #28Августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Основы ООП в Java
Переопределение и ключевое слово super
Что такое переопределение методов в ООП?
Переопределение (method overriding) — это возможность подкласса предоставить свою реализацию метода, унаследованного от суперкласса. Это воплощает полиморфизм: объект подкласса может вести себя иначе, чем суперкласс, но сохранять ту же сигнатуру метода.
Когда использовать: Если поведение суперкласса не подходит для подкласса, но имя и параметры метода должны остаться теми же (например, все животные едят, но собака ест по-своему).
Правила переопределения:
Сигнатура метода (имя, параметры) должна быть идентичной суперклассу.
Тип возвращаемого значения может быть подтипом (covariant return type) в Java 5+.
Модификатор доступа не может быть строже (например, если в супер protected, в подклассе нельзя private, но можно public).
Метод в суперкласса не должен быть final или static (static не переопределяются, а скрываются).
Аннотация @Override: Рекомендуется добавлять для проверки компилятором — если метод не переопределяет, ошибка.
Нюанс: Переопределение отличается от перегрузки (overloading) — перегрузка: разные сигнатуры в одном классе; переопределение: одинаковые сигнатуры в иерархии.
Ключевое слово super: Доступ к суперклассу
super — это ссылка на суперкласс, аналог this для родителя.
Оно используется для:
Вызова методов суперкласса (super.method()).
Доступа к полям суперкласса (super.field), если они скрыты.
Вызова конструктора суперкласса (super(params)).
super полезно, когда в подклассе переопределен метод, но нужно вызвать оригинальную версию из суперкласса.
Подробный пример
Возьмем класс: Animal (суперкласс) и Dog (подкласс).
Суперкласс Animal:
Подкласс Dog с переопределением:
Нюанс: Если поле в подклассе скрывает поле суперкласса (field hiding, редко рекомендуется), super.field дает доступ к скрытому.
#Java #для_новичков #beginner #extends #super
Переопределение и ключевое слово super
Что такое переопределение методов в ООП?
Переопределение (method overriding) — это возможность подкласса предоставить свою реализацию метода, унаследованного от суперкласса. Это воплощает полиморфизм: объект подкласса может вести себя иначе, чем суперкласс, но сохранять ту же сигнатуру метода.
Когда использовать: Если поведение суперкласса не подходит для подкласса, но имя и параметры метода должны остаться теми же (например, все животные едят, но собака ест по-своему).
Правила переопределения:
Сигнатура метода (имя, параметры) должна быть идентичной суперклассу.
Тип возвращаемого значения может быть подтипом (covariant return type) в Java 5+.
Модификатор доступа не может быть строже (например, если в супер protected, в подклассе нельзя private, но можно public).
Метод в суперкласса не должен быть final или static (static не переопределяются, а скрываются).
Аннотация @Override: Рекомендуется добавлять для проверки компилятором — если метод не переопределяет, ошибка.
Нюанс: Переопределение отличается от перегрузки (overloading) — перегрузка: разные сигнатуры в одном классе; переопределение: одинаковые сигнатуры в иерархии.
Ключевое слово super: Доступ к суперклассу
super — это ссылка на суперкласс, аналог this для родителя.
Оно используется для:
Вызова методов суперкласса (super.method()).
Доступа к полям суперкласса (super.field), если они скрыты.
Вызова конструктора суперкласса (super(params)).
super полезно, когда в подклассе переопределен метод, но нужно вызвать оригинальную версию из суперкласса.
Подробный пример
Возьмем класс: Animal (суперкласс) и Dog (подкласс).
Суперкласс Animal:
public class Animal {
protected String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(name + " ест пищу.");
}
public int getAge() {
return age;
}
}
Подкласс Dog с переопределением:
public class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age); // Вызов конструктора суперкласса
this.breed = breed;
}
// Переопределение метода eat()
@Override // Аннотация для проверки
public void eat() {
super.eat(); // Вызов версии из суперкласса
System.out.println("Но предпочитает кости!"); // Расширение поведения
}
public void bark() {
System.out.println(name + " лает: Гав!");
}
}
Аннотация @Override: Указывает, что метод переопределен. Если ошибка (например, сигнатура не совпадает) — компилятор предупредит.
super.eat(): Вызывает оригинальный eat() из Animal, затем добавляет свое.
Если убрать super.eat(), метод полностью заменит поведение суперкласса.
Нюанс: Если поле в подклассе скрывает поле суперкласса (field hiding, редко рекомендуется), super.field дает доступ к скрытому.
#Java #для_новичков #beginner #extends #super
👍3
Все нюансы переопределения и super
Сигнатура и совместимость:
Имя, количество/типы параметров должны совпадать точно.
Возврат: Может быть подтипом (например, супер возвращает Animal, под — Dog).
Исключения: Подкласс может бросать меньше или подтипы исключений, но не больше (checked exceptions).
Модификаторы:
Доступ: Может быть шире (protected → public), но не уже (public → protected — ошибка).
Final: Final-методы нельзя переопределять.
Static: Static-методы не переопределяются — это method hiding. Вызов зависит от типа ссылки, не объекта.
Private: Private-методы не видны, так что не переопределяются.
super в конструкторах:
Должен быть первой строкой.
Если не указан, Java вставит super() без параметров.
Нюанс: В цепочке иерархий (A extends B extends C) конструкторы вызываются сверху вниз: C() → super(B) → super(A).
super для методов и полей:
super.method(): Вызывает версию суперкласса, даже если переопределен.
Полезно для расширения, а не замены поведения.
Нюанс: super не работает для static — используйте SuperClass.method().
Field hiding: Если подкласс имеет поле с тем же именем, super.field дает доступ к суперклассу.
Ошибки компиляции и runtime:
Без @Override: Если сигнатура не совпадает, создастся новый метод (overloading вместо overriding) — неожиданное поведение.
Runtime: Если метод не переопределен правильно, вызовется версия суперкласса.
Abstract методы: Должны быть переопределены в non-abstract подклассах.
Полиморфизм и overriding:
Вызов метода зависит от типа объекта, не ссылки: Animal a = new Dog(); a.eat() — вызовет Dog.eat().
Нюанс: Для полей — наоборот, зависит от типа ссылки (field hiding, не overriding).
Дизайн и лучшие практики:
Переопределяйте только когда нужно изменить поведение.
Используйте super для композиции поведения.
Избегайте переопределения для радикальных изменений — лучше новый метод.
В больших иерархиях: Документируйте, что можно переопределять.
Как создать это в IntelliJ IDEA
Переопределение метода:
В подклассе Dog: Ctrl+O (Override Methods) → Выберите eat() — IDE добавит @Override и скелет.
Добавьте super:
В сгенерированном методе вставьте super.eat().
Проверка: IDE подскажет ошибки в сигнатуре или доступе.
Полезные советы для новичков
Всегда используйте @Override: Избегайте ошибок.
Тестируйте полиморфно: Создавайте ссылки суперкласса на объекты подкласса и проверяйте вызовы.
super в конструкторах: Не забывайте, если суперкласс требует параметров.
Избегайте field hiding: Лучше разные имена для полей.
#Java #для_новичков #beginner #extends #super
Сигнатура и совместимость:
Имя, количество/типы параметров должны совпадать точно.
Возврат: Может быть подтипом (например, супер возвращает Animal, под — Dog).
Исключения: Подкласс может бросать меньше или подтипы исключений, но не больше (checked exceptions).
Модификаторы:
Доступ: Может быть шире (protected → public), но не уже (public → protected — ошибка).
Final: Final-методы нельзя переопределять.
Static: Static-методы не переопределяются — это method hiding. Вызов зависит от типа ссылки, не объекта.
Private: Private-методы не видны, так что не переопределяются.
super в конструкторах:
Должен быть первой строкой.
Если не указан, Java вставит super() без параметров.
Нюанс: В цепочке иерархий (A extends B extends C) конструкторы вызываются сверху вниз: C() → super(B) → super(A).
super для методов и полей:
super.method(): Вызывает версию суперкласса, даже если переопределен.
Полезно для расширения, а не замены поведения.
Нюанс: super не работает для static — используйте SuperClass.method().
Field hiding: Если подкласс имеет поле с тем же именем, super.field дает доступ к суперклассу.
Ошибки компиляции и runtime:
Без @Override: Если сигнатура не совпадает, создастся новый метод (overloading вместо overriding) — неожиданное поведение.
Runtime: Если метод не переопределен правильно, вызовется версия суперкласса.
Abstract методы: Должны быть переопределены в non-abstract подклассах.
Полиморфизм и overriding:
Вызов метода зависит от типа объекта, не ссылки: Animal a = new Dog(); a.eat() — вызовет Dog.eat().
Нюанс: Для полей — наоборот, зависит от типа ссылки (field hiding, не overriding).
Дизайн и лучшие практики:
Переопределяйте только когда нужно изменить поведение.
Используйте super для композиции поведения.
Избегайте переопределения для радикальных изменений — лучше новый метод.
В больших иерархиях: Документируйте, что можно переопределять.
Как создать это в IntelliJ IDEA
Переопределение метода:
В подклассе Dog: Ctrl+O (Override Methods) → Выберите eat() — IDE добавит @Override и скелет.
Добавьте super:
В сгенерированном методе вставьте super.eat().
Проверка: IDE подскажет ошибки в сигнатуре или доступе.
Полезные советы для новичков
Всегда используйте @Override: Избегайте ошибок.
Тестируйте полиморфно: Создавайте ссылки суперкласса на объекты подкласса и проверяйте вызовы.
super в конструкторах: Не забывайте, если суперкласс требует параметров.
Избегайте field hiding: Лучше разные имена для полей.
#Java #для_новичков #beginner #extends #super
👍5
Какая зп в месяц для Вас была бы достаточной для жизни без излишеств (роскоши, ежемесячных поездок в тайланд и тд)?
Anonymous Poll
4%
30-50 тысяч
9%
50-80 тысяч
27%
80-120 тысяч
47%
120-300 тысяч
13%
Более 300 тысяч
👍4
Тестирование в Spring
4. Интеграционные тесты в Spring.
Тестирование БД (Zonky, Testcontainers, SQL-скрипты, Liquibase).
Серия видео посвященная тестированию всего и вся в Spring.
Что мы рассмотрели:
🔵 Как в целом поднять интеграционные тесты с БД и зачем нам это вообще.
🔵 Различные способы внедрения тестовых данных в тест и базу данных (Json, SQL, Faker, Instancio).
🔵 Запуск тестовой БД PostgresQL в памяти JVM (Zonky) и контейнере Docker(Testcontainers).
🔵 Как можно ошибиться и не найти ошибку)))
Ссылка на Youtube
Ссылка на Рутьюб
Ссылка на GitHub - жду ваших звезд☺️
Смотрите, ставьте лайки, подписывайтесь на каналы!✌️
4. Интеграционные тесты в Spring.
Тестирование БД (Zonky, Testcontainers, SQL-скрипты, Liquibase).
Серия видео посвященная тестированию всего и вся в Spring.
Что мы рассмотрели:
Ссылка на Youtube
Ссылка на Рутьюб
Ссылка на GitHub - жду ваших звезд
Смотрите, ставьте лайки, подписывайтесь на каналы!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Что выведет код?
#Tasks
class A280525 {
String message = "A";
void print() {
System.out.println(message);
}
}
class B280525 extends A280525 {
String message = "B";
void print() {
super.print();
System.out.println(message);
}
}
class C280525 extends B280525 {
String message = "C";
void print() {
super.print();
System.out.println(message);
}
}
public class Task280825 {
public static void main(String[] args) {
A280525 obj = new C280525();
obj.print();
}
}
#Tasks
👍3🔥1
Варианты ответа:
Anonymous Quiz
10%
"A" затем "B"
15%
"A" затем "C"
10%
"C" затем "C"
50%
"A" затем "B" затем "C"
15%
Ошибка компиляции
👍4
Вопрос с собеседований
Что такое inner class и его типы?🤓
Ответ:
Inner class — класс, определенный внутри другого класса.
Типы:
Static nested class: принадлежит классу, не имеет доступа к нестатическим членам.
Non-static inner class: имеет доступ к членам внешнего класса.
Local class: в методе.
Anonymous class: без имени, для одноразового использования.
Пример non-static:
class Outer {
private int x = 10;
class Inner { void print() { System.out.println(x); } }
}
Полезны для инкапсуляции логики.
#собеседование
Что такое inner class и его типы?
Ответ:
Типы:
Static nested class: принадлежит классу, не имеет доступа к нестатическим членам.
Non-static inner class: имеет доступ к членам внешнего класса.
Local class: в методе.
Anonymous class: без имени, для одноразового использования.
Пример non-static:
class Outer {
private int x = 10;
class Inner { void print() { System.out.println(x); } }
}
Полезны для инкапсуляции логики.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Юрий Александрович Маматов (29 августа 1948 года, Тамбов, Тамбовская область, РСФСР, СССР — 16 декабря 1997 года, Ярославль, Ярославская область, Россия) — советский/российский учёный в области информатики и вычислительной техники, работы по вычислительным системам, САПР и телекоммуникационным инфраструктурам.
Стивен Вольфрам (англ. Stephen Wolfram, род. 29 августа 1959, Лондон) — создатель Mathematica и Wolfram Language; популяризатор вычислительного подхода к науке.
1831 — Майкл Фарадей успешно применил первый электрический трансформатор.
1982 — учёные из Дармштадта (Западная Германия) сообщили об открытии 109-го элемента периодической системы Менделеева — мейтнерия.
1997 — основание Netflix (Санта-Крус/Скотс-Вэлли). Из DVD-сервиса компания вырастет в глобальную стриминговую платформу.
2003 — первый публичный релиз (beta) Skype. Старт сервиса P2P-телефонии, впоследствии задавшего массовый видеозвонок как формат.
#Biography #Birth_Date #Events #29Августа
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Фундамент Docker и его экосистемы
Что такое контейнеризация и чем она отличается от виртуализации
Контейнеризация — это технология, которая позволяет упаковывать приложение вместе с его зависимостями (библиотеками, настройками и окружением) в легковесный "контейнер". Представьте контейнер как изолированный ящик: внутри все, что нужно для работы приложения, но он делит ресурсы с основной системой. Это упрощает разработку, тестирование и развертывание: приложение работает одинаково на любом компьютере, где есть Docker.
На уровне системы контейнеризация использует возможности ядра операционной системы (в основном Linux). Ключевые механизмы — пространства имен (namespaces) и группы контроля ресурсов (cgroups).
Пространства имен создают изоляцию: например, процессы в контейнере видят только свои файлы, сеть и идентификаторы процессов (PID). В памяти это значит, что процессы контейнера работают в своем "пузыре", но делят одно ядро с хост-машиной (основным компьютером).
Cgroups ограничивают ресурсы: вы можете сказать, "этот контейнер использует не больше 1 ГБ памяти", и система enforced это, убивая процессы при превышении (через OOM-killer — механизм, который выбирает, кого убить по приоритетам).
Виртуализация — это создание полной виртуальной машины (VM), как с VirtualBox или VMware. VM эмулирует весь компьютер: свое ядро ОС, процессор, память и диск. Гипервизор (программа-эмулятор) распределяет ресурсы хоста, но с overhead: эмуляция аппаратного уровня добавляет 10-20% потерь производительности. В памяти VM занимает отдельный блок: ее процессы полностью изолированы, но запуск VM занимает минуты, и образы — гигабайты.
Контейнеризация легче: нет эмуляции ядра, overhead 1-5%, запуск — секунды, образы — сотни мегабайт. Но минус — меньшая изоляция: уязвимость в ядре может затронуть все контейнеры.
В контейнерах используйте seccomp (фильтры системных вызовов) и AppArmor/SELinux для усиления безопасности. В производительности контейнеры выигрывают для микросервисов, но VM лучше для разнородных ОС (Windows в Linux-хосте через эмуляцию).
Архитектура Docker: Engine, Daemon, CLI и Registry
Docker — это не монолит, а экосистема компонентов.
Docker Engine — это (ядро) системы, включающее все для создания и запуска контейнеров. Он состоит из даемона (демона — фонового процесса) и CLI (командной строки). Engine работает на хосте, управляя контейнерами через API.
Docker Daemon (dockerd) — серверный процесс, который слушает запросы по сокету или TCP. Он взаимодействует с ядром ОС: создает namespaces, cgroups, управляет образами и контейнерами. В памяти daemon держит состояние: список контейнеров, кэш образов.
Нюанс: daemon — single-threaded в некоторых частях, так что при большом нагрузке (сотни контейнеров) мониторьте /var/run/docker.sock на bottlenecks. Используйте --debug для логов.
CLI (docker) — клиент, который отправляет команды daemon'у. Например, docker run — это запрос к daemon на создание контейнера. CLI парсит аргументы и общается по API. Для удаленного управления настройте TLS для безопасности.
Registry — хранилище образов, как репозиторий. Docker Hub — публичный (бесплатный для open-source), но есть частные (AWS ECR, Google Artifact Registry). Registry хранит образы в формате OCI (стандарт для совместимости). При pull (загрузке) daemon проверяет аутентификацию и скачивает слои.
Нюанс: registry использует content-addressable storage (хранение по хэшу), так что слои не дублируются. Настройте garbage collection (GC) в registry, чтобы чистить dangling слои (неиспользуемые), иначе диск заполнится.
В целом архитектура клиент-серверная: CLI -> Daemon -> Ядро ОС. Для swarm (оркестрации) добавляется manager, но это позже.
#Java #middle #Docker
Что такое контейнеризация и чем она отличается от виртуализации
Контейнеризация — это технология, которая позволяет упаковывать приложение вместе с его зависимостями (библиотеками, настройками и окружением) в легковесный "контейнер". Представьте контейнер как изолированный ящик: внутри все, что нужно для работы приложения, но он делит ресурсы с основной системой. Это упрощает разработку, тестирование и развертывание: приложение работает одинаково на любом компьютере, где есть Docker.
На уровне системы контейнеризация использует возможности ядра операционной системы (в основном Linux). Ключевые механизмы — пространства имен (namespaces) и группы контроля ресурсов (cgroups).
Пространства имен создают изоляцию: например, процессы в контейнере видят только свои файлы, сеть и идентификаторы процессов (PID). В памяти это значит, что процессы контейнера работают в своем "пузыре", но делят одно ядро с хост-машиной (основным компьютером).
Cgroups ограничивают ресурсы: вы можете сказать, "этот контейнер использует не больше 1 ГБ памяти", и система enforced это, убивая процессы при превышении (через OOM-killer — механизм, который выбирает, кого убить по приоритетам).
Виртуализация — это создание полной виртуальной машины (VM), как с VirtualBox или VMware. VM эмулирует весь компьютер: свое ядро ОС, процессор, память и диск. Гипервизор (программа-эмулятор) распределяет ресурсы хоста, но с overhead: эмуляция аппаратного уровня добавляет 10-20% потерь производительности. В памяти VM занимает отдельный блок: ее процессы полностью изолированы, но запуск VM занимает минуты, и образы — гигабайты.
Контейнеризация легче: нет эмуляции ядра, overhead 1-5%, запуск — секунды, образы — сотни мегабайт. Но минус — меньшая изоляция: уязвимость в ядре может затронуть все контейнеры.
В контейнерах используйте seccomp (фильтры системных вызовов) и AppArmor/SELinux для усиления безопасности. В производительности контейнеры выигрывают для микросервисов, но VM лучше для разнородных ОС (Windows в Linux-хосте через эмуляцию).
Архитектура Docker: Engine, Daemon, CLI и Registry
Docker — это не монолит, а экосистема компонентов.
Docker Engine — это (ядро) системы, включающее все для создания и запуска контейнеров. Он состоит из даемона (демона — фонового процесса) и CLI (командной строки). Engine работает на хосте, управляя контейнерами через API.
Docker Daemon (dockerd) — серверный процесс, который слушает запросы по сокету или TCP. Он взаимодействует с ядром ОС: создает namespaces, cgroups, управляет образами и контейнерами. В памяти daemon держит состояние: список контейнеров, кэш образов.
Нюанс: daemon — single-threaded в некоторых частях, так что при большом нагрузке (сотни контейнеров) мониторьте /var/run/docker.sock на bottlenecks. Используйте --debug для логов.
CLI (docker) — клиент, который отправляет команды daemon'у. Например, docker run — это запрос к daemon на создание контейнера. CLI парсит аргументы и общается по API. Для удаленного управления настройте TLS для безопасности.
Registry — хранилище образов, как репозиторий. Docker Hub — публичный (бесплатный для open-source), но есть частные (AWS ECR, Google Artifact Registry). Registry хранит образы в формате OCI (стандарт для совместимости). При pull (загрузке) daemon проверяет аутентификацию и скачивает слои.
Нюанс: registry использует content-addressable storage (хранение по хэшу), так что слои не дублируются. Настройте garbage collection (GC) в registry, чтобы чистить dangling слои (неиспользуемые), иначе диск заполнится.
В целом архитектура клиент-серверная: CLI -> Daemon -> Ядро ОС. Для swarm (оркестрации) добавляется manager, но это позже.
#Java #middle #Docker
👍3
Образы и контейнеры: слоистая файловая система
Образ — это шаблон, как архив с файлами и инструкциями для контейнера. Контейнер — запущенный экземпляр образа, как процесс из шаблона.
Образы строятся слоями: каждый слой — изменение файловой системы (добавление файлов, установка пакетов). Слоистая файловая система (UnionFS, конкретно overlay2 в Docker) объединяет слои: нижние — read-only, верхний — writable для контейнера. В памяти при запуске слои монтируются: overlayfs использует copy-on-write (копирование при записи), так что изменения не трогают базовые слои, экономя диск. Например, если 10 контейнеров от одного образа, базовые слои shared.
UnionFS влияет на производительность — много слоев замедляют поиск файлов (до 10-20% overhead). Оптимизируйте: объединяйте RUN в Dockerfile. В памяти: слои загружаются lazily (по мере нужды), но при pull все скачивается.
Жизненный цикл контейнера
Жизненный цикл контейнера — это последовательность этапов, через которые проходит контейнер от момента его создания до полного удаления. Представьте контейнер как живой организм — он рождается, живет, работает и умирает, но все это под контролем Docker.
Жизненный цикл начинается с образа — статического шаблона.
Когда вы решаете запустить контейнер, Docker проходит следующие следующие шаги:
Загрузка образа (Pull): Если образа нет локально на вашей машине, Docker скачивает его из регистра (хранилища, как Docker Hub). Это происходит автоматически при команде docker run, если образ не найден.
Под капотом: daemon проверяет локальный кэш по тегу (метке версии, например, :latest), затем обращается к registry по HTTP/HTTPS. Слои скачиваются параллельно, если поддерживает registry.
Нюанс: pull может быть дорогим по сети — используйте локальные зеркала или caching-proxy в CI/CD. Если образ большой (гигабайты), это влияет на время старта; оптимизируйте размер слоев.
В памяти: скачанные слои хранятся в /var/lib/docker/overlay2, используя диск, но не RAM до запуска.
Создание контейнера (Create): Команда docker create аллоцирует ресурсы, но не запускает процессы. Docker создает уникальный ID для контейнера, настраивает namespaces (изолированные пространства для процессов, сети, файлов), cgroups (ограничения на CPU, память) и монтирует слоистую файловую систему. В этот момент контейнер — как "замороженный" шаблон: writable-слой (верхний слой для изменений) готов, но пуст.
Здесь происходит системный вызов clone() для namespaces, и cgroupfs монтируется. Если указаны volumes или networks, они attach'атся.
Подводный камень: если ресурсы хоста исчерпаны (например, мало дискового места), create провалится с ошибкой — мониторьте с docker system df.
#Java #middle #Docker
Образ — это шаблон, как архив с файлами и инструкциями для контейнера. Контейнер — запущенный экземпляр образа, как процесс из шаблона.
Образы строятся слоями: каждый слой — изменение файловой системы (добавление файлов, установка пакетов). Слоистая файловая система (UnionFS, конкретно overlay2 в Docker) объединяет слои: нижние — read-only, верхний — writable для контейнера. В памяти при запуске слои монтируются: overlayfs использует copy-on-write (копирование при записи), так что изменения не трогают базовые слои, экономя диск. Например, если 10 контейнеров от одного образа, базовые слои shared.
UnionFS влияет на производительность — много слоев замедляют поиск файлов (до 10-20% overhead). Оптимизируйте: объединяйте RUN в Dockerfile. В памяти: слои загружаются lazily (по мере нужды), но при pull все скачивается.
Жизненный цикл контейнера
Жизненный цикл контейнера — это последовательность этапов, через которые проходит контейнер от момента его создания до полного удаления. Представьте контейнер как живой организм — он рождается, живет, работает и умирает, но все это под контролем Docker.
Жизненный цикл начинается с образа — статического шаблона.
Когда вы решаете запустить контейнер, Docker проходит следующие следующие шаги:
Загрузка образа (Pull): Если образа нет локально на вашей машине, Docker скачивает его из регистра (хранилища, как Docker Hub). Это происходит автоматически при команде docker run, если образ не найден.
Под капотом: daemon проверяет локальный кэш по тегу (метке версии, например, :latest), затем обращается к registry по HTTP/HTTPS. Слои скачиваются параллельно, если поддерживает registry.
Нюанс: pull может быть дорогим по сети — используйте локальные зеркала или caching-proxy в CI/CD. Если образ большой (гигабайты), это влияет на время старта; оптимизируйте размер слоев.
В памяти: скачанные слои хранятся в /var/lib/docker/overlay2, используя диск, но не RAM до запуска.
Создание контейнера (Create): Команда docker create аллоцирует ресурсы, но не запускает процессы. Docker создает уникальный ID для контейнера, настраивает namespaces (изолированные пространства для процессов, сети, файлов), cgroups (ограничения на CPU, память) и монтирует слоистую файловую систему. В этот момент контейнер — как "замороженный" шаблон: writable-слой (верхний слой для изменений) готов, но пуст.
Здесь происходит системный вызов clone() для namespaces, и cgroupfs монтируется. Если указаны volumes или networks, они attach'атся.
Подводный камень: если ресурсы хоста исчерпаны (например, мало дискового места), create провалится с ошибкой — мониторьте с docker system df.
#Java #middle #Docker
👍2
Запуск контейнера (Start или Run): Команда docker start (для созданного) или docker run (create + start) приводит контейнер в жизнь. Docker fork'ует (копирует) процесс и exec'ует (заменяет) его на ENTRYPOINT или CMD из образа — это становится PID 1 (первым процессом) в контейнере. Процессы стартуют в изолированном окружении: сеть подключается, порты expose'ятся, env-переменные устанавливаются.
В памяти: процессы контейнера появляются в хост-PS, но с метками cgroup. Overhead минимален — 1-2 МБ на контейнер плюс приложение.
Нюанс: запуск занимает миллисекунды, но если образ с init-скриптами (например, база данных), это может затянуться. Используйте healthchecks (docker run --health-cmd) для проверки готовности — это критично в оркестрации, чтобы не слать трафик на "холодный" контейнер.
Работа контейнера (Running): Контейнер выполняет свою задачу: ваше приложение бежит, обрабатывает запросы, пишет логи. Docker мониторит состояние: если PID 1 выходит (exit code 0 — успех, ненулевой — ошибка), контейнер останавливается. Логи доступны через docker logs.
В памяти: ресурсы потребляются динамически — cgroups enforced лимиты, так что при превышении памяти OOM-killer может убить процессы (приоритет по oom_score). Мониторьте с docker stats или Prometheus exporter; учитывайте, что restart-policy (docker run --restart=always) может перезапускать при сбоях, но это маскирует root-cause.
Пауза и возобновление (Pause/Unpause): Опционально, docker pause замораживает процессы (сигнал SIGSTOP), сохраняя состояние в памяти. Unpause (SIGCONT) продолжает. Полезно для maintenance.
Нюанс: пауза не освобождает ресурсы полностью — RAM все равно занята.
Остановка контейнера (Stop): Команда docker stop посылает SIGTERM (сигнал мягкой остановки) PID 1, дает grace-period (по умолчанию 10 секунд) на shutdown, затем SIGKILL (принудительное убийство). Это позволяет приложению gracefully закрыться: сохранить данные, завершить транзакции. Если PID 1 — Java или shell, который не ловит сигналы, используйте --init или tini для forwarding. В production настройте timeout (--time=30) для долгоживущих shutdown.
Удаление контейнера (Remove): Docker rm чистит все: удаляет writable-слой, освобождает namespaces/cgroups, detach'ит volumes/networks. Если --rm в run, удаление автоматическое.
Нюанс: stopped-контейнеры хранят состояние (файлы, логи) — используйте docker ps -a для просмотра. Dangling resources (неудаленные volumes) накапливаются — чистите с docker system prune; в скриптах автоматизируйте rm для избежания утечек диска.
Весь цикл обеспечивает воспроизводимость: контейнеры эфемерны (временны), данные persist в volumes. Подводный камень: в кластерах (Swarm/Kubernetes) lifecycle управляется оркестратором, с auto-restart и rolling updates.
#Java #middle #Docker
В памяти: процессы контейнера появляются в хост-PS, но с метками cgroup. Overhead минимален — 1-2 МБ на контейнер плюс приложение.
Нюанс: запуск занимает миллисекунды, но если образ с init-скриптами (например, база данных), это может затянуться. Используйте healthchecks (docker run --health-cmd) для проверки готовности — это критично в оркестрации, чтобы не слать трафик на "холодный" контейнер.
Работа контейнера (Running): Контейнер выполняет свою задачу: ваше приложение бежит, обрабатывает запросы, пишет логи. Docker мониторит состояние: если PID 1 выходит (exit code 0 — успех, ненулевой — ошибка), контейнер останавливается. Логи доступны через docker logs.
В памяти: ресурсы потребляются динамически — cgroups enforced лимиты, так что при превышении памяти OOM-killer может убить процессы (приоритет по oom_score). Мониторьте с docker stats или Prometheus exporter; учитывайте, что restart-policy (docker run --restart=always) может перезапускать при сбоях, но это маскирует root-cause.
Пауза и возобновление (Pause/Unpause): Опционально, docker pause замораживает процессы (сигнал SIGSTOP), сохраняя состояние в памяти. Unpause (SIGCONT) продолжает. Полезно для maintenance.
Нюанс: пауза не освобождает ресурсы полностью — RAM все равно занята.
Остановка контейнера (Stop): Команда docker stop посылает SIGTERM (сигнал мягкой остановки) PID 1, дает grace-period (по умолчанию 10 секунд) на shutdown, затем SIGKILL (принудительное убийство). Это позволяет приложению gracefully закрыться: сохранить данные, завершить транзакции. Если PID 1 — Java или shell, который не ловит сигналы, используйте --init или tini для forwarding. В production настройте timeout (--time=30) для долгоживущих shutdown.
Удаление контейнера (Remove): Docker rm чистит все: удаляет writable-слой, освобождает namespaces/cgroups, detach'ит volumes/networks. Если --rm в run, удаление автоматическое.
Нюанс: stopped-контейнеры хранят состояние (файлы, логи) — используйте docker ps -a для просмотра. Dangling resources (неудаленные volumes) накапливаются — чистите с docker system prune; в скриптах автоматизируйте rm для избежания утечек диска.
Весь цикл обеспечивает воспроизводимость: контейнеры эфемерны (временны), данные persist в volumes. Подводный камень: в кластерах (Swarm/Kubernetes) lifecycle управляется оркестратором, с auto-restart и rolling updates.
#Java #middle #Docker
👍2
Базовые настройки: volumes, networks и environment variables
После запуска контейнера важно настроить его взаимодействие с внешним миром. Эти настройки — как "провода" для данных, связи и конфигурации.
Volumes — механизм для хранения данных вне контейнера, чтобы они пережили удаление.
Есть два типа:
bind-mount (привязка к директории хоста, docker run -v /host/path:/container/path) и named volume (управляемый Docker, -v myvol:/path).
Volumes монтируются в FS контейнера, позволяя читать/писать persistently. Это как внешний жесткий диск для контейнера.
В памяти: данные на диске хоста, но доступ через namespace — нет overhead, кроме I/O.
Нюанс: bind-mounts делят permissions (права доступа) с хостом, что рискованно; используйте named volumes с docker volume create для изоляции.
В production: volume drivers (plugins) для облака, как AWS EBS, но следите за latency — медленные volumes замедляют app. Чистите unused volumes с prune, иначе диск заполнится.
Networks — для связи контейнеров между собой или с внешним миром. По умолчанию — bridge (локальная виртуальная сеть, контейнеры общаются по именам).
Другие:
host (делит сеть хоста, no isolation — быстро, но небезопасно), overlay (для multi-host в Swarm).
Docker создает network namespace: каждый контейнер имеет veth-интерфейс (virtual ethernet). Bridge использует NAT (network address translation) для внешнего доступа, с overhead 5-10% на трафик. Expose порты с -p 80:80 (host:container).
В production: custom networks для изоляции (docker network create mynet), и firewall (ufw/iptables) для безопасности.
Environment variables (переменные окружения, -e KEY=VALUE) — способ передать конфиг в контейнер, как API_KEY или DB_URL. Они устанавливаются в env процесса PID 1 и доступны в коде (System.getenv в Java). Это как настройки в панели управления.
В памяти: хранятся в process-env, минимум overhead.
Нюанс: не храните секреты в env — они видны в docker inspect или ps aux; используйте --secret или Docker Secrets в Swarm. Env влияют на эргономику (например, JAVA_OPTS), но перезапись в Dockerfile с ENV фиксирует их в слое — избегайте для sensitive данных.
Эти настройки комбинируются: например, volume для DB-data, network для связи с backend, env для creds.
Разница между образами для разработки и для production
Образы адаптируются под стадию: dev — для удобства, prod — для эффективности и безопасности.
В dev: используйте полный JDK (для компиляции), добавьте debug-tools (jdb, maven), volumes для mount кода (hot-reload). Образ большой (1ГБ+), с shell для exec (docker exec -it для отладки). Multi-stage build: stage1 — build с JDK, stage2 — copy artifacts в JRE.
В production: минимальный JRE или distroless (без shell, утилит — поверхность атаки меньше). Удалите dev-зависимости, оптимизируйте слои (unite RUN). Размер 100-200МБ, immutable (неизменяемый).
Нюанс: в prod учитывайте container-aware JVM (лимиты cgroups), signals для shutdown, entropy для crypto. Тестируйте под real limits; используйте scanning (Trivy) для vuln. Dev-образы для локали/CI, prod — для deploy.
Мини-пример: запуск hello-world и openjdk образов
Установите Docker, если его нет.
Сначала hello-world — простой тест:
Для Java: openjdk:21-jre (runtime):
#Java #middle #Docker
После запуска контейнера важно настроить его взаимодействие с внешним миром. Эти настройки — как "провода" для данных, связи и конфигурации.
Volumes — механизм для хранения данных вне контейнера, чтобы они пережили удаление.
Есть два типа:
bind-mount (привязка к директории хоста, docker run -v /host/path:/container/path) и named volume (управляемый Docker, -v myvol:/path).
Volumes монтируются в FS контейнера, позволяя читать/писать persistently. Это как внешний жесткий диск для контейнера.
В памяти: данные на диске хоста, но доступ через namespace — нет overhead, кроме I/O.
Нюанс: bind-mounts делят permissions (права доступа) с хостом, что рискованно; используйте named volumes с docker volume create для изоляции.
В production: volume drivers (plugins) для облака, как AWS EBS, но следите за latency — медленные volumes замедляют app. Чистите unused volumes с prune, иначе диск заполнится.
Networks — для связи контейнеров между собой или с внешним миром. По умолчанию — bridge (локальная виртуальная сеть, контейнеры общаются по именам).
Другие:
host (делит сеть хоста, no isolation — быстро, но небезопасно), overlay (для multi-host в Swarm).
Docker создает network namespace: каждый контейнер имеет veth-интерфейс (virtual ethernet). Bridge использует NAT (network address translation) для внешнего доступа, с overhead 5-10% на трафик. Expose порты с -p 80:80 (host:container).
В production: custom networks для изоляции (docker network create mynet), и firewall (ufw/iptables) для безопасности.
Environment variables (переменные окружения, -e KEY=VALUE) — способ передать конфиг в контейнер, как API_KEY или DB_URL. Они устанавливаются в env процесса PID 1 и доступны в коде (System.getenv в Java). Это как настройки в панели управления.
В памяти: хранятся в process-env, минимум overhead.
Нюанс: не храните секреты в env — они видны в docker inspect или ps aux; используйте --secret или Docker Secrets в Swarm. Env влияют на эргономику (например, JAVA_OPTS), но перезапись в Dockerfile с ENV фиксирует их в слое — избегайте для sensitive данных.
Эти настройки комбинируются: например, volume для DB-data, network для связи с backend, env для creds.
Разница между образами для разработки и для production
Образы адаптируются под стадию: dev — для удобства, prod — для эффективности и безопасности.
В dev: используйте полный JDK (для компиляции), добавьте debug-tools (jdb, maven), volumes для mount кода (hot-reload). Образ большой (1ГБ+), с shell для exec (docker exec -it для отладки). Multi-stage build: stage1 — build с JDK, stage2 — copy artifacts в JRE.
В production: минимальный JRE или distroless (без shell, утилит — поверхность атаки меньше). Удалите dev-зависимости, оптимизируйте слои (unite RUN). Размер 100-200МБ, immutable (неизменяемый).
Нюанс: в prod учитывайте container-aware JVM (лимиты cgroups), signals для shutdown, entropy для crypto. Тестируйте под real limits; используйте scanning (Trivy) для vuln. Dev-образы для локали/CI, prod — для deploy.
Мини-пример: запуск hello-world и openjdk образов
Установите Docker, если его нет.
Сначала hello-world — простой тест:
docker run hello-world
Pull'нет образ (~1МБ), запустит, выведет сообщение и выйдет. Проверьте docker ps -a — увидите stopped контейнер.
Для Java: openjdk:21-jre (runtime):
docker run -it --rm openjdk:21-jre java -version
-it — interactive terminal, --rm — auto-remove. Выведет версию. Добавьте --memory=512m — JVM увидит лимит и подстроит heap. Для senior: exec docker exec -it <id> bash (если shell есть) для инспекции.</id>
#Java #middle #Docker
👍3
Как вы думаете, если на собесе сказать - "я не этого не знаю, но готов изучить" - каковы шансы, что Вы пройдете?
Anonymous Poll
56%
Шансы отличные! Честность важна и ценится! 🙂
12%
Лучше попытаться что-то соврать, есть шанс, что интервьюер сам этого не знает ☺️
26%
Шансы резко падают! Нужно лучше готовиться! 👎
7%
Надо замереть и замолчать, изобразив дисконект. Или пустить слюну и упасть - могут взять из жалости.
👍1
Что выведет код?
#Tasks
public class Task290825 {
public static void main(String[] args) {
try {
System.out.print("A");
int result = 10 / 0;
System.out.print("B");
} catch (Exception e) {
System.out.print("C");
} finally {
System.out.print("D");
}
System.out.print("E");
}
}
#Tasks
👍2