Java
Java — статически типизированный язык, компилируемый в байт-код JVM, основной инструмент корпоративных бэкендов и Android-разработки.
Что такое Java
Java — объектно-ориентированный язык со статической строгой типизацией, выпущенный Sun Microsystems в 1995 году. Код компилируется не в машинные инструкции, а в байт-код, который исполняет виртуальная машина JVM. Отсюда принцип «write once, run anywhere»: один и тот же .jar работает везде, где есть JVM.
Три аббревиатуры, которые постоянно путают:
- JVM (Java Virtual Machine) — виртуальная машина, исполняющая байт-код. Только запуск.
- JRE (Java Runtime Environment) — JVM плюс стандартные библиотеки. Достаточно, чтобы запускать.
- JDK (Java Development Kit) — JRE плюс компилятор
javacи инструменты. Нужен, чтобы собирать.
Где живёт Java: банковские и корпоративные бэкенды (Spring Boot), Android, Big Data — Hadoop, Kafka и Elasticsearch написаны на JVM-языках.
@Override — что это
@Override — аннотация, помечающая метод как переопределяющий метод родительского класса или реализующий метод интерфейса.
На поведение программы она не влияет вообще. Её единственная задача — заставить компилятор проверить, что метод действительно что-то переопределяет:
class Animal {
void makeSound() { System.out.println("..."); }
}
class Dog extends Animal {
@Override
void makeSound() { System.out.println("Гав"); } // ок
@Override
void makeSoud() { } // опечатка → ошибка компиляции
}
Без @Override вторая строка молча создала бы новый метод makeSoud(), а makeSound() продолжил бы печатать точки. Баг ушёл бы в прод. Поэтому аннотацию ставят всегда — это бесплатная страховка от опечаток и от изменений в родительском классе.
equals и hashCode
equals() отвечает на вопрос «эти два объекта равны по смыслу?». По умолчанию (из Object) он сравнивает ссылки — то есть «это буквально один объект в памяти», почти никогда не то, что нужно.
hashCode() возвращает хеш объекта. Его используют HashMap и HashSet, чтобы быстро найти корзину с объектом, не сравнивая его со всеми подряд.
Контракт между ними — то, о чём и спрашивают на собеседованиях:
- Если
a.equals(b), тоa.hashCode() == b.hashCode()— обязательно. - Обратное неверно: одинаковый хеш при разных объектах допустим (коллизия).
- Пока объект в коллекции, его хеш меняться не должен.
Нарушение первого пункта ломает коллекции. Переопределили equals, забыли hashCode — и объект «пропадает» из HashSet:
Set<User> set = new HashSet<>();
set.add(new User(1, "Пётр"));
set.contains(new User(1, "Пётр")); // false, если hashCode не переопределён
Объекты равны по equals, но хеши разные — поиск уходит не в ту корзину. Правильно — переопределять оба, обычно по одним и тем же полям:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User user)) return false;
return id == user.id && Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
На практике оба метода генерирует IDE или закрывает Lombok (@EqualsAndHashCode); в современной Java для таких классов чаще берут record — там equals и hashCode есть из коробки.
Артефакт
Артефакт (artifact) в Java — результат сборки, файл, который можно положить в репозиторий и развернуть. JAR (Java ARchive) — библиотека или приложение, по сути zip с классами и манифестом. WAR (Web ARchive) — веб-приложение под сервлет-контейнер вроде Tomcat; сейчас чаще собирают fat JAR со встроенным сервером.
В Maven артефакт однозначно определяется координатами groupId:artifactId:version:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
</dependency>
Здесь artifactId — имя самого модуля. Собирают проект через Maven или Gradle, а готовые артефакты хранят в репозитории (Maven Central, Nexus, Artifactory) — это JVM-аналог model registry или Docker Registry для образов.
mvn clean package # собрать jar в target/
java -jar app.jar # запустить
Java на сервере: память
Главная эксплуатационная особенность — JVM управляет памятью сама, и ограничивать её нужно явно. Куча (heap) растёт до -Xmx, а сверх неё JVM берёт метапространство, стеки потоков и буферы: реальное потребление процесса всегда больше -Xmx.
В контейнере это классические грабли — JVM видит память хоста, а не лимит контейнера, раздувает кучу, и процесс убивает OOM killer. Современные JDK учитывают cgroup-лимиты, но полагаться на умолчания не стоит:
java -XX:MaxRAMPercentage=75 -jar app.jar # 75% от лимита контейнера
Отсюда же правило: лимит памяти в Kubernetes ставьте с запасом к -Xmx, а не равным ему.
Связанные термины
- SOLID — принципы, сформулированные на примерах Java
- Паттерны проектирования — книга GoF писалась в мире Java и C++
- Типы данных и типизация — статическая строгая типизация на практике
- IDE — IntelliJ IDEA как стандарт для Java
- Docker — где JVM требует настройки лимитов памяти
- Микросервисы и монолит — типичная архитектура Java-бэкендов
Готовы запустить GPU-задачу?
Запустить GPU-сервер