Files
2026-09-14 19:26:07 +03:00

381 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Целые числа в Java: теория и практика
## 1. Что такое целые числа и зачем они нужны
**Целое число** — это число без дробной части: ..., −3, −2, −1, 0, 1, 2, 3, ...
В программировании целые числа используются для:
- счёта объектов (количество учеников, итераций цикла);
- индексов массивов и коллекций;
- идентификаторов (номер заказа, ID пользователя);
- работы с денежными суммами в копейках/центах (чтобы избежать ошибок округления);
- битовых операций и работы с памятью.
> ⚠️ **Важно:** в Java нельзя хранить в целочисленной переменной дробное значение — компилятор выдаст ошибку или потребует явного приведения.
---
## 2. Примитивные целочисленные типы
В Java **4 примитивных целочисленных типа**, различающихся диапазоном и объёмом памяти:
| Тип | Размер | Диапазон | Применение |
|-----|--------|----------|------------|
| `byte` | 8 бит | от −128 до 127 | экономия памяти в массивах, работа с байтами |
| `short` | 16 бит | от −32 768 до 32 767 | редко, в основном в устаревшем коде |
| `int` | 32 бита | от −2 147 483 648 до 2 147 483 647 | **основной тип по умолчанию** |
| `long` | 64 бита | от −9.2·10¹⁸ до 9.2·10¹⁸ | большие числа, время в миллисекундах |
**Запомните:** по умолчанию любое целое литеральное число в Java имеет тип `int`. Чтобы получить `long`, добавьте суффикс `L`:
```java
int a = 2_000_000_000; // ок
long b = 9_000_000_000L; // без L будет ошибка компиляции
```
---
## 3. Объявление переменных и литералы
```java
byte small = 100;
short medium = 30_000;
int normal = 1_000_000;
long big = 123_456_789_012L;
// Системы счисления:
int decimal = 255; // 10-я
int hex = 0xFF; // 16-я (префикс 0x)
int binary = 0b1111_1111; // 2-я (префикс 0b)
int octal = 0377; // 8-я (ведущий 0)
// Подчёркивания для читаемости
int million = 1_000_000;
```
**Константы** (`final`) — значение нельзя изменить после инициализации:
```java
final int MAX_SCORE = 100;
// MAX_SCORE = 200; // ошибка компиляции
```
---
## 4. Ввод целых чисел (класс `Scanner`)
Самый простой способ — `java.util.Scanner`.
```java
import java.util.Scanner;
public class InputDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Введите целое число: ");
int n = sc.nextInt(); // читает int
System.out.print("Введите длинное число: ");
long L = sc.nextLong(); // читает long
System.out.print("Введите байт: ");
byte b = sc.nextByte();
System.out.println(String.format("Вы ввели: %d, %d, %d", n, L, b));
sc.close();
}
}
```
Для чтения из файла/строки можно использовать `Scanner(new File("input.txt"))` или `BufferedReader`.
---
## 5. Вывод целых чисел
```java
int x = 42;
// Если нужно вывести только число — подходит обычный println:
System.out.println(x); // 42
// Когда нужен текст или форматирование — String.format:
System.out.println(String.format("x = %d", x));
// Форматирование в разных системах счисления:
System.out.println(String.format("hex = %x, bin = %s",
255, Integer.toBinaryString(255)));
// hex = ff, bin = 11111111
// Выравнивание и ширина поля:
System.out.println(String.format("|%5d|", 42)); // | 42|
System.out.println(String.format("|%-5d|", 42)); // |42 |
System.out.println(String.format("|%05d|", 42)); // |00042|
```
Часто используемые спецификаторы `String.format`:
| Спецификатор | Смысл |
|--------------|-------|
| `%d` | целое в 10-й системе |
| `%x` | 16-я система |
| `%o` | 8-я система |
| `%05d` | целое с ведущими нулями, ширина 5 |
| `%n` | перевод строки (переносимый) |
---
## 6. Основные операции
### 6.1 Арифметические
```java
int a = 17, b = 5;
System.out.println(a + b); // 22
System.out.println(a - b); // 12
System.out.println(a * b); // 85
System.out.println(a / b); // 3 — ЦЕЛОЧИСЛЕННОЕ деление
System.out.println(a % b); // 2 — остаток от деления
```
> ⚠️ Деление целых чисел **отбрасывает дробную часть**, а не округляет: `7 / 2 == 3`, `-7 / 2 == -3` (округление к нулю).
### 6.2 Операции присваивания
```java
int x = 10;
x += 5; // x = 15
x -= 3; // x = 12
x *= 2; // x = 24
x /= 4; // x = 6
x %= 4; // x = 2
x++; // x = 3
x--; // x = 2
```
### 6.3 Сравнение
```java
int p = 5, q = 7;
boolean r1 = p == q; // false
boolean r2 = p != q; // true
boolean r3 = p < q; // true
boolean r4 = p >= q; // false
```
### 6.4 Побитовые операции
```java
int m = 0b1100; // 12
int n = 0b1010; // 10
System.out.println(m & n); // 8
System.out.println(m | n); // 14
System.out.println(m ^ n); // 6
System.out.println(~m); // -13
System.out.println(m << 1); // 24 (сдвиг влево = ×2)
System.out.println(m >> 1); // 6 (сдвиг вправо)
System.out.println(m >>> 1); // 6 (беззнаковый сдвиг)
```
### 6.5 Приведение типов
**Автоматическое** (расширяющее) — от меньшего к большему:
```java
byte b = 100;
int i = b; // ок
long l = i; // ок
```
**Явное** (сужающее) — от большего к меньшему, возможна потеря данных:
```java
int big = 300;
byte small = (byte) big; // 300 % 256 = 44 (переполнение)
```
**Переполнение** — опасная ситуация: `int` не может выйти за пределы диапазона и «зацикливается»:
```java
int max = Integer.MAX_VALUE;
System.out.println(max + 1); // -2147483648
```
---
## 7. Критерии применимости целых чисел
Используйте целочисленный тип, если:
1. **Величина по своей природе дискретна** — количество, индекс, счётчик.
2. **Нужна точность без округлений** — деньги (лучше в копейках), ID, временные метки.
3. **Выполняются операции над целыми** — деление нацело, остаток, битовые сдвиги.
4. **Важна производительность** — целочисленная арифметика быстрее вещественной.
5. **Нужна экономия памяти** — например, `byte[]` для большого массива.
**Не используйте целые числа**, если:
- величина непрерывна (расстояние, температура, вес) — берите `double`/`float`;
- нужна высокая точность над дробными числами — `BigDecimal`.
**Выбор типа:**
- по умолчанию — `int`;
- если значения > 2·10⁹ или работа со временем в мс — `long`;
- для больших массивов малых чисел — `byte`/`short`;
- для чисел, не помещающихся ни в один примитив (> 9.2·10¹⁸) — `BigInteger`.
---
## 8. Классы стандартной библиотеки
### 8.1 Классы-обёртки: `Integer`, `Long`, `Short`, `Byte`
Каждому примитиву соответствует класс-обёртка. Нужен для:
- хранения в коллекциях (`ArrayList<Integer>`);
- использования полезных методов;
- `null`-значений (например, «значение отсутствует»).
```java
Integer obj = 42; // автоупаковка (autoboxing)
int prim = obj; // автораспаковка (unboxing)
// Полезные методы (там, где выводится только число — println):
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Integer.parseInt("123")); // 123
System.out.println(Integer.compare(3, 5)); // -1
System.out.println(Integer.max(3, 5)); // 5
System.out.println(Integer.sum(3, 5)); // 8
System.out.println(Integer.bitCount(7)); // 3
System.out.println(Integer.numberOfLeadingZeros(1)); // 31
// Там, где результат — строка — String.format:
System.out.println(String.format("%s", Integer.toBinaryString(10))); // 1010
System.out.println(String.format("%s", Integer.toHexString(255))); // ff
```
> ⚠️ Сравнивайте объекты-обёртки через `.equals()`, а не `==`:
> ```java
> Integer a = 1000, b = 1000;
> System.out.println(a == b); // false (разные объекты)
> System.out.println(a.equals(b)); // true
> ```
> Кэш `Integer` работает только для значений от −128 до 127, поэтому `Integer a = 100; Integer b = 100; a == b` даст `true`, но для 1000 — уже `false`.
### 8.2 `BigInteger` — для чисел произвольной длины
Когда `long` недостаточно (факториалы, криптография, длинная арифметика):
```java
import java.math.BigInteger;
BigInteger a = new BigInteger("123456789012345678901234567890");
BigInteger b = BigInteger.valueOf(987654321L);
System.out.println(a.add(b)); // сложение
System.out.println(a.subtract(b)); // вычитание
System.out.println(a.multiply(b)); // умножение
System.out.println(a.divide(b)); // деление
System.out.println(a.mod(b)); // остаток
System.out.println(a.pow(2)); // возведение в степень
System.out.println(a.gcd(b)); // НОД
// Факториал 100:
BigInteger fact = BigInteger.ONE;
for (int i = 2; i <= 100; i++)
fact = fact.multiply(BigInteger.valueOf(i));
System.out.println(fact);
```
`BigInteger` **иммутабелен** — операции возвращают новый объект, а не меняют исходный.
### 8.3 `Math` — математические функции
Работает с `double`, но есть методы и для целых:
```java
System.out.println(Math.abs(-7)); // 7
System.out.println(Math.max(3, 8)); // 8
System.out.println(Math.min(3, 8)); // 3
// Math.pow / Math.sqrt возвращают double — для форматирования используем String.format:
System.out.println(String.format("%.1f", Math.pow(2, 10))); // 1024.0
System.out.println(String.format("%.1f", Math.sqrt(144))); // 12.0
```
### 8.4 `Random` — генерация случайных чисел
```java
import java.util.Random;
Random rnd = new Random();
int r1 = rnd.nextInt(); // любое int
int r2 = rnd.nextInt(100); // [0, 100)
int r3 = rnd.nextInt(50) + 1; // [1, 50]
System.out.println(r2);
System.out.println(r3);
// Начиная с Java 17 — RandomGenerator:
// int r = java.util.random.RandomGenerator.getDefault().nextInt(1, 101);
```
---
## 9. Мини-пример: сумма цифр числа
```java
import java.util.Scanner;
public class SumDigits {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Введите целое число: ");
long n = Math.abs(sc.nextLong());
int sum = 0;
while (n > 0) {
sum += (int)(n % 10); // последняя цифра
n /= 10; // отбрасываем её
}
System.out.println(sum);
}
}
```
Здесь задействованы: `long`, `%` и `/`, приведение типов, ввод/вывод, `Math.abs`.
---
## 10. Типичные ошибки
| Ошибка | Как избежать |
|--------|--------------|
| Деление нацело вместо дробного | Привести один операнд: `(double) a / b` |
| Переполнение `int` | Использовать `long` или `Math.addExact` (бросает исключение) |
| Сравнение обёрток через `==` | Использовать `.equals()` |
| Забыть `L` у большого литерала | `long x = 3000000000L;` |
| `NullPointerException` при распаковке | Проверять на `null` перед присваиванием в примитив |
| Потеря точности при `(int) longValue` | Проверять диапазон или использовать `Math.toIntExact` |
```java
// Безопасные операции (Java 8+):
int sum = Math.addExact(1_000_000_000, 1_000_000_000); // ArithmeticException
int prod = Math.multiplyExact(100_000, 100_000); // исключение
```
---
## 11. Итоги
- В Java 4 примитивных целочисленных типа; основной — `int`, для больших значений — `long`.
- По умолчанию целые литералы — `int`, для `long` нужен суффикс `L`.
- Деление целых **отбрасывает** дробную часть, остаток даёт `%`.
- Для чисел > 9.2·10¹⁸ используйте `BigInteger`.
- Для коллекций и `null` — классы-обёртки (`Integer`, `Long`, ...).
- Всегда проверяйте возможность **переполнения** и корректность приведения типов.