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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Внутреннее устройство оператора try-catch и примеры применения

Внутреннее устройство try-catch
Когда в коде происходит исключение, виртуальная машина Java (JVM) начинает искать подходящий блок catch для обработки этого исключения. Процесс поиска начинается с текущего метода и продолжается вверх по стеку вызовов методов, пока не будет найден блок, способный обработать данное исключение. Если соответствующий блок не найден, программа завершает работу с ошибкой.

Алгоритм работы:

Код в блоке try выполняется до тех пор, пока не возникнет исключение.
Если в блоке try возникает исключение, дальнейший код внутри него не выполняется, и JVM ищет блок catch, соответствующий типу исключения.
Как только найден подходящий блок catch, выполняется его код.
Если исключение не обработано в блоке catch, оно передаётся вверх по стеку вызовов, пока не будет найден обработчик.
Если обработчик исключений не найден, программа завершается.


public class Main {
public static void main(String[] args) {
try {
int result = divide(10, 0);
System.out.println("Результат: " + result);
} catch (ArithmeticException e) {
System.out.println("Ошибка: Деление на ноль!");
}
}

public static int divide(int a, int b) {
return a / b;
}
}
В данном примере исключение ArithmeticException возникает в методе divide, но обработка происходит в методе main, потому что блок catch для этого исключения находится именно там.


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


Как только возникает исключение, оно передаётся (или пробрасывается) вверх по стеку вызовов, пока не найдётся блок catch, который может его обработать. Этот механизм называется propagation (распространение исключений).
public class Main {
public static void main(String[] args) {
try {
methodA();
} catch (ArithmeticException e) {
System.out.println("Ошибка: Деление на ноль!");
}
}

public static void methodA() {
methodB();
}

public static void methodB() {
int result = 10 / 0; // Исключение здесь
}
}
Исключение ArithmeticException возникло в методе methodB, но оно было перехвачено и обработано в методе main. Это демонстрирует механизм распространения исключений.


Оператор finally

Оператор finally используется в сочетании с try-catch и содержит код, который будет выполнен независимо от того, возникло исключение или нет. Этот блок часто используется для освобождения ресурсов, таких как закрытие файлов, соединений с базой данных и других внешних ресурсов.
public class Main {
public static void main(String[] args) {
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Ошибка: Деление на ноль!");
} finally {
System.out.println("Этот блок выполнится в любом случае.");
}
}
}

Результат выполнения:
Ошибка: Деление на ноль!
Этот блок выполнится в любом случае.


#Java #Training #Medium #Try_catch
Пример применения: работа с файлами
Рассмотрим пример, где блок finally используется для закрытия файла после его чтения:
import java.io.*;

public class Main {
public static void main(String[] args) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.out.println("Файл не найден.");
} catch (IOException e) {
System.out.println("Ошибка чтения файла.");
} finally {
try {
if (reader != null) {
reader.close();
System.out.println("Файл закрыт.");
}
} catch (IOException e) {
System.out.println("Ошибка при закрытии файла.");
}
}
}
}
Здесь, даже если возникает исключение при чтении файла, блок finally гарантирует, что файл будет закрыт. Это важно для освобождения системных ресурсов и предотвращения утечек.


Вложенные операторы try-catch
Иногда бывает нужно использовать несколько операторов try-catch внутри друг друга. Это может быть полезно, если разные части кода требуют разной обработки исключений:
public class Main {
public static void main(String[] args) {
try {
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Внутренний блок: Деление на ноль.");
}

String str = null;
System.out.println(str.length());
} catch (NullPointerException e) {
System.out.println("Внешний блок: NullPointerException.");
}
}
}
В этом примере два исключения обрабатываются в разных блоках try-catch. Первое исключение (деление на ноль) перехватывается внутренним блоком, а второе — внешним.


#Java #Training #Medium #Try_catch
Оператор multi-catch в Java

С появлением Java 7 была добавлена возможность использования multi-catch — когда несколько исключений могут быть обработаны в одном блоке catch. Это особенно удобно в случаях, когда одно и то же действие требуется выполнить для разных типов исключений.

