Java for Beginner
673 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
5.2. Сравнение ссылок и содержимого

Оператор == сравнивает адреса в памяти, то есть проверяет, совпадают ли ссылки.
Метод equals() (если переопределён) сравнивает логическое содержание объектов.


String a = new String("hello");
String b = new String("hello");

System.out.println(a == b); // false (разные объекты)
System.out.println(a.equals(b)); // true (одинаковое содержимое)
Неверное использование == вместо equals() приводит к тому, что два «логически одинаковых» объекта будут считаться разными.


5.3. Изменяемые (mutable) и неизменяемые (immutable) объекты

Изменяемые объекты (например, ArrayList, StringBuilder) позволяют изменять своё внутреннее состояние после создания. Если несколько ссылок указывают на один и тот же экземпляр, то изменение через одну ссылку будет видно через все остальные.
Неизменяемые объекты (например, String, Integer, LocalDate) после создания не меняются; операции, которые «меняют» их, на самом деле возвращают новый экземпляр.

Непонимание этого может привести к неожиданным результатам:

List<String> list = new ArrayList<>();
list.add("A");
List<String> another = list;
another.clear(); // очищает список для обеих ссылок
System.out.println(list); // []


5.4. Утечки памяти

В Java утечки памяти возникают не из-за отсутствия явного удаления объектов (как в C++), а из-за того, что на объекты остаются неожиданно живые ссылки, и GC не может их убрать:
Хранение объектов в static-полях и неочищаемых коллекциях.
Неправильная работа с кешами или пулом объектов, где ссылки не удаляются вовремя.
Анонимные внутренние классы или лямбда-выражения, сохраняющиеся после использования.


Пример простой утечки:
public class Cache {
private static final Map<String, Object> CACHE = new HashMap<>();

public static void put(String key, Object value) {
CACHE.put(key, value);
}

// Если не реализовать метод удаления из CACHE, то объекты будут храниться в памяти постоянно
}


5.5. Производительность и частые аллокации

Частое создание небольших временных объектов может привести к частым запускам GC и общему снижению производительности.
Конкатенация строк в цикле через оператор + создаёт новые объекты String на каждом шаге.


Лучше использовать StringBuilder:
// Плохо:
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // каждый раз создаётся новый String
}

// Лучше:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
String result = sb.toString();


5.6. Пограничные случаи при копировании — глубокое vs поверхностное копирование

Поверхностное копирование (shallow copy) копирует только поля-примитивы и ссылки; вложенные объекты не дублируются, а «разделяются» между двумя экземплярами.
Глубокое копирование (deep copy) предполагает создание новых экземпляров для всех вложенных объектов, чтобы изменения в одном объекте не затрагивали другой.


class Address {
String street;
}

class Person implements Cloneable {
String name;
Address address;

@Override
protected Person clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone(); // поверхностное копирование
cloned.address = new Address(); // нужно вручную создать новый адрес
cloned.address.street = this.address.street;
return cloned;
}
}
Если не учитывать глубокое копирование, можно случайно разделить внутреннее состояние между двумя объектами, что приведёт к трудноотлавливаемым ошибкам.


5.7. Потокобезопасность (thread-safety)

Когда объекты доступны из нескольких потоков, нужно грамотно синхронизировать доступ к их полям и методам:
Использовать synchronized, ReentrantLock, атомарные типы (AtomicInteger, AtomicReference).
Предпочитать неизменяемые объекты, так как они автоматически безопасны для чтения из разных потоков.
Избегать состояния, зависимого от порядка выполнения, или пользоваться высокоуровневыми абстракциями из java.util.concurrent.


#Java #для_новичков #beginner #reference_types #Object
6. Дополнительные нюансы

6.1. Массивы как объекты

Хотя у массивов особый синтаксис, они всё же являются полноценными объектами:
Имеют поле length.
Могут быть null (если не инициализированы), поэтому доступ к элементам массива без проверки может привести к NullPointerException.
Создаются через new Type[size] или инициализируются через литералы { … }.


