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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Переменные-ссылки в 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
Переменные-ссылки в 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
Применение переменных-ссылок

Модели данных (DTO). В корпоративных приложениях часто используются классы данных (Data Transfer Objects, DTO) для передачи информации между различными уровнями приложения. Эти объекты передаются по ссылке для минимизации накладных расходов, связанных с копированием данных.
Копировать код
class User {
String name;
int age;

User(String name, int age) {
this.name = name;
this.age = age;
}
}

public class Main {
public static void main(String[] args) {
User user = new User("John", 30);
updateUser(user);
System.out.println("Updated user: " + user.name + ", age: " + user.age);
}

public static void updateUser(User user) {
user.name = "John Doe"; // Изменение объекта по ссылке
user.age = 31;
}
}


Работа с коллекциями. Коллекции в Java, такие как списки (List), карты (Map) и множества (Set), хранят ссылки на объекты. Это позволяет эффективно управлять большими объёмами данных, не создавая лишних копий.

import java.util.ArrayList;
import java.util.List;

class Car {
String model;

Car(String model) {
this.model = model;
}
}

public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
cars.add(new Car("Tesla"));
cars.add(new Car("BMW"));

for (Car car : cars) {
System.out.println(car.model);
}
// Изменение объекта в коллекции
cars.get(0).model = "Tesla Model S";

for (Car car : cars) {
System.out.println(car.model); // Изменения будут отражены в коллекции
}
}
}


Паттерны проектирования. Многие паттерны проектирования, такие как одиночка (Singleton), наблюдатель (Observer) и фабричный метод (Factory Method), зависят от правильного использования ссылок для управления объектами и их состояниями.
Пример реализации паттерна Singleton:
class Singleton {
private static Singleton instance;

private Singleton() {}

public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

public class Main {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();

System.out.println(singleton1 == singleton2); // Выведет true, т.к. обе ссылки указывают на один объект
}
}


#Java #Training #Reference_Variables