int i = 2;
if (i = 4) {
printf("head\n");
} else {
printf("tail\n");
}@inponomarev
Иван Пономарёв, КУРС/МФТИ
![]() |
|
![]() | ![]() | ![]() |
Cay S. Horstmann. Core Java vol 1 & 2
Raoul-Gabriel Urma et al. Modern Java in Action
![]() | ![]() |
Joshua Bloch Effective Java
Brian Goetz et al. Java Concurrency in Practice
Устаревший язык, на нём, наверное, уже новых проектов и не пишет никто…
Языки вообще учить не надо: Claude всё напишет за нас…
Что такого я узнаю на лекциях, чего нет онлайн?..
— всё это правильные вопросы! Отвечу на них с конца…
Инженерия — искусство компромиссов (engineering trade-offs).
Осваивать это искусство хорошо на удачных примерах из прошлого.
Java — такой пример.
Инженеру в наше время не так важно знать конкретный язык, как понимать, что компромисс неизбежен, и уметь выбирать наилучший.
Язык + виртуальная машина: https://docs.oracle.com/javase/specs/index.html
Java Language Specification (872 стр)
Java Virtual Machine Specification (626 стр)
Экосистема
стандартная библиотека,
иные JVM-языки (Kotlin, Scala, Groovy), и реализации языков для JVM (JRuby)
Репозиторий библиотек Maven Central и огромное количество переиспользуемого кода
Тулинг (IDE, инструменты тестирования)
![]() James Gosling (JPoint 2020) |
|
The Java Story: The Official Documentary, July 2026
https://www.youtube.com/watch?v=ZqGSg4b_cZA
Q&A with James Gosling, June 2020:
https://www.youtube.com/watch?v=XThhlihqTXI
| ![]() |
Повсюду: от чипов в банковских картах до серверов в дата-центрах.
![]() |
| ![]() |
![]() |
При разработке Android, Google использовали Java как язык, javac, стандартные API, байткод, но не виртуальную машину и не реализацию API.
11 лет судов Google с Oracle (2010—2021), пока решение не было вынесено в пользу Google.
Kotlin (язык, компилирующийся в тот же JVM байт-код) провозглашён основным языком Android.
Oracle не признаёт настоящей «Джавой» то, что работает на Android.
По некоторым оценкам, в мире около 3.9 млрд Android-устройств.
Напечатает | Не скомпилируется (как и в C, |
Язык допускает подобный код (компилятор, в зависимости от версии и настроек, может выдать warning). | Не скомпилируется (unreachable statement не допустим). |

Неопределённое поведение | 3 + 4 + 5 = 12 |
Неопределенное поведение (включая чтение чужих данных или segmentation fault). |
|
Неопределенное поведение (включая аварийное завершение программы). |
|
На разных типах компьютеров разные
Endianness…
Размер регистров и ссылок (sizeof(int), sizeof(void *)…
Floating point hardware & format…
Приходилось разрабатывать разные версии программ для разных платформ (или писать спагетти из #ifdef)
Java bytecode — исполняемый код виртуальной машины. Виртуальные машины (написанные на C++) написаны для разных платформ, все они исполняют байт-код.
LLVM intermediate representation — схожая идея, появившаяся позднее.
Решается вопрос не только кроссплатформенности, но и безопасности.
![]() | ![]() |

Перед выполнением байткода, JVM выполняет его статическую проверку (https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.10)
Если код невалидный (например, stack underflow) — VerifyError

JVM начинает исполнение с интерпретации байт-кода, накапливая статистику выполнения.

По мере того, как накапливается статистика использования кода, код компилируется в оптимизированный машинный код с использованием допущений, накопленных по статистике выполнения.
Скомпилированный код хранится в Code Cache (специальном сегменте оперативной памяти).

Если путь выполнения меняется, срабатывает "uncommon trap" и выполнение возвращается к интерпретатору.
| ![]() |
| ![]() |
| ![]() |
| ![]() |
| ![]() |
Нет больше * и &, всё определено за нас.
«Объекты» и «примитивы/value-объекты» ведут себя по-разному.
| ![]() |
| ![]() |
| ![]() |
| ⇒ нет проблемы «висячих» ссылок |
| ⇒ нет проблемы «потерянных» ссылок |
| Компромисс ради быстродействия при отсутствии лучшего решения. Осложнил систему типов, обучение языку Java, привёл к дальнейшим проблемам типа использования типов-обёрток в generics. |
C#: «соперник Java», на 4 года моложе Джавы
|
Rust: «соперник C», примерно на 10 лет моложе Джавы
|
Потребляет слишком много памяти
Медленно стартует
Многословна (слишком много "boilerplate code")
Язык консервативен, медленно развивается (этот аргумент, в частности, привёл к появлению новых JVM языков: Scala, Groovy, Xtend, Kotlin).
С 2018 года Oracle перешёл на 6-месячный цикл релизов.

https://redmonk.com/ — Альтернатива TIOBE с 2012 г., GitHub+StackOverflow. Проблема: StackOverflow, достигавший пика в 2016м, теперь практически мёртв.
Мир меняется, языки и платформы развиваются в условиях жёсткой конкуренции — Java не исключение.
Как ни измеряй, Java/JVM на протяжении 30 лет была и продолжает быть одной из ведущих экосистем.
Garbage Collection
MultiThreading & Memory Model
Загрузка и исполнение кода в runtime
Рефлексия
Стандартная библиотека
Достоинства
WORA
Safety/техническая безопасность: исключение фатальных сбоев на сервере
Security/информационная безопасность: защита от злонамеренных действия
Недостатки
Overhead по производительности и памяти
Отсутствие гибкости, предоставляемой низкоуровневыми языками
Разработчику не нужно заботиться о высвобождении памяти
Ссылок на объект нет? — garbage collection
Достоинства:
Меньше кода
Не бывает некорректных ссылок (на разрушенный объект)
Меньше утечек памяти
Недостатки:
Не контролируем время работы GC
STW-паузы (бывает, в неподходящий момент)
GC полностью изолирован от исполняемого кода.
Семантика не меняется при замене одного GC на другой!
![]() |
| ![]() |
Latency | ![]() | Throughput |
Многопоточность
Возможность запуска параллельных потоков выполнения встроена в язык с первой версии (Thread, Runnable etc)
Memory Model
Часть спецификации VM: модель того, как работает хранилище данных в условиях многопоточного доступа
Отвечает на вопрос: «какие значения может прочитать конкретный read в программе?»
class DumbWayToFallAsleep implements Runnable {
private boolean asleep;
public void setAsleep(boolean asleep){
this.asleep = asleep;
}
@Override
public void run() {
while (!asleep){
//countSomeSheep
//УСНЁМ ЛИ МЫ?
}
}
}class NotSoDumbWayToFallAsleep implements Runnable {
private volatile boolean asleep;
public void setAsleep(boolean asleep){
this.asleep = asleep;
}
@Override
public void run() {
while (!asleep){
//countSomeSheep
//...
}
}
}Скомпилированный байт-код класса может быть доставлен на любую систему в runtime (чаще всего «подкладыванием файла» на файловую систему).
Пересборка/линковка не требуется.
Идея, в начале казавшаяся очень хорошей!
Исследование информации о классах, полях, методах и т. д. во время выполнения
Чтение/модификация полей (в том числе private!) и динамический вызов методов (в том числе private!)
Proxy и AOP
Независимая от системы часть
Структуры данных
Математика
Зависимая от системы часть
Дата и время
Доступ к файловой системе
Доступ к сети
Пользовательский интерфейс
Любой, как угодно давно скомпилированный .jar-файл может быть запущен на любой современной JVM
Дар или проклятие?
type inference (var),
switch expressions,
text blocks
sealed classes,
pattern matching (instanceof, switch),
records,
unnamed main classes,
virtual threads…
Project Amber: productivity-oriented features (например: flexible constructors)
Project Loom: fibers & continuators
Project Valhalla: value objects
Panama: Java & native code connection
Leyden: improve startup time
etc…
Есть виртуальная машина — можно компилировать из любого языка!
20-30 языков
Специально созданные: Groovy, Scala, Kotlin, Xtend…
Реимплементация для JVM: JRuby, Clojure (Lisp dialect), Nashorn/Graal.js…
Библиотеки и фреймворки (в т. ч. для тестирования)
Среды разработки
Репозиторий Maven Central
Системы сборки
IDEA (proprietary, JetBrains) | NetBeans (ASF / Oracle) |
Eclipse Foundation |
VS Code (Microsoft) |
22 миллиона пакетов, 2-3 млн новых пакетов каждый год (https://mvnrepository.com/repos/central)
Условие публикации — open source (хотя есть исключения), обязательно прикладывать исходники и электронную подпись.
В отличие от PyPI и npm, авторы имеют group id, основанный на домене организации (com.microsoft, org.atp-fivt), и производится процесс верификации домена.
XML configuration | ![]() Groovy DSL / Kotlin DSL |
Conferences (Joker/JPoint/SnowOne, DevoXX etc.)
JUGs
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>hello-world</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.release>25</maven.compiler.release>
</properties>
</project>src/main/java/org/example/Main.java
package org.example;
public class Main {
static void main() {
IO.println("Hello World!");
}
}mvn package
java -cp target/hello-world-1.0-SNAPSHOT.jar org.example.Main