int[] nums = new int[5];
System.out.println(nums.length); // 5

String[] names = null;
System.out.println(names.length); // NullPointerException


6.2. Generics и ограничение на примитивы

В обобщённых (generic) классах и методах можно использовать только ссылочные типы. Примитивы (например, int, char) нельзя указать напрямую как параметр типа.
В качестве параметры обобщений применяются соответствующие классы-обёртки: Integer, Character, Double и т. д.


List<Integer> integers = new ArrayList<>();
integers.add(10); // автоупаковка: int → Integer


6.3. Наследование от Object

Все классы в Java неявно наследуются от java.lang.Object.
В классе Object определены методы: toString(), equals(), hashCode(), getClass(), clone(), finalize() и др.


При работе с любыми объектами полезно переопределять toString(), equals() и hashCode() в соответствии с логикой класса:

class Point {
int x, y;

@Override
public String toString() {
return "Point(" + x + ", " + y + ")";
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Point)) return false;
Point other = (Point) obj;
return x == other.x && y == other.y;
}

@Override
public int hashCode() {
return 31 * x + y;
}
}


6.4. Расположение в памяти

Объекты — в куче. При создании нового экземпляра сборщик мусора определяет, в какой части кучи разместить объект (young generation, old generation и т. д.).
Ссылочные переменные (локальные) — в стеке вызовов. Когда метод завершается, все локальные ссылки удаляются из стека.
Ссылки в полях — часть объекта в куче. Когда объект удаляется, удаляются и все его поля-ссылки.

Это знание помогает понимать, какие объекты могут быстро «умирать» (локальные объекты, ссылки на которые не передаются дальше) и какие могут «жить» дольше (объекты, ссылки на которые остаются в статических полях или в глобальном контексте).


#Java #для_новичков #beginner #reference_types #Object
Что выведет код?