До появления multi-catch разработчики вынуждены были писать отдельные блоки catch для каждого исключения, даже если логика обработки была одинаковой:
try {
// Код, который может вызвать несколько исключений
} catch (IOException e) {
// Обработка исключения
} catch (SQLException e) {
// Обработка исключения
}

Это выглядело громоздко, особенно если исключения требовали одинаковой обработки.

Как работает multi-catch?

Multi-catch позволяет обработать несколько исключений в одном блоке, разделяя их типы через вертикальную черту |. Таким образом, код становится компактнее и более читаемым:
try {
// Код, который может вызвать несколько исключений
} catch (IOException | SQLException e) {
// Общая обработка исключений
}


Пример применения multi-catch
Представим, что нам нужно обрабатывать два типа исключений: работу с файлами и работу с базой данных. Для обоих случаев нужно просто вывести сообщение об ошибке:
import java.io.*;
import java.sql.*;

public class Main {
public static void main(String[] args) {
try {
readFile("file.txt");
connectToDatabase();
} catch (IOException | SQLException e) {
System.out.println("Ошибка при работе с файлом или базой данных: " + e.getMessage());
}
}

public static void readFile(String fileName) throws IOException {
// Чтение из файла
throw new IOException("Ошибка чтения файла");
}

public static void connectToDatabase() throws SQLException {
// Подключение к базе данных
throw new SQLException("Ошибка подключения к базе данных");
}
}
Здесь блок catch перехватывает как IOException, так и SQLException, обрабатывая их одним сообщением. Если бы не было возможности использовать multi-catch, нам пришлось бы писать два отдельных блока catch, что увеличило бы количество строк кода.


Ограничения multi-catch


Есть некоторые правила и ограничения, которые необходимо учитывать при использовании multi-catch:
Нельзя использовать наследуемые типы вместе.
Это означает, что нельзя комбинировать в multi-catch исключения, которые находятся в иерархии друг над другом, например, Exception и IOException, так как IOException является подклассом Exception. В таких случаях JVM не сможет определить, какой именно блок обработки должен быть вызван.


Неверный пример:
try {
// Код
} catch (IOException | Exception e) {
// Ошибка компиляции
}


Вместо этого вы должны использовать только более общий тип, такой как Exception:
try {
// Код
} catch (Exception e) {
// Обработка всех исключений
}


Исключение нельзя повторно назначить.
В блоке multi-catch переменная исключения e автоматически объявляется как final. Это означает, что её нельзя переназначать внутри блока catch. Например, следующий код вызовет ошибку компиляции:
try {
// Код
} catch (IOException | SQLException e) {
e = new Exception(); // Ошибка: переменная e final
}
Это ограничение незначительно, так как в большинстве случаев переменная e используется только для чтения информации об исключении, например, вызова метода getMessage().


Multi-catch и полиморфизм

Использование multi-catch позволяет лучше реализовывать полиморфизм, обрабатывая несколько типов исключений через их общего предка, например, через базовый класс Exception. В некоторых случаях вместо multi-catch удобнее и правильнее просто обработать исключение общего типа, например, если всё равно нужно выполнить одинаковые действия.
try {
// Код, который может вызвать любое исключение
} catch (Exception e) {
System.out.println("Произошла ошибка: " + e.getMessage());
}
Здесь Exception охватывает любые исключения, унаследованные от этого класса. Это полезно, если не нужно точно обрабатывать специфические типы ошибок.


#Java #Training #Medium #Try_catch #Multi_catch
Пример сложного применения
Предположим, мы пишем приложение, которое одновременно работает с файлами и подключениями к интернету, и нам нужно корректно обрабатывать несколько исключений. Мы используем multi-catch для упрощения кода:
import java.io.*;
import java.net.*;

public class Main {
public static void main(String[] args) {
try {
readFile("file.txt");
connectToServer("http://example.com");
} catch (IOException | MalformedURLException e) {
System.out.println("Ошибка ввода-вывода или неверный URL: " + e.getMessage());
}
}

public static void readFile(String fileName) throws IOException {
// Чтение из файла
throw new IOException("Файл не найден");
}

public static void connectToServer(String url) throws MalformedURLException {
// Подключение к серверу
throw new MalformedURLException("Неверный URL");
}
}
Здесь мы можем одновременно обработать исключения, возникающие при работе с файлами и URL, поскольку они оба являются подклассами IOException. В результате мы сокращаем количество блоков catch и делаем код более читаемым.


