Лекция 3
определение
Отличие от c++
Объявление, создание и инициализация массивов 
Объявление, создание и инициализация массивов 
Объявление, создание и инициализация массивов 
Объявление, создание и инициализация массивов 
Объявление, создание и инициализация массивов 
Устройство массива в памяти JVM
Устройство массива в памяти JVM
Как массив распределяется в памяти
Как достаем данные из памяти
Escape-анализ и скаляризация
Вопросы для закрепления
Копирование массивов 
Остальные методы копирования
Как создать уникальный метод копирования
Класс Arrays — методы работы с массивами
Класс Arrays — методы работы с массивами
Многомерные массивы
Инициализация многомерного массива
Подводный камень многомерных массивов
Транспонирование
 Ковариантность, generics и varargs
 Ковариантность, параметризированный тип и varargs
 Практикум
Работа с датой и временем
Основные классы библиотеки
Instant 
LocalDate, LocalTime, LocalDateTime
LocalDate
LocalDate
LocalTime 
LocalDateTime
ZonedDateTime
Переход между часовыми поясами
OffsetDateTime и OffsetTime
Duration
Period 
практика
99.63K

лекция 3 библиотеки даты и времени, Массивы

1. Лекция 3

Массивы + работа с датой и временем

2. определение

Массив — это структура данных,
хранящая фиксированное количество
элементов одного типа, расположенных в
памяти непрерывно, с доступом по целому
индексу от нуля.
Главное преимущество — доступ за O(1).
Адрес элемента вычисляется по формуле:
• Начало данных + индекс × размер элемента

3. Отличие от c++

в C массив — это указатель на первый элемент, и
арифметика указателей позволяет выйти за границы.
В Java массив — полноценный объект в куче:
• Переменная хранит ссылку, а не сами данные.
• У массива есть заголовок с длиной.
• При каждом доступе JVM проверяет границы.
безопасность в обмен на свободу. Запомните это —
дальше всё будет строиться на этом.

4. Объявление, создание и инициализация массивов 

Объявление, создание и
инициализация массивов
Объявление имеет два способа реализации:
• int[] numbers;
• int numbers[]; ( устаревший вариант который
не стоит использовать в своем коде, но можно
увидеть в учебниках)
Объявление не создаёт массив. Переменная
инициализируется null. Обращение к элементам
даст NullPointerException

5. Объявление, создание и инициализация массивов 

Объявление, создание и
инициализация массивов
Массив создаётся оператором new:
numbers = new int[5];
JVM выделяет в куче непрерывный блок,
записывает длину в заголовок,
инициализирует элементы значениями по
умолчанию, возвращает ссылку.

6. Объявление, создание и инициализация массивов 

Объявление, создание и
инициализация массивов
Уже созданные ранее массивы можно
первый раз инициализировать константными
значениям не прибегая повторно к
использованию ключевого слова new
int[] primes = {2, 3, 5, 7, 11};
String[] names = {"Анна", "Борис", "Виктор"};

7. Объявление, создание и инициализация массивов 

Объявление, создание и
инициализация массивов
Также инициализировать массив
константыми элементами можно уже в
момент его создания, в таком случае нам не
требуется задавать заголовок размера в
ручную
Int [] primes = new int[]{2, 3, 5, 7, 11};

8. Объявление, создание и инициализация массивов 

Объявление, создание и
инициализация массивов
Если мы хотим инициализировать элемент
массива или переписать его значение уже
после создания в дальнейшем коде, нам
необходимо обратиться к нему по индексу
нужного нам элемента
arr[0] = 99;

9. Устройство массива в памяти JVM

Заголовок объекта
1. Слово разметки - 4 байта на 32-битной JVM, 8
байт на 64-битной. Содержит хэш-код, возраст в
поколениях GC, флаг блокировки, указатель на монитор.
2. Указатель на метаданные класса в metaspace - 4 байта
со сжатыми ссылками или 8 байт без них. Сжатые ссылки
включены по умолчанию, если куча меньше 32 ГБ.
3. Заголовок длины массива - 4 байта, Максимальный
размер ограничен Integer.MAX_VALUE (2³¹−1).