public class Task090625 {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();

System.out.println(obj1 == obj2);
System.out.println(obj1.equals(obj2));
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
9%
true true
12%
true false
53%
false true
26%
false false
Please open Telegram to view this post
VIEW IN TELEGRAM
Что такое package в Java и зачем он нужен? 🤓

Ответ:

Пакет (package) — это пространство имен для организации классов и интерфейсов, предотвращающее конфликты имен.

Например, java.util содержит классы вроде ArrayList. Пакеты улучшают читаемость, модульность и контроль доступа. Для создания пакета используется package com.example;, а для импорта — import java.util.List;. Пакеты также влияют на видимость при использовании модификатора default.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Введение в Flyway

Flyway представляет собой специализированный инструмент управления миграциями баз данных, реализующий принцип "Database-as-Code". Его фундаментальная задача заключается в обеспечении контролируемого и воспроизводимого процесса эволюции схемы базы данных через систему версионированных изменений.

Ключевые функциональные аспекты:
Декларативное управление схемой - все изменения БД описываются в виде отдельных скриптов
Детерминированность применения - каждая миграция имеет строгую версионную привязку
Атомарность изменений - миграции применяются как единое целое (транзакционно)
Историчность - полный аудит всех выполненных изменений


Сравнение с Liquibase

Принципиальные различия между Flyway и Liquibase проявляются в нескольких аспектах:

Архитектурный подход
Flyway придерживается парадигмы "SQL-первым", где основным носителем изменений являются нативные SQL-скрипты. Liquibase предлагает абстрактный DSL (XML/YAML/JSON) для описания изменений, который затем транслируется в SQL.

Механизм откатов
В Flyway стратегия откатов реализована через создание новых миграционных скриптов с обратными изменениями. Liquibase предоставляет встроенный механизм описания операций отката непосредственно в changeSet.

Сложность и гибкость
Flyway демонстрирует минималистичный подход с низким порогом вхождения. Liquibase предлагает более богатый функционал за счет усложненной модели конфигурации.

Интеграционные возможности
Оба инструмента имеют глубокую интеграцию с экосистемой Java, но Flyway чаще выбирают для Spring Boot-проектов благодаря более простой автоконфигурации.


Базовые концепции

Модель миграций

Flyway оперирует двумя фундаментальными типами миграций:


Версионные миграции (префикс V)
Линейно упорядоченные изменения схемы
Неизменяемые после применения


Пример именования: V2__Add_email_column.sql

Содержимое SQL-скрипта:

ALTER TABLE users ADD COLUMN email VARCHAR(255);


Повторяемые миграции (префикс R)
Перезаписываемые скрипты
Применяются при изменении контрольной суммы


Пример: R__Update_report_views.sql


Механизм контроля версий

Система использует служебную таблицу flyway_schema_history, содержащую:
Точную версию каждой примененной миграции
Контрольную сумму скрипта
Временные метки выполнения
Статус операции


Жизненный цикл изменений

Типичный workflow включает:
Инициализацию схемы (baseline)
Валидацию существующих миграций
Применение новых изменений (migrate)
При необходимости - очистку (clean) и повторное развертывание



Поддерживаемые системы управления базами данных

Flyway обеспечивает совместимость с большинством современных реляционных СУБД:
PostgreSQL (полная поддержка, включая расширения)
MySQL/MariaDB (включая специфичные движки хранения)
Oracle (с учетом особенностей PL/SQL)
SQL Server (включая Azure SQL)
Встраиваемые БД (H2, SQLite)
Для NoSQL-систем (MongoDB) требуется использование коммерческой версии Flyway. Важно отметить, что некоторые специфические функции СУБД могут требовать особого подхода при миграциях.



Типовые сценарии использования

Разработка - синхронизация схемы между средами
Тестирование - подготовка изолированных тестовых БД
Развертывание - автоматизация деплоя в production
Анализ - отслеживание истории изменений схемы


#Java #middle #Flyway
Что выведет код?

import java.util.stream.IntStream;

public class Task100625 {
public static void main(String[] args) {
int sum = IntStream.range(1, 5)
.peek(System.out::print)
.filter(i -> i % 2 == 0)
.sum();

System.out.println(" sum=" + sum);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
17%
24 sum=6
13%
24 sum=12
58%
1234 sum=6
13%
2468 sum=6
Продолжаем выбирать темы для разбора и голосовать за рассмотрение предложенных! 🤓

Голосуем за тему к рассмотрению в эти выходные!

Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)

Не стесняемся! ✌️
Please open Telegram to view this post
VIEW IN TELEGRAM
Что такое конструктор в Java и может ли он быть приватным? 🤓

Ответ:

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

Пример:

class Person {
String name;
Person(String name) {
this.name = name; }
}

Приватный конструктор (private) используется для реализации паттернов, например, Singleton, чтобы запретить создание объектов извне:

class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return instance; }
}


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Ссылочные типы в Java — массивы

В Java массивы представляют собой ссылочные типы данных, которые позволяют хранить фиксированное количество элементов одного типа. В отличие от примитивных типов, массивы создаются в куче и управляются через ссылки. Понимание того, как работают массивы как объекты в Java, критически важно для эффективного управления памятью, избежания ошибок и написания производительного кода.

Создание массивов

Массивы в Java создаются с помощью ключевого слова new, аналогично другим объектам. При этом в куче выделяется непрерывный блок памяти под элементы массива.


Например:
int[] numbers = new int[5];


Здесь переменная numbers — это ссылка на объект массива, содержащего 5 элементов типа int. Все элементы автоматически инициализируются значениями по умолчанию — нулями для чисел, false для логических значений, null для ссылок.

Можно также создать и инициализировать массив сразу:
String[] names = {"Alice", "Bob", "Charlie"};


Ключевые моменты:
Массив — это объект, даже если он содержит примитивные типы.
У массива всегда есть поле length, определяющее количество элементов.
После создания размер массива изменить нельзя. Для динамических структур используются коллекции, такие как ArrayList.


Существование и удаление массивов