#Java #Training #Medium #Try_catch #Multi_catch
Оператор try-with-resources

В Java управление ресурсами, такими как файлы, сетевые соединения и потоки данных, всегда было важным аспектом разработки. Когда вы работаете с такими ресурсами, важно правильно их закрывать после использования, чтобы избежать утечек памяти или блокировок системных ресурсов. Именно для этой цели был введён оператор try-with-resources в Java 7.

try-with-resources — это специальная форма оператора try, предназначенная для автоматического закрытия ресурсов, которые реализуют интерфейс AutoCloseable. Он гарантирует, что ресурсы будут закрыты в конце блока try, даже если в процессе выполнения кода возникло исключение.

До Java 7 разработчикам приходилось явно закрывать ресурсы в блоке finally, чтобы гарантировать их освобождение. Это приводило к громоздкому и подверженному ошибкам коду, особенно когда возникали исключения.

Основная цель try-with-resources — упростить работу с ресурсами, которые требуют явного закрытия (например, потоки ввода-вывода, базы данных, сетевые соединения). Применение этого оператора позволяет избежать необходимости написания блока finally и исключает риск того, что ресурс останется открытым в случае ошибки.

Пример работы с файлами до Java 7:
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
В этом примере ресурсы (файл) явно закрываются в блоке finally, что добавляет сложности и может привести к ошибкам, если закрытие файла не будет выполнено правильно.


Начиная с Java 7, try-with-resources позволяет избежать явного закрытия ресурсов, упрощая код и делая его более безопасным. Рассмотрим, как тот же код выглядит с использованием нового оператора:
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
Теперь ресурс (BufferedReader) автоматически закрывается, как только выполнение блока try завершено. Если возникает исключение, ресурс всё равно будет закрыт.


Преимущества try-with-resources

Автоматическое управление ресурсами. Ресурсы, открытые в блоке try-with-resources, автоматически закрываются по завершении блока.
Меньше кода. Вам больше не нужно вручную закрывать ресурсы в блоке finally.
Безопасность. Исключения или ошибки в процессе работы с ресурсами не приведут к утечке, так как ресурсы всё равно будут закрыты.
Поддержка нескольких ресурсов. Вы можете работать с несколькими ресурсами одновременно, и все они будут закрыты корректно.


Основное требование для использования ресурса в конструкции try-with-resources — он должен реализовывать интерфейс AutoCloseable (или его предшественник Closeable, который является подинтерфейсом). Большинство стандартных классов Java, таких как потоки ввода-вывода, соединения с базами данных и прочие, уже реализуют эти интерфейсы.

Интерфейс AutoCloseable:
public interface AutoCloseable {
void close() throws Exception;
}
Когда вы используете класс, реализующий этот интерфейс в try-with-resources, JVM автоматически вызывает метод close() после завершения блока try.


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

Если при закрытии ресурса возникает ошибка, это исключение также обрабатывается и может быть подавлено, если в блоке try уже возникло другое исключение.

#Java #Training #Medium #Try_with_resources
Что выведет код?

public class Task200924 {
public static void main(String[] args) {
try (MyResource resource = new MyResource()) {
resource.doSomething();
} catch (Exception e) {
System.out.println("Exception caught");
} finally {
System.out.println("Finally block executed");
}
}
}

class MyResource implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("Resource closed");
}

public void doSomething() throws Exception {
System.out.println("Doing something");
throw new Exception("Error occurred");
}
}


#Tasks
Грустненько как-то😞🤪

https://t.me/Java_for_beginner_dev

#Mems
Внутреннее устройство try-with-resources

Основной принцип работы try-with-resources заключается в том, что все ресурсы, объявленные в круглых скобках после оператора try, автоматически закрываются по завершении блока. Важная деталь состоит в том, что каждый ресурс должен реализовывать интерфейс AutoCloseable, который гарантирует наличие метода close(). Этот метод вызывается JVM в конце выполнения блока try.