10. Устройство массива в памяти JVM

Размер любого объекта кратен 8 байтам.
Если после данных остаётся «хвост», JVM
добавляет padding — неиспользуемые байты
в конце.
byte[10] – занимает 10 байт данных, 10 не
кратно 8, система добавляет 6 байт хвоста

11. Как массив распределяется в памяти

В стеке - 4 байта под ссылку.
В куче - 40 байт (16 заголовок + 20 данные + 4
padding).
Ссылка в стеке указывает на начало объекта.

12. Как достаем данные из памяти

Процессор читает память кэш-линиями —
обычно 64 байта. Одна линия вмещает
16 int или 8 long. При чтении arr[0] в кэш
загружается вся линия — arr[0]…arr[15].
Следующие 15 итераций попадают в быстрый
кэш L1, а не в медленную оперативную
память.

13. Escape-анализ и скаляризация

компилятор HotSpot умеет делать escape-анализ, он проверяет,
что если массив создаётся внутри метода, не возвращается наружу
и не сохраняется в поле, компилятор может скаляризовать его —
заменить на отдельные переменные в регистрах без выделения
памяти в куче.
int sum(int a, int b) {
int[] temp = {a, b};
return temp[0] + temp[1];
}
JIT компилятор может полностью устранить массив. Но это
работает только для простых локальных случаев.

14. Вопросы для закрепления

Вопрос 1: сколько байт занимает double[100]?
(1 дабл = 8 байт)
Вопрос 2: почему int[0] занимает 16 байт?
Вопрос 3: когда массив может не попасть в
кучу?

15. Копирование массивов 

Копирование массивов
Присваивание int[] b = a; копирует ссылку, а не
массив. Изменение через b видно через a
Если мы хотим создать действительно копию
массива без вреда для оригинального то самый
быстрый способ будет:
int[] source = {1, 2, 3, 4, 5};
int[] dest = new int[5];
System.arraycopy(source, 0, dest, 0, source.length);

16. Остальные методы копирования

int[] copy = original.clone(); (поверхностная
копия, в случае строк скопирует лишь ссылки)
Если нам нужно скопировать не весь массив а
только определенный диапазон то
применяют методы:
int[] extended = Arrays.copyOf(original, 10);
int[] range = Arrays.copyOfRange(original, 1, 4);

17. Как создать уникальный метод копирования

for (int i = 0; i < original.length; i++) {
if (ваше нужное условие)
deepCopy[i] = original[i].clone();
}

18. Класс Arrays — методы работы с массивами

Класс Arrays — методы работы с
массивами
Arrays.toString() / deepToString() – представление значений массива в виде строки
Arrays.sort() – сортировка массива, можно отсортировать только конкретый диапазон
указав его
Arrays.parallelSort() – также сортировка, но уже гораздо быстрее без возможности указать
диапазон
Arrays.binarySearch() – ищет индекс определенного значения, но только в
отсортированном массиве
Arrays.equals() / deepEquals() – проверка равенства элементов массива с чем либо
Arrays.fill() – заполняет массив или указанный диапазон массива определенным
значением

19. Класс Arrays — методы работы с массивами

Класс Arrays — методы работы с
массивами
Arrays.stream() — поток для функциональной обработки всего массива.
Например : int sum = Arrays.stream(new int[]{1, 2, 3}).sum();
Arrays.setAll() – заполняет массив значениями полученными из функции что в
него передали, например Arrays.setAll(squares, i -> i * i); вернет массив [0, 1, 4, 9,
16]
Arrays.compare() – возвращает логическое да или логическое нет о равенстве 2
массивов
Arrays.hashCode() – генерация хэш значения для массива на основе его адреса

20. Многомерные массивы

