Классы в Java особым образом связаны с типами данных. Посмотрите на пример:
var user = new User("Danil", "Miloshin");
Каким будет реальный тип в данном случае? Классы, сами по себе, ведут себя как типы. Поэтому типом переменной user
будет User
, то есть так:
User user = new User("Danil", "Miloshin");
В Java все типы данных делятся на две категории: примитивные и ссылочные. К примитивным относятся все виды чисел, символы и логический тип данных (булеан). К ссылочным - классы, массивы, строки. В зависимости от категории, значительно меняется поведение кода и об этом нужно знать. В этом уроке мы разберем отличия между этими категориями и научимся правильно с ними работать.
Для изучения нам понадобится пример какого-то класса, чьи объекты мы используем в примерах кода. Возьмем для простоты класс User
с двумя полями и одним конструктором:
class User {
public String firstName;
public String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
Значение по умолчанию
Примитивные данные всегда имеют значение, даже если они определяются без инициализации:
int a;
System.out.println(a); // => 0
У ссылочных в качестве значения по умолчанию используется null
. Это специальное значение, которое может быть использовано в качестве любого объекта
User u;
System.out.println(u); // => null
// Можно присваивать и явно
// User u = null;
Присваивание
Примитивное значение всегда копируется при присваивании:
// Содержимое a и b не связаны
var a = 5;
var b = a;
Ссылочные же данные не копируются. При присваивании переменные начинают указывать (ссылаться) на один и тот же объект:
var u1 = new User("Igor", "Mon");
// Обе переменные ссылаются на один тот же объект
var u2 = u1;
u2.firstName = "Nina";
System.out.println(u1.firstName); // => Nina
u1 == u2; // true
// u2 теперь ссылается на другой объект
// Содержимое объекта при этом не важно, оно может быть одинаковым, а может быть разным
// Java проверяет только то, та же ли это ссылка или нет
u2 = new User("Igor", "Mon");
u1 == u2; // false
Больше всего это проявляется при передаче данных в методы и их возврате оттуда. Ссылочное значение передается по ссылке, а значит его можно изменить изнутри метода.
class UserController {
// Ничего не нужно возвращать, потому что пользователь будет изменен напрямую
public static void replaceName(User user, String newFirstName) {
// Чтобы продемонстрировать, как работают ссылочные данные, обращаемся к свойству напрямую
user.firstName = newFirstName;
}
}
var u = new User("Igor", "Mon");
UserController.replaceName(u, "Nina");
System.out.println(u.firstName); // => "Nina"
Сравнение
Примитивные данные сравниваются по значению. Пять всегда равно пяти, истина всегда равна истине:
var a = 5;
var b = 5;
a == b; // true
var t1 = true;
var t2 = true;
t1 == t2; // true
Ссылочные сравниваются по ссылкам, а не на основе содержимого. Объекты равны только сами себе. То что хранится внутри них - не важно.
var u1 = new User("Igor", "Mon");
var u2 = new User("Igor", "Mon");
// Проверяется только ссылка, указывает она на тот же объект или нет
u1 == u2; // false
// Объект равен сам себе, что ожидаемо
u1 == u1; // true
u2 == u2; // true
Иногда объекты все же нужно сравнивать между собой и определять равенство по каким-то признакам. Для этого есть решение и мы познакомимся с ним в следующих курсах.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.