Когда в try-with-resources используется несколько ресурсов, их закрытие происходит в обратном порядке их открытия. То есть если ресурсы объявлены следующим образом:
try (
Resource1 res1 = new Resource1();
Resource2 res2 = new Resource2();
) {
// Работа с ресурсами
}
То сначала будет закрыт res2, а затем — res1. Это важно учитывать при работе с взаимосвязанными ресурсами, например, когда один из них зависит от другого.


Обработка исключений при закрытии ресурсов

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

Подавление исключений
Если в блоке try возникает исключение, а затем в процессе закрытия ресурса возникает ещё одно исключение, Java подавляет второе исключение, чтобы не потерять основное, и предоставляет возможность получить доступ к подавленному исключению с помощью метода getSuppressed().
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
for (Throwable suppressed : e.getSuppressed()) {
System.out.println("Подавленное исключение: " + suppressed);
}
e.printStackTrace();
}
В этом примере, если при чтении файла возникнет исключение, а затем при закрытии ресурса также возникнет ошибка, основное исключение будет сохранено, а исключение, возникшее при закрытии, станет подавленным и может быть получено через getSuppressed().


Реализация собственного ресурса для использования с try-with-resources

Вы можете создать собственный класс, который будет использоваться в конструкции try-with-resources. Для этого нужно реализовать интерфейс AutoCloseable и переопределить метод close().
public class CustomResource implements AutoCloseable {
private String resourceName;

public CustomResource(String resourceName) {
this.resourceName = resourceName;
System.out.println(resourceName + " открыт.");
}

@Override
public void close() throws Exception {
System.out.println(resourceName + " закрыт.");
}
}

public class Main {
public static void main(String[] args) {
try (CustomResource res = new CustomResource("Ресурс 1")) {
System.out.println("Работа с ресурсом.");
} catch (Exception e) {
e.printStackTrace();
}
}
}


Вывод программы:
Ресурс 1 открыт.
Работа с ресурсом.
Ресурс 1 закрыт.
Здесь объект CustomResource автоматически закрывается по завершении блока try, как только завершилась работа с ним.


Применение try-with-resources в реальных проектах

try-with-resources широко используется в реальных проектах, особенно при работе с файловыми потоками, базами данных и сетевыми соединениями.

Работа с базами данных. При работе с JDBC важно закрывать соединения, запросы и результаты запросов.
try (
Connection conn = DriverManager.getConnection("jdbc:example_url", "user", "password");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM table")
) {
while (rs.next()) {
System.out.println(rs.getString("column"));
}
} catch (SQLException e) {
e.printStackTrace();
}
Здесь все ресурсы — Connection, Statement и ResultSet — будут закрыты автоматически.


#Java #Training #Medium #Try_with_resources
Работа с сокетами. В сетевом программировании важно корректно закрывать сокеты и потоки.
try (
Socket socket = new Socket("localhost", 8080);
InputStream input = socket.getInputStream();
OutputStream output = socket.getOutputStream()
) {
// Чтение и запись данных
} catch (IOException e) {
e.printStackTrace();
}


Работа с файловыми потоками.
try (
FileInputStream fis = new FileInputStream("source.txt");
FileOutputStream fos = new FileOutputStream("destination.txt")
) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) != -1) {
fos.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}


#Java #Training #Medium #Try_with_resources
Всем доброго субботнего утра!🔆

Как прошла Ваша неделя? Что нового изучили в джаве?

Делитесь в чате и комментариях!

По прежнему актуален вопрос - о чем Вам рассказать завтра? Есть предложения?

Прекрасных выходных!!!!👍
This media is not supported in your browser
VIEW IN TELEGRAM
Всем доброго утра!☀️

Напоминаю, что сегодня, как и каждое воскресение, в 16:00 по МСК мы соберемся на онлайн встречу!

Тема сегодняшнего лайф-кодинга (по просьбам трудящихся):
"JDBC — платформенно независимый промышленный стандарт взаимодействия Java-приложений с различными СУБД, реализованный в виде пакета java.sql, входящего в состав Java SE."

На примерах разберем основу основ взаимодействия с базами данных в Java!