Как и другие объекты в Java, массивы существуют в памяти до тех пор, пока на них имеются ссылки.

Когда все ссылки теряются, массив становится кандидатом на сборку мусора:
int[] data = new int[100];
data = null; // массив станет доступен для удаления


Если массив используется в нескольких местах через копирование ссылок, он не будет удалён, пока хотя бы одна ссылка остаётся активной. Это особенно важно при передаче массивов в методы, возврате из методов и хранении их в структурах данных.

Использование массивов

Массивы позволяют обращаться к элементам по индексу, начиная с нуля:
numbers[0] = 10;
System.out.println(numbers[0]); // выводит 10


При передаче массива в метод метод получает копию ссылки, а не сам массив.

Это означает, что любые изменения внутри метода влияют на оригинальный массив:
void fill(int[] arr) {
arr[0] = 42;
}
После вызова fill(numbers) значение numbers[0] станет 42.


Также массивы могут быть многомерными, например, двумерный массив int[][] представляет собой массив массивов.

#Java #для_новичков #beginner #reference_types #Arrays
Трудности и подводные камни

Работа с массивами может сопровождаться рядом типичных ошибок:

1. ArrayIndexOutOfBoundsException

Ошибка возникает при попытке обратиться к несуществующему индексу:
int[] a = new int[3];
a[3] = 5; // ошибка: допустимые индексы — 0, 1, 2


2. NullPointerException


Если массив равен null, любая попытка доступа к его элементам вызывает исключение:
int[] a = null;
System.out.println(a.length); // ошибка


3. Фиксированный размер

После создания размер массива не может быть изменён. Чтобы добавить или удалить элементы, необходимо создать новый массив или использовать коллекции.


4. Поверхностное копирование

При копировании массива переменная будет указывать на тот же объект, если используется простое присваивание:
int[] a = {1, 2, 3};
int[] b = a;
b[0] = 99;
System.out.println(a[0]); // выведет 99


Для создания копии используется метод Arrays.copyOf или ручное копирование по элементам.

5. Сравнение массивов

Сравнение массивов через == проверяет ссылки, а не содержимое.

Для сравнения содержимого следует использовать Arrays.equals():
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println(a == b); // false
System.out.println(Arrays.equals(a, b)); // true


6. Утечки памяти

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

7. Потокобезопасность

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

Дополнительные нюансы

Массивы как объекты:
Даже массив примитивных типов — это объект, доступный через ссылку, с полем length.

Обобщения:
Нельзя создавать массивы параметризованных типов, например new List<String>[10], из-за ограничений системы типов Java. Для таких целей используют коллекции.

Массивы и методы класса Object:

Как и другие объекты, массивы наследуют методы класса Object, например toString() и hashCode(), но стандартная реализация toString() для массивов возвращает строку вида [I@1b6d3586. Для корректного вывода содержимого массива используйте Arrays.toString() или Arrays.deepToString().

Массивы и производительность:
Работа с массивами быстрее, чем с коллекциями, за счёт простоты реализации и отсутствия лишнего обёртывания. Однако отсутствие гибкости может потребовать дополнительного кода.

#Java #для_новичков #beginner #reference_types #Arrays
Варианты ответа:2.5
Anonymous Quiz
50%
2.5
36%
2.0
14%
2
0%
Ошибка компиляции
Что выведет код?

public class Task110625 {
public static void main(String[] args) {
int a = 5;
int b = 2;

double result = a / b;
System.out.println(result);
}
}


#Tasks
Что такое композиция и агрегация в ООП? 🤓

Ответ:

Композиция и агрегация — это отношения "часть-целое":

Композиция: объект-часть не существует без целого (например, двигатель в машине). Если машина уничтожается, двигатель тоже.

Агрегация: объект-часть может существовать отдельно (например, студент в университете).

Пример композиции:
class Car {
Engine engine = new Engine(); // Композиция
}

Пример агрегации:
class University {
List<Student> students; // Агрегация
}


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM