---
# System prepended metadata

title: Устройство Java - Всё что нужно знать

---

# Устройство Java - Всё что нужно знать
## *О чём тут написано?*
1. Язык Java. Особенности языка.
2. Средства разработки. JDK и JRE. Компиляция и выполнение программы. JAR-архивы.
3. Примитивные типы данных в Java. Приведение типов.
4. Работа с переменными. Декларация. Инициализация. Присваивание.
5. Одномерные и двумерные массивы. Декларация и создание массивов. Доступ к элементам массива.
6. Инструкции ветвления (if-else, switch) и циклов (do, while, for).
7. Операторы и выражения в Java. Особенности вычисления, приоритеты операций.
8. Математические функции в составе стандартной библиотеки Java. Класс `java.lang.Math`.
9. Подпрограммы, методы, параметры и возвращаемые значения.
10. Форматированный вывод числовых данных.
-----

## Язык Java. Особенности языка
Java — строго типизированный объектно-ориентированный кроссплатформенный язык программирования общего назначения, разработанный компанией Sun Microsystems. 

> *строго типизированный* - язык требует строгого задания типов данных, для выполнения операций с разными типами данных требуется привести их к одному типу данных. 
> ПРОЩЕ: Создавая переменную вы должны писать её тип, а не как в питоне))

> *Объектно-ориентированное программирование (ООП)* — это **подход, при котором программа рассматривается как набор объектов(классов и экземпляров), взаимодействующих друг с другом**

> *Кроссплатформенный* - программы написанные на языке Java могут работать на любой платформе благодаря JVM(Java Virtual Machine)

## Инфраструктура Java
Средства разработки. JDK и JRE. Компиляция и выполнение программы. JAR-архивы.
--
![Pasted image 20251004174753](https://hackmd.io/_uploads/HygTcZJTeg.png)


**Компилятор vs Интерпретатор**
Компилятор
- создаёт машинный код
- под конкретную платформу
- не нужен при исполнении
Интерпретатор
- интерпретирует и исполняет программу


> **JDK (Java Devolopment kit)** — это набор сервисов, облегчающих процесс написания кода на языке Java. Инструменты JDK нужны для написания кода, его компиляции, отлаживания и запуска. Без них нет возможности полноценно программировать.
> 
> **Пакет состоит из:**
> - среды выполнения Java — JRE;
> - интерпретатора — java;
 - компилятора — javac;
 >- архиватора — jar;
 - генератора документации — javadoc.

>**JRE (Java Runtime Environvement)**
   минимальная (без компилятора и других средств разработки) реализация [виртуальной машины](https://ru.wikipedia.org/wiki/%D0%92%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%88%D0%B8%D0%BD%D0%B0 "Виртуальная машина"), необходимая для исполнения [Java](https://ru.wikipedia.org/wiki/Java "Java")-приложений. Состоит из виртуальной машины [Java Virtual Machine](https://ru.wikipedia.org/wiki/Java_Virtual_Machine "Java Virtual Machine") и [библиотеки Java-классов](https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D0%B0%D1%8F_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B0 "Стандартная библиотека") (Java API)
> **Java API** - стандартный набор библиотек 
> **JIT** (Just In Time compilator) - **компилирует в моменте** часто выполняющиеся части кода(циклы и методы) переводит в машинный код и таким образом ускоряет их выполнение.
> *Возможно JIT использует hash для проверки на повторяемость результатов выполнения кода*


##### Запуск Java кода или почему Java кроссплатформенный 

> **Как это работает?**
> Вы написали программу на языке Java. Далее вы компилируете программу c помощью javac(Java compiler входит в JDK)  на выходе получается файл .class c байт-кодом. (его можно посмотреть с помощью javap). 
> 
> Далее, когда вам нужно запустить код вашего Java-приложения, JVM интерпретирует готовый байт-код в машинный код, а с помощью JIT (Just In Time compiler — компилятора «в реальном времени») часто выполняющиеся части кода (циклы и методы) переводятся в машинный код, что ускоряет их выполнение. Благодаря JVM можно выполнять код, написанный на Java, на любой платформе.

**!!!Важно!!!**

```bash
javap -c YourClassName.class 
выводит байт код
```

##### JAR (Java Archive)
>— это формат архивирования, основанный на ZIP, предназначенный для объединения скомпилированных файлов Java-классов, ресурсов (таких как изображения, аудио, конфигурационные файлы) и метаданных в один файл с расширением `.jar`. Это упрощает распространение Java-приложений и библиотек, поскольку все необходимые файлы содержатся в одном архиве
>
>MyProgramm.java => **javac** => MyProgramm.class => **jar**  => MyProgramm.jar


Файл который определяет откуда будет запускаться ваша программа после создания JAR
``` MANIFEST
MANIFEST.MF
– Main-Class: Hello
```

``` bash
jar -c -f hello.jar -e Hello *.class 
```



## Примитивные типы данных и приведение типов

Примитивные типы в Java — это восемь основных, не-объектных типов данных, встроенных в язык. Они делятся на целочисленные (byte, short, int, long, char), вещественные (float, double(два бита)) для чисел с плавающей точкой и логический тип boolean (true или false), который используется в операциях сравнения.

**Примитивные**
- Целые (byte, short, int, long)
- Символьные (char)
- Вещественный (float, double)
- Логический (boolean)

![Pasted image 20251004191710](https://hackmd.io/_uploads/ByOlobJ6xl.png)

##### Не примитивные типы данных или ссылочные типы данных
Это данные, которые являются составными(классы, массивы, строки(массив char))

**Примитивные типы vs ссылочные**
![Pasted image 20251004202842](https://hackmd.io/_uploads/BJ7GsWJagl.png)

#### Приведение типов
Бывает явным и неявным в зависимости от того насколько дружат типы) 
*Почитайте в интернете об этом чуть более подробно*
###### Ниже пример кода, когда тип данных изменяется автоматически, то есть неявно
```java
int intValue = 100;
long longValue = intValue;        // автоматически
double doubleValue = intValue;    // автоматически
float floatValue = longValue;     // автоматически
```
###### Явное приведение или ручное
```java
double doubleValue = 100.9;
int intValue = (int) doubleValue;     // будет 100 (дробная часть отбрасывается)
long longValue = 30000;
short shortValue = (short) longValue; // может быть потеря данных
```


## Переменные
**Декларация. Инициализация. Присваивание - этапы жизни переменных**
##### 1. Декларация (объявление)
Объявление переменной с указанием её типа и имени.

```java
// Декларация без значения
int age;
String name;
double salary;
```
##### 2. Инициализация
Первое присваивание значения переменной.

```java
// Явная инициализация при объявлении
int age = 25;
String name = "Иван";
double salary = 50000.0;

// Отложенная инициализация
int count;
count = 10; // инициализация
```
##### 3. Присваивание
Изменение значения уже объявленной переменной.

```java
int x = 5;  // декларация + инициализация
x = 10;     // присваивание нового значения
x = 15;     // еще одно присваивание
```

### Память в Java
https://topjava.ru/blog/stack-and-heap-in-java

>Для оптимальной работы приложений JVM использует разные типы памяти, каждая из которых имеет свое назначение и особенности.
  Всякий раз, когда мы объявляем переменные, создаем объекты или вызываем методы, виртуальная машина выделяет память для этих операций либо в стеке (_stack_), либо в куче (_heap_).

##### **СТЕК**
>Всякий раз, когда в Java вызывается новый метод, содержащий примитивные значения или ссылки на объекты, на вершине стека под них выделяется блок памяти, называемый фреймом (_frame, кадр стека_). Этот блок создается в верхней части пространства памяти стека и растет вниз по мере добавления новых данных.

Фреймы обычно содержат:  
- аргументы вызванного метода, которые были ему переданы
- зарезервированное пространство под локальные переменные, созданные в методе
- ссылки на объекты в куче на которые ссылается метод
- адрес возврата, указывающий на строку байт-кода, куда методу следует вернуть результат своей работы
- ссылку на предыдущий фрейм (указатель на фрейм вызывающего метода)

>Когда метод завершает выполнение, отведенный для его нужд фрейм, очищается (выталкивается), освобождая пространство для нового метода. При этом поток выполнения программы возвращается к месту вызова метода с последующим переходом к следующей строке кода.

Именно из-за стека рекурсия бывает выдает ошибку)

##### **КУЧА**
>Эта область памяти используется для динамического выделения памяти для объектов и классов JRE во время выполнения. Новые объекты всегда создаются в куче, а ссылки на них хранятся в стеке.  
   Эти объекты имеют глобальный доступ и могут быть получены из любого места программы.

**Эта область памяти разбита на несколько более мелких частей, называемых поколениями:** 
1. **Young Generation** — область где размещаются недавно созданные объекты. Когда она заполняется, происходит быстрая сборка мусора  
2. **Old (Tenured) Generation** — здесь хранятся долгоживущие объекты. Когда объекты из Young Generation достигают определенного порога «возраста», они перемещаются в Old Generation  
3. **Permanent Generation** — эта область содержит метаинформацию о классах и методах приложения, но начиная с Java 8 данная область памяти была упразднена. Подробнее об этом можно узнать из [статьи](https://topjava.ru/blog/permgen-and-metaspace), а также посмотрев [видео](https://youtu.be/EMXflWb9Z5w?t=6m47s)

Мы можем управлять размерами кучи в зависимости от наших требований.

**Минусы кучи:**
- Когда эта область памяти полностью заполняется, Java бросает java.lang.OutOfMemoryError  
- Доступ к ней медленнее, чем к стеку  
- Эта память, в отличие от стека, автоматически не освобождается. Для сбора неиспользуемых объектов используется сборщик мусора  
- В отличие от стека, куча не является потокобезопасной и ее необходимо контролировать, правильно синхронизируя код


Metaspace (метапространство) — это область памяти в Java Virtual Machine (JVM), которая хранит метаданные классов. Она была введена в Java 8 и заменила собой область, известную как Permanent Generation (PermGen).


##### **КРАТКО**
---
Локальные переменные методов живут в стеке, а все объекты создаются в куче. Сборщик мусора автоматически удаляет объекты из кучи, когда на них нет ссылок.

**Память в Java** - динамически управляется:
- выделяется автоматически 
- освобождается автоматически 
- 2 основные области: стек и куча
**Стек**
- локальные переменные
- параметры метода
- примитивные значения, а также ссылки на объекты(не примитивы)
**Куча**
- Объекты (классы, массивы и т. д)
- Чиститься сборщиком мусора (Garbage Collector)


![Pasted image 20251004200720](https://hackmd.io/_uploads/Syx4jbJaxg.png)


## Одномерные и двумерные массивы. 
**Декларация и создание массивов. Доступ к элементам массива.**

Массив - это ссылочный тип данных, может иметь ноль и более элементов, характеристики массива фиксируются при создании:
- расположение в памяти начального элемента 
-  длина (количество элементов) 
-  тип (и размер в байтах) элементов

Работает всё также как и с переменными, пример работы с ними:

```java
// 1. Декларация
int[] numbers;
String[] names;

// 2. Создание с указанием размера
numbers = new int[5];          // массив из 5 элементов (0,0,0,0,0)
names = new String[3];         // массив из 3 элементов (null,null,null)

// 3. Декларация + создание в одной строке
double[] prices = new double[10];

// 4. Инициализация с значениями
int[] primes = {2, 3, 5, 7, 11};
String[] colors = {"red", "green", "blue"};

// Чтение элементов
System.out.println(primes[0]);    // 10 (первый элемент)
System.out.println(primes[2]);    // 30 (третий элемент)

// Запись элементов
numbers[1] = 25;                   // было 20, стало 25
numbers[4] = 100;                  // было 50, стало 100

// Итерация по массиву
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

// For-each цикл
for (int number : numbers) {
    System.out.println(number);
}
```
#### Двумерные массивы

```java
// 1. Декларация
int[][] matrix;
String[][] table;

// 2. Создание прямоугольного массива
matrix = new int[3][4];        // 3 строки, 4 столбца
table = new String[2][3];      // 2 строки, 3 столбца

// 3. Декларация + создание
double[][] prices = new double[5][5];

// 4. Инициализация с значениями
int[][] matrix2 = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// 5. Зубчатый массив (jagged array)
int[][] jagged = new int[3][];
jagged[0] = new int[2];        // первая строка - 2 элемента
jagged[1] = new int[4];        // вторая строка - 4 элемента  
jagged[2] = new int[3];        // третья строка - 3 элемента

```

```java
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// Чтение элементов
System.out.println(matrix[0][0]);  // 1 (первая строка, первый столбец)
System.out.println(matrix[1][2]);  // 6 (вторая строка, третий столбец)

// Запись элементов
matrix[0][1] = 20;                // было 2, стало 20
matrix[2][2] = 99;                // было 9, стало 99

// Итерация по двумерному массиву
for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        System.out.print(matrix[i][j] + " ");
    }
    System.out.println();
}

// For-each для двумерного массива
for (int[] row : matrix) {
    for (int element : row) {
        System.out.print(element + " ");
    }
    System.out.println();
}
```

**Многомерные массивы**
Есть два способа хранения многомерных массивов
 1 способ - плотный (dense) или регулярный (regular) массив
 - Для доступа к элементу многомерного массива в этом плоском массиве используется математическая формула, которая преобразует многомерные индексы в один одномерный.
 - Единый блок хранения в памяти
 - Высокая производительность 
 - Возможность гибко менять форму и размерность 
 
 2 способ (Массив массивов меньшей размерности)
 - Может храниться частями
 - Производительность ниже, но зависит от реальной формы
 - Возможность иметь не только прямоугольную форму 

**ВАЖНО: В java массивы хранятся, как массив массивов. Это фундаментальное архитектурное решение языка.**
В Java многомерные массивы хранятся не как единый непрерывный блок памяти, а как массив массивов. Это означает, что: 
- В двумерном массиве каждая "строка" является отдельным одномерным массивом.
- Главный (внешний) массив содержит ссылки на эти внутренние массивы, а не сами данные.
- Каждый внутренний массив хранится в памяти независимо от других. 



![Pasted image 20251004203956](https://hackmd.io/_uploads/BkHriZJagx.png)



## Инструкции ветвления (if-else, switch) и циклов (do, while, for).

```java
if (number > 0) {
    System.out.println("Число положительное");
}
        
// if-else
if (number % 2 == 0) {
    System.out.println("Число четное");
} else {
    System.out.println("Число нечетное");
}
        
// if-else if-else
int score = 85;
if (score >= 90) {
    System.out.println("Оценка A");
} else if (score >= 80) {
    System.out.println("Оценка B");
} else if (score >= 70) {
    System.out.println("Оценка C");
} else {
    System.out.println("Оценка D");
}

// switch
switch (dayOfWeek) {
    case 1:
        System.out.println("Понедельник");
        break;
    case 2:
        System.out.println("Вторник");
        break;
    case 3:
	    System.out.println("Среда");
        break;
    case 4:
        System.out.println("Четверг");
        break;
    case 5:
        System.out.println("Пятница");
        break;
    default:
        System.out.println("Выходной день");
}
        
// Switch с несколькими case (Java 14+)
String season = "Лето";
switch (season) {
    case "Зима", "Весна", "Лето", "Осень" -> 
        System.out.println("Это время года: " + season);
    default -> System.out.println("Неизвестное время года");
}

// Классический for
System.out.println("Числа от 1 до 5:");
for (int i = 1; i <= 5; i++) {
    System.out.println("i = " + i);
}
        
// Обратный отсчет
System.out.println("Обратный отсчет:");
for (int i = 5; i >= 1; i--) {
    System.out.println("i = " + i);
}
        
// For-each для массива
String[] fruits = {"Яблоко", "Банан", "Апельсин"};
System.out.println("Фрукты:");
for (String fruit : fruits) {
    System.out.println(fruit);
}
// While с условием
int counter = 1;
System.out.println("While цикл:");
while (counter <= 5) {
    System.out.println("Счетчик: " + counter);
    counter++;
}

// Do-while (гарантированно выполнится хотя бы 1 раз)
int number = 10;
System.out.println("Do-while цикл:");
do {
    System.out.println("Число: " + number);
    number++;
} while (number <= 5); // Условие ложно, но цикл выполнится 1 раз
```

## Операторы и выражения в Java. Особенности вычисления, приоритеты операций.

>Операторы  — это специальные символы или ключевые слова, которые выполняют операции над операндами (переменными, константами, выражениями). Выражения комбинируют операторы и операнды для вычисления значения.  

---

### **1. Типы операторов**
#### **Арифметические**
- `+` (сложение), `-` (вычитание), `*` (умножение), `/` (деление), `%` (остаток от деления).
- Инкремент/декремент: `++` и `--` (префиксные и постфиксные).
- Пример:
  ```java
  int a = 5 + 3; // 8
  int b = a % 3; // 2
  ```

#### **Операторы сравнения**
- `==`, `!=`, `>`, `<`, `>=`, `<=`.
- Возвращают `boolean`:
  ```java
  boolean result = (10 > 5); // true
  ```

#### **Логические**
- `&&` (И), `||` (ИЛИ), `!` (НЕ).
- **Сокращённое вычисление (short-circuit)**:
- Для `&&`: если левый операнд `false`, правый не вычисляется.
- Для `||`: если левый операнд `true`, правый не вычисляется.
- Пример:
```java
if (x != null && x.getValue() > 10) { ... } // Безопасно
    ```

#### **Побитовые**
- `&`, `|`, `^` (XOR), `~` (НЕ), `<<`, `>>`, `>>>`.
- Работают с битами целочисленных типов:
  ```java
  int x = 5 & 3; // 1 (101 & 011 = 001)
  ```

#### **Присваивания**
- `=`, `+=`, `-=`, `*=`, `/=`, `%=` и другие комбинированные операторы.
- Пример:
  ```java
  int x = 10;
  x += 5; // x = 15
  ```

#### **Тернарный оператор**
- `условие ? выражение1 : выражение2`.
- Пример:
  ```java
  int max = (a > b) ? a : b;
  ```
  
### **2. Приоритет операций**
Приоритет определяет порядок вычисления. Список от высшего к низшему:

| Категория         | Операторы                                      |
| ----------------- | ---------------------------------------------- |
| Постфиксные       | `[]`, `()`, `.`, `++`, `--` (после переменной) |
| Унарные           | `++`, `--`, `!`, `~`, `+`, `-` (унарные)       |
| Мультипликативные | `*`, `/`, `%`                                  |
| Аддитивные        | `+`, `-`                                       |
| Сдвиги            | `<<`, `>>`, `>>>`                              |
| Отношение         | `<`, `<=`, `>`, `>=`, `instanceof`             |
| Равенство         | `==`, `!=`                                     |
| Побитовые И       | `&`                                            |
| Побитовое XOR     | `^`                                            |
| Логическое И      | `&&`                                           |
| Тернарный         | `? :`                                          |
| Присваивание      | `=`, `+=`, `-=` и т.д.                         |

**Пример:**
```java
int result = 10 + 5 * 2; // 5*2 вычисляется первым → 10 + 10 = 20
boolean flag = true || false && false; // && приоритетнее → true || (false) = true
```

## Математические функции в составе стандартной библиотеки Java. Класс `java.lang.Math`

| Категория | Метод | Описание |
| :--- | :--- | :--- |
| **Основные операции** | `abs(double a)` | Возвращает абсолютное значение (модуль) числа. |
| | `max(double a, double b)` | Возвращает большее из двух чисел. |
| | `min(double a, double b)` | Возвращает меньшее из двух чисел. |
| **Степени, корни, логарифмы** | `pow(double a, double b)` | Возводит число `a` в степень `b`. |
| | `sqrt(double a)` | Возвращает квадратный корень числа. |
| | `cbrt(double a)` | Возвращает кубический корень числа. |
| | `log(double a)` | Возвращает натуральный логарифм (по основанию `e`). |
| | `log10(double a)` | Возвращает десятичный логарифм. |
| **Тригонометрия** | `sin(double a)`, `cos(double a)`, `tan(double a)` | Стандартные тригонометрические функции (угол в радианах). |
| | `toRadians(double angdeg)` | Преобразует угол из градусов в радианы. |
| | `toDegrees(double angrad)` | Преобразует угол из радиан в градусы. |
| **Округление** | `round(double a)` | Округляет до ближайшего целого числа. |
| | `ceil(double a)` | Округляет число вверх ("потолок"). |
| | `floor(double a)` | Округляет число вниз ("пол"). |
| **Случайные числа** | `random()` | Возвращает случайное `double` число от `0.0` (включительно) до `1.0` (не включительно). |
| **Полезные константы** | `Math.PI` | Число π (приблизительно 3.14159). |
| | `Math.E` | Число e (основание натурального логарифма, приблизительно 2.718). |

#### Примеры использования

```java
// Вычисление гипотенузы
double sideA = 3.0;
double sideB = 4.0;
double hypotenuse = Math.hypot(sideA, sideB); // Результат: 5.0

// Возведение в степень и округление
double radius = 10.0;
double area = Math.PI * Math.pow(radius, 2);
long roundedArea = Math.round(area); // Результат: 314

// Генерация случайного числа в диапазоне [min, max]
int min = 10;
int max = 20;
int randomNum = (int) (Math.random() * ((max - min) + 1)) + min;
```

## Подпрограммы, методы, параметры и возвращаемые значения.

**Подпрограммы** - именованная часть кода, которая может выполняться по вызову. Уменьшает количество строк кода в программе и улучшает читаемость.
**Функция** - подпрограмма, не привязанная к методу
**Методы** - подпрограмма, которая в отличии от функции привязана к классу или объекту.
**Параметры** - специальные переменные метода или функции передаваемые вовремя вызовы.

| Тип параметров                 | Синтаксис                | Особенности                    |
| ------------------------------ | ------------------------ | ------------------------------ |
| **Обычные параметры**          | `(тип1 имя1, тип2 имя2)` | Каждый параметр имеет свой тип |
| **Varargs (переменное число)** | `(тип... имя)`           | Все аргументы одного типа      |


## Форматированный вывод числовых данных.
![Pasted image 20251004230133](https://hackmd.io/_uploads/H1nIs-16xx.png)

## Metaspace, ClassLoader, JIT
### 1. Metaspace (Метасространство) и ClassLoader (Загрузчик классов)

**Metaspace** — это область памяти в JVM (заменившая собой старую **PermGen** начиная с Java 8), где хранится **метаинформация о классах**.
*   **Что хранится:** Определения классов (имя, методы, поля, аннотации), константный пул (constant pool), информация для JIT-компиляции и т.д.
*   **Важно:** Это не память под сами объекты (объекты лежат в Heap/Кучи), а их "чертежи".
*   **Управление памятью:** Metaspace автоматически расширяется (в рамках ограничений, которые можно задать) и собирается сборщиком мусора (Garbage Collection), когда класс выгружается. Класс выгружается, когда его загрузивший ClassLoader и все его экземпляры становятся недостижимыми.

**ClassLoader (Загрузчик классов)** — это часть JVM, которая отвечает за динамическую загрузку, связывание и инициализацию классов.
*   **Иерархия:** Работают по принципу делегирования. Есть Bootstrap ClassLoader (загружает системные классы), Extension ClassLoader (загружает классы расширений) и Application ClassLoader (загружает классы вашего приложения).
*   **Связь с Metaspace:** Когда ClassLoader загружает класс, он помещает всю его метаинформацию в Metaspace. Каждый класс "помнит", какой ClassLoader его загрузил.

**Взаимосвязь:** ClassLoader'ы загружают байт-код классов, а метаинформация об этих классах хранится в Metaspace. JIT-компилятор (C1/C2) использует эту метаинформацию для компиляции.

---

### 2. C1 и C2: Как JIT компилирует методы и циклы

JIT (Just-In-Time) — компиляция "на лету". Вместо того чтобы интерпретировать байт-код снова и снова, JVM компилирует часто выполняемые участки кода в нативный машинный код для процессора.

В HotSpot JVM используется **Многоуровневая компиляция (Tiered Compilation)**, которая объединяет два компилятора:

*   **C1 (Клиентский компилятор):**
    *   **Цель:** Скорость компиляции, минимальные затраты, быстрое стартовое время.
    *   **Оптимизации:** Базовые (inlining, удаление неиспользуемого кода, несложные оптимизации циклов).
    *   **Используется на** уровнях 1, 2 и 3 многоуровневой компиляции.

*   **C2 (Серверный компилятор):**
    *   **Цель:** Максимальная производительность (пиковая), даже ценой более долгой компиляции.
    *   **Оптимизации:** Очень агрессивные и сложные. Основаны на **профилировании** (сборе статистики во время работы).
    *   **Примеры оптимизаций C2:** Инлайнинг виртуальных методов, размотровка циклов, анализ эскейп-анализа (определение, что объект не "убегает" за пределы метода и может быть размещен на стеке), удаление границ проверок массивов и т.д.
    *   **Используется на** уровне 4.

#### Процесс компиляции методов и циклов

1.  **Интерпретация и подсчет.**
    *   Изначально все методы выполняются в **интерпретаторе**.
    *   У каждого метода есть два счетчика:
        *   **Счетчик вызовов** (invocation counter): Увеличивается при каждом входе в метод.
        *   **Счетчик обратных ветвлений** (backedge counter): Увеличивается при каждом завершении итерации цикла (когда выполнение "перепрыгивает" назад к началу цикла).

2.  **Обнаружение "Горячего" кода (HotSpot).**
    *   JVM постоянно следит за этими счетчиками. Когда они превышают определенный порог, метод или цикл помечаются как "горячие" (**hot spot** — отсюда и название HotSpot JVM).
    *   **Метод становится "горячим"** при большом количестве вызовов.
    *   **Цикл становится "горячим"** при большом количестве итераций (даже внутри одного вызова метода!).

3.  **Эскалация компиляции (Tiered Compilation).**
    *   **Уровень 3 (C1 с полным профилированием):** Сначала "горячий" метод компилируется компилятором **C1**. На этом этапе C1 активно собирает детальную профилировочную информацию: какие типы объектов реально используются, какие ветки кода выполняются чаще и т.д.
    *   **Уровень 4 (C2 с агрессивными оптимизациями):** Когда набирается достаточно профилировочных данных, в дело вступает **C2**. Он использует эти данные для проведения глубоких оптимизаций.

#### Специфические оптимизации для циклов

*   **Размотровка цикла (Loop Unrolling):** C2 может "развернуть" цикл, чтобы уменьшить количество проверок условий.
    *   **Было:**
        ```java
        for (int i = 0; i < 1000; i++) {
            doSomething(i);
        }
        ```
    *   **Стало (условно, в нативном коде):**
        ```java
        for (int i = 0; i < 1000; i += 4) {
            doSomething(i);
            doSomething(i+1);
            doSomething(i+2);
            doSomething(i+3);
        }
        ```
    Это снижает накладные расходы на проверку `i < 1000` и инкремент `i++`.

*   **Вынос инвариантов (Loop Invariant Code Motion):** Если внутри цикла есть вычисления, результат которых не меняется от итерации к итерации, C2 выносит их за пределы цикла.
    *   **Было:**
        ```java
        for (int i = 0; i < items.length; i++) {
            result = items[i] * Math.PI; // Math.PI - константа
        }
        ```
    *   **Стало:**
        ```java
        double constantPi = Math.PI;
        for (int i = 0; i < items.length; i++) {
            result = items[i] * constantPi;
        }
        ```

*   **Слияние циклов (Loop Fusion):** Если подряд идут два цикла с одинаковыми условиями, C2 может объединить их в один, чтобы уменьшить количество проходов.

*   **Замена на intrinsics:** Очень маленькие и часто используемые циклы (например, `System.arraycopy`) JVM может заменить на предопределенный высокооптимизированный машинный код (intrinsic).

### Краткий итог процесса:

**Интерпретатор → Сбор профиля → C1 (быстро) → Больше профиля → C2 (медленно, но очень эффективно) → Агрессивные оптимизации (размотровка циклов и т.д.)**

Эта сложная система позволяет Java-приложениям начинать работу быстро (благодаря интерпретатору и C1), а со временем достигать производительности, сравнимой с скомпилированным C++ кодом (благодаря C2).