Приходите, будет интересно😎

Ссылка на встречу будет в нашем чате - https://t.me/Java_Beginner_chat
Когда-то и я так говорил😂

https://t.me/Java_for_beginner_dev

#Mems
Все, или почти все о JDBC (Java Database Connectivity). Встреча от 22.09.2024

Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE

Спасибо тем кто был, за Ваше участие и вопросы, это важно!🙏

На сегодняшней встрече, мы рассмотрели на примере кода основные тезисы о JDBC (Java Database Connectivity), его настройке, и запуске с базой данных Postgresql в контейнере Docker.

Пример кода - https://github.com/Oleborn/JDBC

Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!

Всем теплого вечера и отличного настроения! 🫡✌️
Встреча_в_Телемосте_22_09_24_20_04_10_—_запись.webm
289.5 MB
Для тех кто не смог победить блокировку Youtube и не желает заходить в Rutube выкладываю видео тут!

Смотрите на здоровье) 🫡

#online_meeting
Переменные-ссылки в Java

Java — это объектно-ориентированный язык программирования, который использует ссылочные типы для работы с объектами. В отличие от примитивных типов данных, таких как int, float или boolean, объекты в Java всегда хранятся и передаются через переменные-ссылки.

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

class Dog {
String name;

Dog(String name) {
this.name = name;
}
}

public class Main {
public static void main(String[] args) {
Dog myDog = new Dog("Buddy");
}
}
Здесь переменная myDog не содержит сам объект типа Dog. Вместо этого она содержит ссылку на объект Dog, который хранится в динамической памяти (куче).


Основные причины, по которым Java использует переменные-ссылки, включают:

Эффективное управление памятью. Объекты могут занимать много памяти, и передача самих объектов между методами или классами привела бы к значительным затратам по времени и памяти. Передача ссылок позволяет работать с объектами без их копирования.
Упрощение работы с объектами. Ссылки позволяют создавать несколько переменных, которые ссылаются на один и тот же объект. Это упрощает совместную работу объектов, а также обновление их состояний в разных частях программы
Передача объектов по ссылке. Когда объект передаётся в метод, фактически передаётся не копия объекта, а копия ссылки на него. Это позволяет методам изменять состояние объектов, переданных им в качестве параметров.


Примитивные типы и ссылочные типы


В Java все типы делятся на примитивные и ссылочные.
Примитивные типы (например, int, boolean, double) хранят непосредственно значения. Если вы присваиваете значение одной переменной другой, создаётся копия этого значения.
Ссылочные типы включают все объекты и массивы. Переменная ссылочного типа хранит ссылку на область памяти, где находится объект. Когда вы присваиваете одну ссылку другой переменной, обе переменные указывают на один и тот же объект в памяти.

Пример различий между примитивными и ссылочными типами:
public class Main {
public static void main(String[] args) {
// Примитивный тип
int a = 5;
int b = a;
b = 10;
System.out.println("a = " + a); // Выведет a = 5, т.к. b — копия значения a

// Ссылочный тип
Dog dog1 = new Dog("Buddy");
Dog dog2 = dog1;
dog2.name = "Max";
System.out.println(dog1.name); // Выведет Max, т.к. dog2 и dog1 ссылаются на один объект
}
}
В случае с примитивными типами значение переменной копируется, а в случае со ссылочными типами переменная хранит ссылку на объект, и при присваивании копируется сама ссылка, а не объект.


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


Пример создания объекта и работы с ссылкой:

public class Main {
public static void main(String[] args) {
Dog dog1 = new Dog("Buddy");
Dog dog2 = dog1;

dog2.name = "Max";
System.out.println(dog1.name); // Выведет Max
}
}
Здесь переменная dog2 является копией ссылки dog1, а не самого объекта. Любые изменения через dog2 отразятся на объекте, на который ссылается dog1.


#Java #Training #Reference_Variables
Передача объектов в методы

Когда объект передаётся в метод, Java передаёт не сам объект, а копию ссылки на него. Это означает, что внутри метода можно изменять свойства объекта, и эти изменения будут видны за пределами метода. Однако если попытаться переназначить ссылку внутри метода, оригинальная переменная, ссылающаяся на объект, не изменится.

Пример передачи объекта в метод:

public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
changeName(dog);
System.out.println(dog.name); // Выведет Max
}

public static void changeName(Dog d) {
d.name = "Max"; // Изменяем поле объекта через ссылку
}
}
Здесь объект Dog передаётся в метод changeName(), и изменения имени через ссылку d изменяют исходный объект.


Однако если попытаться переназначить переменную внутри метода, оригинальная ссылка не изменится:
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
changeDog(dog);
System.out.println(dog.name); // Выведет Buddy
}

public static void changeDog(Dog d) {
d = new Dog("Max"); // Переназначаем ссылку, но это не влияет на оригинальную переменную
}
}
Здесь создание нового объекта внутри метода не изменяет ссылку на оригинальный объект dog в методе main().


Сравнение ссылок

Когда вы сравниваете переменные ссылочного типа с помощью оператора ==, фактически сравниваются сами ссылки, а не содержимое объектов. Это может привести к путанице, если вы не учтёте, что сравнение объектов требует использования метода equals().
Dog dog1 = new Dog("Buddy");
Dog dog2 = new Dog("Buddy");

System.out.println(dog1 == dog2); // Выведет false, так как ссылки разные
System.out.println(dog1.equals(dog2)); // Зависит от реализации метода equals()
По умолчанию метод equals() в классе Object сравнивает ссылки. Чтобы корректно сравнивать объекты по содержимому, необходимо переопределить метод equals().


#Java #Training #Reference_Variables
Что выведет код?

class Person {
String name;

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

public class Task230924 {
public static void main(String[] args) {
Person p1 = new Person("Alice");
Person p2 = p1;
p2.name = "Bob";
System.out.println(p1.name);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
41%
Alice
50%
Bob
9%
null
0%
Ошибка компиляции
Ведь правда?🧐😂

https://t.me/Java_for_beginner_dev

#Mems
Переменные-ссылки в Java — внутреннее устройство

Когда вы создаёте объект в Java, он размещается в куче (heap), которая управляется JVM. Переменная-ссылка хранит в себе адрес этого объекта в памяти. Это значит, что сама переменная ссылается на область памяти, где хранится объект, а не содержит его данные напрямую.

Куча (heap) — это область памяти, где хранятся все динамически создаваемые объекты. Куча управляется сборщиком мусора (Garbage Collector), который освобождает память, занятую объектами, на которые больше не ссылаются переменные.

Ссылочные переменные хранятся в стеке (stack). Они содержат адреса объектов, расположенных в куче. Когда переменная выходит из области видимости (например, метод завершает работу), её ссылка из стека удаляется.
Dog dog1 = new Dog("Buddy");
Dog dog2 = dog1;
Здесь объект Dog("Buddy") хранится в куче, а ссылки dog1 и dog2 хранятся в стеке. Обе ссылки указывают на один и тот же объект в куче. Когда переменная dog1 выходит из области видимости, её ссылка удаляется, но если на объект всё ещё ссылается dog2, объект остаётся в памяти.


Ключевые моменты работы со ссылками

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

Утечки памяти. Несмотря на то, что Java использует сборщик мусора для управления памятью, неправильная работа с ссылками может привести к утечкам памяти. Например, если вы сохраняете ссылки на ненужные объекты в структурах данных (таких как списки или карты), эти объекты не будут собраны сборщиком мусора, что приведёт к увеличению потребления памяти.

Сравнение ссылок и объектов. Для сравнения содержимого объектов необходимо переопределять метод equals(). Сравнение ссылок с помощью оператора == проверяет, ссылаются ли переменные на один и тот же объект в памяти, а не идентичны ли объекты по содержимому.

Пример переопределения метода equals():
class Dog {
String name;

Dog(String name) {
this.name = name;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Dog dog = (Dog) obj;
return name.equals(dog.name);
}
}

public class Main {
public static void main(String[] args) {
Dog dog1 = new Dog("Buddy");
Dog dog2 = new Dog("Buddy");

System.out.println(dog1.equals(dog2)); // Выведет true, т.к. мы переопределили equals
}
}


#Java #Training #Reference_Variables