В Java нет настоящих многомерных
массивов. int[][] — это массив ссылок на int[].
int[][] matrix = new int[3][4];
первое число отвечает за строки, второе за
столбцы

21. Инициализация многомерного массива

int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
Для обхода таких массивов, необходим
вложенный цикл

22. Подводный камень многомерных массивов

каждый подмассив — отдельный объект, они
могут быть не рядом в куче. Что может
отрицательно влиять на производительности
работы с ним, но упрощать основное
ограничение массивов в лице зависимости от
соседства ячеек памяти

23. Транспонирование

int[][] transpose(int[][] m) {
int rows = m.length, cols = m[0].length;
int[][] result = new int[cols][rows];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
result[j][i] = m[i][j];
return result;
}

24.  Ковариантность, generics и varargs

Ковариантность, generics и varargs
В Java массивы ковариантны, это значит что
если S — подтип T, то S[] — подтип T[]. Но при
этом параметризированные типы данных
инвариативны, в связи с чем если изначально
тип данных массива не был указан конкретно,
ковариативность невозможна

25.  Ковариантность, параметризированный тип и varargs

Ковариантность,
параметризированный тип и varargs
В Java массивы ковариантны, это значит что если S —
подтип T, то S[] — подтип T[].
Но при этом параметризированные типы данных
инвариативны, в связи с чем если изначально тип данных
массива не был указан конкретно, ковариативность
невозможна
Varargs (T... args) в Java технически реализованы как
массив. То есть сигнатура:
void foo(String... args)
равна
void foo(String[] args)

26.  Практикум

Практикум
Задание: написать программу, которая
запрашивает размер массива, заполняет его
числами с клавиатуры, выводит
через Arrays.toString, сортирует, находит
сумму элементов и максимальный элемент

27. Работа с датой и временем

В старых версиях джавы использовалась
библиотека java.util.Date с ним можно
ознакомиться для общего развития но в коде
он более не применяется
Актуальной библиотекой для работы сейчас
является java.time

28. Основные классы библиотеки

Instant - на шкале времени (UTC), точность до наносекунд
LocalDate - Дата без времени и зоны (год-месяц-день)
LocalTime - Время без даты и зоны (часы-минуты-секунды-наносекунды)
LocalDateTime - Дата и время без зоны
ZonedDateTime -Дата и время с часовым поясом
OffsetDateTime - Дата и время со смещением от UTC
OffsetTime - Время со смещением
ZoneId - Идентификатор часового пояса
ZoneOffset - Смещение от UTC
Duration
- Промежуток времени в секундах/наносекундах
Period - Промежуток в годах/месяцах/днях
DateTimeFormatter - Форматирование и парсинг
Clock - Источник текущего времени (удобно для тестов)

29. Instant 

Instant
Instant — это точка на временной шкале, всегда в UTC.
Instant хранит два числа: количество секунд с эпохи Unix и
количество наносекунд внутри текущей секунды. Это
позволяет представлять время с точностью до наносекунд
— миллиардной доли секунды.
Instant now = Instant.now();
Этот объект не знает ни о годах, ни о месяцах, ни о
часовых поясах. Он просто говорит: «прошло вот столько
секунд и наносекунд с 1 января 1970 года».

30. LocalDate, LocalTime, LocalDateTime

LocalDate, LocalTime, LocalDateTime
Эти три класса представляют время так, как
его видит человек, — но без привязки к
часовому поясу.
LocalDate — только дата
• LocalDate today = LocalDate.now();
• LocalDate birthday = LocalDate.of(1995, 7,
12);
• LocalDate parsed = LocalDate.parse("2024-0315");

31. LocalDate

LocalDate date = LocalDate.of(2024, 3, 15);
int year = date.getYear();
// 2024
int month = date.getMonthValue(); // 3
Month monthEnum = date.getMonth(); // MARCH
int day = date.getDayOfMonth(); // 15
DayOfWeek dow = date.getDayOfWeek(); // FRIDAY
int dayOfYear = date.getDayOfYear(); // 75 (15 марта — 75-й
день года)
boolean leap = date.isLeapYear();
int daysInMonth = date.lengthOfMonth();

32. LocalDate

LocalDate today = LocalDate.of(2024, 3, 15);
• LocalDate tomorrow = today.plusDays(1);
• LocalDate nextMonth = today.plusMonths(1);
• LocalDate lastYear = today.minusYears(1);
• today.isBefore(tomorrow );
• today.isAfter(tomorrow );
• today.isEqual(tomorrow );

33. LocalTime 

LocalTime
Внутри LocalTime хранит часы, минуты, секунды и наносекунды.
LocalTime time = LocalTime.of(14, 30, 45);
int hour = time.getHour(); // 14
int minute = time.getMinute(); // 30
int second = time.getSecond(); // 45
int nano = time.getNano(); // 0
LocalTime plusHour = time.plusHours(1); // 15:30:45
LocalTime minusMin = time.minusMinutes(15); // 14:15:45
truncatedTo(ChronoUnit.SECONDS) — отбрасывает всё, что меньше указанной
единицы:

34. LocalDateTime

Это комбинация LocalDate и LocalTime. Хранит
год, месяц, день, часы, минуты, секунды,
наносекунды. Но без часового пояса.
Методы все такие же как у дочерних классов
рассмотренных ранее

35. ZonedDateTime

Это LocalDateTime плюс часовой пояс. Он знает, что «15
марта 2024, 14:30» произошло именно в Москве, а не в
Нью-Йорке. Это делает его полноценным представлением
момента времени, эквивалентным Instant, но с
календарной информацией.
Часовой пояс в Java представлен классом ZoneId.
Идентификаторы зон — это строки
вида Europe/Moscow, America/New_York, Asia/Tokyo
ZoneId moscow = ZoneId.of("Europe/Moscow");
ZonedDateTime now = ZonedDateTime.now(moscow);

36. Переход между часовыми поясами

ZonedDateTime moscow =
ZonedDateTime.now(ZoneId.of("Europe/Moscow"))
;
ZonedDateTime tokyo =
moscow.withZoneSameInstant(ZoneId.of("Asia/Tok
yo"));
Метод withZoneSameInstant сохраняет момент и
меняет зону. Если в Москве 12:00, то в Токио
будет 18:00 — тот же момент, разные часы.

37. OffsetDateTime и OffsetTime

OffsetDateTime и OffsetTime
Иногда у вас нет полной информации о зоне — только
смещение от UTC. Например, сервер прислал
время 2024-03-15T14:30:00+03:00. Вы не знаете,
Москва это или Стамбул — обе зоны имеют +03:00.
Для таких случаев есть OffsetDateTime.
OffsetDateTime odt = OffsetDateTime.now();
OffsetDateTime parsed = OffsetDateTime.parse("202403-15T14:30:00+03:00");
ZoneOffset offset = odt.getOffset(); // +03:00

38. Duration

Duration представляет точное количество
времени — секунды и наносекунды. Он не знает
о календаре. Подходит для измерения «сколько
прошло времени между двумя моментами».
Instant start = Instant.now(); // ... какая-то
работа ...
Instant end = Instant.now();
Duration duration = Duration.between(start, end);

39. Period 

Period
Все точно также как и duration но разницу
измеряет уже не в секундах а днях и месяцах
LocalDate birth = LocalDate.of(1990, 5, 20);
LocalDate today = LocalDate.now();
Period age = Period.between(birth, today);
System.out.println(age.getYears() + " лет, "
+ age.getMonths() + " месяцев, "
+ age.getDays() + " дней");

40. практика

Сколько дней до Нового года?
LocalDate today = LocalDate.now();
LocalDate newYear = LocalDate.of(today.getYear() +
1, 1, 1);
long days = ChronoUnit.DAYS.between(today,
newYear);
System.out.println("До Нового года: " + days + "
дней");
English     Русский Правила