👍2
Что такое bytecode verification в JVM? 🤓
Ответ:
Bytecode verification — это процесс, выполняемый JVM перед выполнением кода, чтобы проверить байт-код на безопасность и соответствие спецификациям (например, отсутствие недопустимых операций).
Это предотвращает ошибки, такие как доступ к неинициализированным переменным или неправильные типы. Происходит в фазе загрузки классов. Если верификация не проходит, выбрасывается VerifyError. Это часть модели безопасности Java, обеспечивающая, что вредоносный код не сможет навредить системе.
#собеседование
Ответ:
Это предотвращает ошибки, такие как доступ к неинициализированным переменным или неправильные типы. Происходит в фазе загрузки классов. Если верификация не проходит, выбрасывается VerifyError. Это часть модели безопасности Java, обеспечивающая, что вредоносный код не сможет навредить системе.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7😱1
Леони́д Никола́евич Пресну́хин (26 августа 1918 года, деревня Харлово, Тверская губерния — 27 июня 2007 года, Зеленоград) — организатор отечественной микроэлектроники, первый ректор МИЭТ; внёс вклад в создание элементной базы для вычислительной техники в СССР.
Карен Спарк Джонс (член британской академии; 26 августа 1935 — 4 апреля 2007) — пионер информационного поиска, автор идеи IDF/взвешивания терминов, лежащих в основе поисковиков.
Ричард Эрнест Бе́ллман (англ. Richard Ernest Bellman; 26 августа 1920, Нью-Йорк, США — 19 марта 1984, Лос-Анджелес, США) — создатель динамического программирования; его идеи легли в основу оптимизации и обучения с подкреплением.
Кэ́трин Ко́улман Гобл Джо́нсон (при рождении — Крео́ла Кэтрин Коулман, в первом замужестве — Кэтрин Коулман Гобл) (англ. Katherine Coleman Goble Johnson; 26 августа 1918, Уайт-Салфер-Спрингс, Западная Виргиния, США — 24 февраля 2020, Ньюпорт-Ньюс, Виргиния, США) — «человеческий компьютер» NASA, чьи расчёты траекторий стали критичны для ранних космических миссий.
Ли де Фо́рест (англ. Lee De Forest; 26 августа 1873, Каунсил-Блафс, штат Айова — 30 июня 1961, Голливуд, штат Калифорния, США) — американский изобретатель, имеющий на своём счету 300 патентов на изобретения. Де Форест изобрёл триод — электронную лампу, которая принимает на входе относительно слабый электрический сигнал и затем усиливает его. Де Форест является одним из отцов «века электроники», потому что триод помог открыть дорогу широкому использованию электроники.
1858 — отправлена первая новость телеграфом.
1984 — «Miss Manners Addresses Computer Correspondence» — Комментатор Miss Manners публикует колонку о вежливом поведении в электронной переписке (часть культурного осмысления новой эры e-mail)
#Biography #Birth_Date #Events #26Августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Docker
Контейнеры, образы и сборка
Что такое контейнер и как он работает
Контейнер — это легковесный способ упаковки и запуска приложения вместе с его зависимостями в изолированной среде. Представьте контейнер как отдельную "комнату" в операционной системе, где ваше приложение живет само по себе, не мешая другим. В отличие от традиционных программ, которые запускаются напрямую на хост-машине (компьютере, где все работает), контейнер использует механизмы операционной системы для создания иллюзии полной изоляции.
На уровне системы контейнер строится на двух ключевых технологиях ядра Linux (поскольку Docker изначально ориентирован на Linux, хотя теперь работает и на других платформах через эмуляцию): пространства имен и группы контроля ресурсов.
Пространства имен — это способ разделить системные ресурсы так, чтобы процессы внутри контейнера видели только свою часть системы. Например, пространство имен для процессов (PID namespace) делает так, что процессы в контейнере имеют свои собственные идентификаторы, начиная с 1, как будто они в отдельной системе. Пространство имен для сети изолирует сетевые интерфейсы, так что контейнер может иметь свой IP-адрес. Есть также пространства для пользователей, файловой системы и других. В памяти это значит, что процессы контейнера не видят процессы хоста напрямую — они работают в своем "пузыре", но делят одно ядро операционной системы. Это экономит ресурсы: нет overhead от полной виртуализации.
Группы контроля ресурсов (cgroups) — это механизм ограничения ресурсов, таких как процессор, память и диск. Например, вы можете сказать: "Этот контейнер может использовать не больше 512 МБ памяти". В памяти это работает через ядро, которое отслеживает использование и при превышении может убить процессы (OOM killer). Cgroups также помогают в изоляции ввода-вывода, чтобы один контейнер не "загружал" диск для всех.
Когда вы запускаете контейнер, Docker создает новый процесс (или группу процессов) с этими изоляциями. В памяти хоста процессы контейнера выглядят как обычные, но с метками для изоляции. Это делает контейнеры быстрыми: запуск занимает секунды, в отличие от виртуальных машин.
Отличие контейнера от виртуальной машины
Виртуальная машина (VM) — это полная эмуляция отдельного компьютера с собственным ядром операционной системы, процессором и памятью. Она использует гипервизор (программу вроде VirtualBox или VMware), который эмулирует аппаратное обеспечение. В памяти хоста VM занимает отдельный блок: ее процессы работают в изолированном пространстве с overhead от эмуляции (до 10-20% потерь производительности).
Контейнер, напротив, делит ядро хоста. Нет эмуляции аппаратного уровня — все процессы используют одно ядро. Это делает контейнеры легче: образ (шаблон для контейнера) может быть в разы меньше (сотни МБ vs гигабайты для VM), запуск быстрее, и overhead минимален (1-5%). Но есть минус: контейнеры менее безопасны, если есть уязвимость в ядре, она может затронуть все. Для Java это значит, что ваше приложение в контейнере запускается на той же JVM (виртуальной машине Java), что и на хосте, но с изоляцией зависимостей, что упрощает развертывание.
#Java #middle #Docker #DockerFile #Docker_compose #Buildx
Контейнеры, образы и сборка
Что такое контейнер и как он работает
Контейнер — это легковесный способ упаковки и запуска приложения вместе с его зависимостями в изолированной среде. Представьте контейнер как отдельную "комнату" в операционной системе, где ваше приложение живет само по себе, не мешая другим. В отличие от традиционных программ, которые запускаются напрямую на хост-машине (компьютере, где все работает), контейнер использует механизмы операционной системы для создания иллюзии полной изоляции.
На уровне системы контейнер строится на двух ключевых технологиях ядра Linux (поскольку Docker изначально ориентирован на Linux, хотя теперь работает и на других платформах через эмуляцию): пространства имен и группы контроля ресурсов.
Пространства имен — это способ разделить системные ресурсы так, чтобы процессы внутри контейнера видели только свою часть системы. Например, пространство имен для процессов (PID namespace) делает так, что процессы в контейнере имеют свои собственные идентификаторы, начиная с 1, как будто они в отдельной системе. Пространство имен для сети изолирует сетевые интерфейсы, так что контейнер может иметь свой IP-адрес. Есть также пространства для пользователей, файловой системы и других. В памяти это значит, что процессы контейнера не видят процессы хоста напрямую — они работают в своем "пузыре", но делят одно ядро операционной системы. Это экономит ресурсы: нет overhead от полной виртуализации.
Группы контроля ресурсов (cgroups) — это механизм ограничения ресурсов, таких как процессор, память и диск. Например, вы можете сказать: "Этот контейнер может использовать не больше 512 МБ памяти". В памяти это работает через ядро, которое отслеживает использование и при превышении может убить процессы (OOM killer). Cgroups также помогают в изоляции ввода-вывода, чтобы один контейнер не "загружал" диск для всех.
Когда вы запускаете контейнер, Docker создает новый процесс (или группу процессов) с этими изоляциями. В памяти хоста процессы контейнера выглядят как обычные, но с метками для изоляции. Это делает контейнеры быстрыми: запуск занимает секунды, в отличие от виртуальных машин.
Отличие контейнера от виртуальной машины
Виртуальная машина (VM) — это полная эмуляция отдельного компьютера с собственным ядром операционной системы, процессором и памятью. Она использует гипервизор (программу вроде VirtualBox или VMware), который эмулирует аппаратное обеспечение. В памяти хоста VM занимает отдельный блок: ее процессы работают в изолированном пространстве с overhead от эмуляции (до 10-20% потерь производительности).
Контейнер, напротив, делит ядро хоста. Нет эмуляции аппаратного уровня — все процессы используют одно ядро. Это делает контейнеры легче: образ (шаблон для контейнера) может быть в разы меньше (сотни МБ vs гигабайты для VM), запуск быстрее, и overhead минимален (1-5%). Но есть минус: контейнеры менее безопасны, если есть уязвимость в ядре, она может затронуть все. Для Java это значит, что ваше приложение в контейнере запускается на той же JVM (виртуальной машине Java), что и на хосте, но с изоляцией зависимостей, что упрощает развертывание.
#Java #middle #Docker #DockerFile #Docker_compose #Buildx
👍6🔥1
OCI-спецификации: образы, манифесты и слои
Open Container Initiative (OCI) — это стандарт, который определяет, как должны выглядеть контейнерные образы и runtime (среда выполнения). Docker следует этим спецификациям, чтобы образы были совместимы с другими инструментами, вроде Podman или containerd.
Образ — это шаблон для контейнера, как архив с файлами, конфигурацией и инструкциями. Он состоит из слоев (layers) — последовательных изменений файловой системы. Каждый слой — это blob (бинарный объект), хранящий дельту (изменения) от предыдущего.
Манифест — это JSON-файл, описывающий образ: платформу (архитектуру процессора), слои, конфигурацию (команда запуска, порты). Для multi-platform образов (для разных CPU, как AMD64 и ARM) есть index-манифест, указывающий на подманифесты.
Content-addressable storage — хранение по хэшу содержимого. Каждый слой имеет уникальный хэш (SHA256), так что если слой не изменился, он не перезагружается. Это влияет на кэш: при сборке Docker проверяет хэш и использует кэш, если ничего не поменялось. "Тонкие" образы (thin images) — это когда слои минимальны, без лишних файлов, что экономит место в памяти и на диске. В памяти при запуске слои монтируются как union-файловая система (overlayfs): верхние слои перекрывают нижние, но в RAM загружается только то, что нужно.
Это позволяет эффективно хранить образы: общие слои (например, базовый Ubuntu) делятся между образами, снижая использование диска.
Регистры образов: Docker Hub, теги и управление
Регистр — это хранилище для образов, как репозиторий для кода. Docker Hub — публичный регистр, где хранятся официальные образы (например, openjdk). Можно использовать частные, вроде в AWS ECR или self-hosted.
Теги — это метки для версий образа, как "latest" или "21-jre". Образы иммутабельны (неизменяемы): после загрузки в регистр их нельзя изменить, только перезаписать тег. Это обеспечивает воспроизводимость: тег "1.0" всегда тот же.
Удаление и сборка мусора (GC): Когда вы удаляете тег, слой не удаляется сразу, если он используется другими тегами. GC (garbage collection) — процесс, который чистит неиспользуемые слои. В Docker Hub это автоматически, но в частных регистрах нужно настраивать. Нюанс: dangling images (висячие, без тегов) накапливаются и жрут место; используйте "docker image prune" для очистки.
Для Java полезно: официальные образы вроде eclipse-temurin:21-jre хранятся в Docker Hub, и теги помогают управлять версиями JVM.
Dockerfile: декларативный подход и подводные камни
Dockerfile — это текстовый файл с инструкциями для сборки образа. Он декларативный: вы описываете, что нужно, а Docker строит слои последовательно.
Ключевые инструкции:
FROM: базовый образ, например, FROM eclipse-temurin:21-jre.
RUN: выполняет команду, создает слой (например, RUN apt-get install ...).
COPY/ADD: копирует файлы в образ.
CMD/ENTRYPOINT: команда запуска.
Подводные камни:
Порядок инструкций: Docker кэширует слои по порядку. Если часто меняющийся RUN в начале, весь кэш сломается. Ставьте стабильные инструкции первыми.
Кэш: Каждый слой кэшируется по хэшу. Если файл в COPY изменился, слои ниже инвалидируются.
Слои: Много RUN создают много слоев — объединяйте в один RUN с && для минимизации. В памяти это значит меньше overhead при монтировании.
Для Java: избегайте установки лишнего в RUN, чтобы образ был маленьким.
#Java #middle #Docker #DockerFile #Docker_compose #Buildx
Open Container Initiative (OCI) — это стандарт, который определяет, как должны выглядеть контейнерные образы и runtime (среда выполнения). Docker следует этим спецификациям, чтобы образы были совместимы с другими инструментами, вроде Podman или containerd.
Образ — это шаблон для контейнера, как архив с файлами, конфигурацией и инструкциями. Он состоит из слоев (layers) — последовательных изменений файловой системы. Каждый слой — это blob (бинарный объект), хранящий дельту (изменения) от предыдущего.
Манифест — это JSON-файл, описывающий образ: платформу (архитектуру процессора), слои, конфигурацию (команда запуска, порты). Для multi-platform образов (для разных CPU, как AMD64 и ARM) есть index-манифест, указывающий на подманифесты.
Content-addressable storage — хранение по хэшу содержимого. Каждый слой имеет уникальный хэш (SHA256), так что если слой не изменился, он не перезагружается. Это влияет на кэш: при сборке Docker проверяет хэш и использует кэш, если ничего не поменялось. "Тонкие" образы (thin images) — это когда слои минимальны, без лишних файлов, что экономит место в памяти и на диске. В памяти при запуске слои монтируются как union-файловая система (overlayfs): верхние слои перекрывают нижние, но в RAM загружается только то, что нужно.
Это позволяет эффективно хранить образы: общие слои (например, базовый Ubuntu) делятся между образами, снижая использование диска.
Регистры образов: Docker Hub, теги и управление
Регистр — это хранилище для образов, как репозиторий для кода. Docker Hub — публичный регистр, где хранятся официальные образы (например, openjdk). Можно использовать частные, вроде в AWS ECR или self-hosted.
Теги — это метки для версий образа, как "latest" или "21-jre". Образы иммутабельны (неизменяемы): после загрузки в регистр их нельзя изменить, только перезаписать тег. Это обеспечивает воспроизводимость: тег "1.0" всегда тот же.
Удаление и сборка мусора (GC): Когда вы удаляете тег, слой не удаляется сразу, если он используется другими тегами. GC (garbage collection) — процесс, который чистит неиспользуемые слои. В Docker Hub это автоматически, но в частных регистрах нужно настраивать. Нюанс: dangling images (висячие, без тегов) накапливаются и жрут место; используйте "docker image prune" для очистки.
Для Java полезно: официальные образы вроде eclipse-temurin:21-jre хранятся в Docker Hub, и теги помогают управлять версиями JVM.
Dockerfile: декларативный подход и подводные камни
Dockerfile — это текстовый файл с инструкциями для сборки образа. Он декларативный: вы описываете, что нужно, а Docker строит слои последовательно.
Ключевые инструкции:
FROM: базовый образ, например, FROM eclipse-temurin:21-jre.
RUN: выполняет команду, создает слой (например, RUN apt-get install ...).
COPY/ADD: копирует файлы в образ.
CMD/ENTRYPOINT: команда запуска.
Подводные камни:
Порядок инструкций: Docker кэширует слои по порядку. Если часто меняющийся RUN в начале, весь кэш сломается. Ставьте стабильные инструкции первыми.
Кэш: Каждый слой кэшируется по хэшу. Если файл в COPY изменился, слои ниже инвалидируются.
Слои: Много RUN создают много слоев — объединяйте в один RUN с && для минимизации. В памяти это значит меньше overhead при монтировании.
Для Java: избегайте установки лишнего в RUN, чтобы образ был маленьким.
#Java #middle #Docker #DockerFile #Docker_compose #Buildx
👍6
Современная сборка образов: BuildKit и Buildx как стандарт
BuildKit — это новый движок сборки, который с 2023 года используется по умолчанию в Docker. В отличие от старого билдера, который обрабатывал инструкции последовательно, BuildKit анализирует весь Dockerfile как граф зависимостей. Это значит, что он может выполнять независимые инструкции параллельно. Например, если у вас несколько RUN, которые не зависят друг от друга, BuildKit запустит их одновременно на разных ядрах процессора. На уровне системы это снижает время сборки: вместо линейного ожидания, вы получаете параллельное использование ресурсов, что в памяти хоста проявляется как более эффективное распределение CPU и RAM во время билда.
Одна из ключевых фишек BuildKit — улучшенный кэш. В классическом подходе кэш хранится локально и может сломаться при изменении инструкций. BuildKit вводит inline-кэш: вы можете экспортировать кэш прямо в образ или в регистр. При следующей сборке Docker pulls (загружает) этот кэш, что ускоряет процесс в CI/CD-пайплайнах (системах непрерывной интеграции и доставки). Например, если вы собираете образ в GitHub Actions, inline-кэш позволяет избежать полной перестройки каждый раз.
Еще нюанс — обработка секретов. В старом билдере пароли или API-ключи могли попасть в слои образа, что небезопасно. BuildKit позволяет передавать секреты через --secret флаг: они монтируются временно в память во время RUN, но не сохраняются в финальном образе. В памяти это работает как tmpfs (временная файловая система в RAM), так что секреты не пишутся на диск и не остаются в истории.
Buildx — это расширение BuildKit для сборки мультиплатформенных образов. Оно позволяет создавать один образ, который работает на разных архитектурах процессоров, таких как x86 (AMD64) и ARM (для Raspberry Pi или облачных инстансов). Под капотом Buildx использует эмуляцию через QEMU: для каждой платформы он запускает виртуальный билдер, собирает слой, и объединяет в манифест. Это влияет на память: эмуляция может потреблять больше RAM, но результат — универсальный образ, который Docker сам выбирает под хост.
Для Java это критично: JVM (виртуальная машина Java) имеет версии для разных платформ, и Buildx обеспечивает, что ваш образ с Java 21 будет работать везде без перестройки. Подводный камень: эмуляция медленнее нативной сборки, так что для больших проектов используйте удаленные билдеры в облаке.
Docker Compose версии 2: оркестрация для локальной разработки и CI
Оркестрация — способ запуска нескольких контейнеров как единой системы. Docker Compose v2 — это инструмент, который стал дефолтным для этого. Он позволяет описать весь стек приложений в одном YAML-файле, включая сервисы, сети и volumes (тома для хранения данных).
Compose работает как надстройка над Docker: он парсит файл docker-compose.yml и вызывает docker run для каждого сервиса. В памяти хоста это значит создание сети по умолчанию (bridge), где контейнеры общаются по именам, и volumes, которые монтируются как bind-mounts (привязки к хост-файлам) или named volumes (управляемые Docker).
Для локальной разработки Compose идеален: команда docker compose up запускает все сервисы, и вы можете отлаживать Java-приложение с базой данных, например, PostgreSQL. В CI, таком как Jenkins или GitLab CI, Compose используется для тестов: он поднимает окружение, запускает тесты и сносит все после.
Нюансы: Compose v2 быстрее v1 благодаря Go-реализации (вместо Python), и лучше интегрируется с Docker Desktop. Подводный камень — зависимости: если сервис A зависит от B, укажите depends_on, но это не гарантирует готовность (например, база данных может стартовать медленно). Для Java используйте healthchecks: в compose-файле добавьте проверку, чтобы приложение ждало базу.
Еще фишка — профили: вы можете группировать сервисы для разных сред (dev, test), чтобы не запускать все сразу.
#Java #middle #Docker #DockerFile #Docker_compose #Buildx
BuildKit — это новый движок сборки, который с 2023 года используется по умолчанию в Docker. В отличие от старого билдера, который обрабатывал инструкции последовательно, BuildKit анализирует весь Dockerfile как граф зависимостей. Это значит, что он может выполнять независимые инструкции параллельно. Например, если у вас несколько RUN, которые не зависят друг от друга, BuildKit запустит их одновременно на разных ядрах процессора. На уровне системы это снижает время сборки: вместо линейного ожидания, вы получаете параллельное использование ресурсов, что в памяти хоста проявляется как более эффективное распределение CPU и RAM во время билда.
Одна из ключевых фишек BuildKit — улучшенный кэш. В классическом подходе кэш хранится локально и может сломаться при изменении инструкций. BuildKit вводит inline-кэш: вы можете экспортировать кэш прямо в образ или в регистр. При следующей сборке Docker pulls (загружает) этот кэш, что ускоряет процесс в CI/CD-пайплайнах (системах непрерывной интеграции и доставки). Например, если вы собираете образ в GitHub Actions, inline-кэш позволяет избежать полной перестройки каждый раз.
Еще нюанс — обработка секретов. В старом билдере пароли или API-ключи могли попасть в слои образа, что небезопасно. BuildKit позволяет передавать секреты через --secret флаг: они монтируются временно в память во время RUN, но не сохраняются в финальном образе. В памяти это работает как tmpfs (временная файловая система в RAM), так что секреты не пишутся на диск и не остаются в истории.
Buildx — это расширение BuildKit для сборки мультиплатформенных образов. Оно позволяет создавать один образ, который работает на разных архитектурах процессоров, таких как x86 (AMD64) и ARM (для Raspberry Pi или облачных инстансов). Под капотом Buildx использует эмуляцию через QEMU: для каждой платформы он запускает виртуальный билдер, собирает слой, и объединяет в манифест. Это влияет на память: эмуляция может потреблять больше RAM, но результат — универсальный образ, который Docker сам выбирает под хост.
Для Java это критично: JVM (виртуальная машина Java) имеет версии для разных платформ, и Buildx обеспечивает, что ваш образ с Java 21 будет работать везде без перестройки. Подводный камень: эмуляция медленнее нативной сборки, так что для больших проектов используйте удаленные билдеры в облаке.
Docker Compose версии 2: оркестрация для локальной разработки и CI
Оркестрация — способ запуска нескольких контейнеров как единой системы. Docker Compose v2 — это инструмент, который стал дефолтным для этого. Он позволяет описать весь стек приложений в одном YAML-файле, включая сервисы, сети и volumes (тома для хранения данных).
Compose работает как надстройка над Docker: он парсит файл docker-compose.yml и вызывает docker run для каждого сервиса. В памяти хоста это значит создание сети по умолчанию (bridge), где контейнеры общаются по именам, и volumes, которые монтируются как bind-mounts (привязки к хост-файлам) или named volumes (управляемые Docker).
Для локальной разработки Compose идеален: команда docker compose up запускает все сервисы, и вы можете отлаживать Java-приложение с базой данных, например, PostgreSQL. В CI, таком как Jenkins или GitLab CI, Compose используется для тестов: он поднимает окружение, запускает тесты и сносит все после.
Нюансы: Compose v2 быстрее v1 благодаря Go-реализации (вместо Python), и лучше интегрируется с Docker Desktop. Подводный камень — зависимости: если сервис A зависит от B, укажите depends_on, но это не гарантирует готовность (например, база данных может стартовать медленно). Для Java используйте healthchecks: в compose-файле добавьте проверку, чтобы приложение ждало базу.
Еще фишка — профили: вы можете группировать сервисы для разных сред (dev, test), чтобы не запускать все сразу.
#Java #middle #Docker #DockerFile #Docker_compose #Buildx
👍5
Примеры кода
Минимальный Dockerfile для Java 21 с использованием BuildKit
Чтобы собрать с BuildKit-фичами:
Inline-кэш сохранит промежуточные результаты в образе.
Если добавить
то в RUN можно использовать $mysecret без записи в слой.
Мультиархитектурная сборка с Buildx
Buildx — стандарт для создания образов под несколько платформ.
Сначала создайте билдер:
Затем соберите:
Это создаст манифест, где Docker выберет нужный вариант. В памяти во время сборки эмуляция ARM на x86 может занять до 2x больше RAM, но результат — универсальность.
#Java #middle #Docker #DockerFile #Docker_compose #Buildx
Минимальный Dockerfile для Java 21 с использованием BuildKit
text# syntax=docker/dockerfile:1 # Включает расширения BuildKit
FROM eclipse-temurin:21-jre
WORKDIR /app # Рабочая директория внутри контейнера
COPY target/myapp.jar /app/myapp.jar # Копируем скомпилированный JAR
ENTRYPOINT ["java", "-jar", "/app/myapp.jar"] # Команда запуска
Чтобы собрать с BuildKit-фичами:
docker buildx build -t myapp:latest --cache-to=type=inline .
Inline-кэш сохранит промежуточные результаты в образе.
Если добавить
--secret id=mysecret,source=/path/to/secret
то в RUN можно использовать $mysecret без записи в слой.
Мультиархитектурная сборка с Buildx
Buildx — стандарт для создания образов под несколько платформ.
Сначала создайте билдер:
docker buildx create --name mybuilder --use.
Затем соберите:
docker buildx build --platform linux/amd64,linux/arm64 -t repo/myapp:latest --push .
Это создаст манифест, где Docker выберет нужный вариант. В памяти во время сборки эмуляция ARM на x86 может занять до 2x больше RAM, но результат — универсальность.
#Java #middle #Docker #DockerFile #Docker_compose #Buildx
👍3
Что выведет код?
#Tasks
public class Task260825 {
public static void main(String[] args) {
int a = 5;
double b = 2;
float c = 3.0f;
double result = a / b + c;
System.out.println(result);
}
}
#Tasks
👍2
👍3
Что такое metaspace в JVM? 🤓
Ответ:
Metaspace — это область памяти в JVM (с Java 8), заменяющая PermGen, для хранения метаданных классов, таких как описания классов и методы. В отличие от PermGen, metaspace динамически расширяется и не имеет фиксированного размера, что снижает риск OutOfMemoryError: PermGen.
Управляется параметрами JVM, такими как -XX:MaxMetaspaceSize.
Полезно понимать для оптимизации памяти в больших приложениях.
#собеседование
Ответ:
Управляется параметрами JVM, такими как -XX:MaxMetaspaceSize.
Полезно понимать для оптимизации памяти в больших приложениях.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Лев Серге́евич Терме́н (фр. Léon Theremin; 16 [28] августа или 15 [27] августа 1896, Санкт-Петербург, Российская империя — 3 ноября 1993, Москва, Россия) — советский изобретатель, создатель терменвокса — первого электромузыкального инструмента.
Кри́стен Ню́гор (норв. Kristen Nygaard; 27 августа 1926, Осло — 10 августа 2002, там же) — норвежский учёный в области теории вычислительных систем, лауреат премии Тьюринга. Вместе с Оле-Йоханом Далем является одним из разработчиков основ объектно-ориентированного программирования, а также первого объектно-ориентированного языка программирования Симула.
Да́фна Коллер (англ. Daphne Koller, род. 27 августа 1968) — израильско-американский профессор факультета информатики Стэнфордского университета, стипендиат фонда Мак-Артура, сооснователь образовательной площадки Coursera. Основной областью исследований Коллер является искусственный интеллект и его приложения в биомедицине.
1962 — космическая миссия Mariner 2 отправилась на исследование Венеры.
1976 — Первое межсетевое TCP/IP-соединение: Дон Коун (SRI) запускает беспроводную связь между локальной сетью и ARPANET с помощью «Packet Radio Van» (порт в «интернет»).
1993 — Compaq Presario официально представлен на рынок. Один из первых массовых домашних ПК под брендом Compaq.
2003 — Включена самая большая в мире батарея (Fairbanks, Аляска) площадью около 2 000 м², весом ~1 300 т, обеспечивавшая аварийное электроснабжение. Выдающееся событие в области хранения энергии.
#Biography #Birth_Date #Events #27Августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Основы ООП в 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