Вопросы для собеседования по Java (серия) — неизменяемый класс
Не меняй ее, она не хочет меняться! 🧩
Краткий
В определенный момент в большинстве собеседований по Java разговор естественным образом переходит к immutable
слово.
Либо это после разговора о String
и почему это неизменно или при обсуждении Внутреннее устройство HashMap.
В конце этого поста вам будет намного удобнее отвечать на следующие вопросы и расширять тему.
🔸 Что такое неизменяемый класс?
🔸 Как бы вы его создали?
🔸 Чем это полезно?
🔸 Знаете ли вы примеры неизменяемых классов Java?
Узнайте больше подобных сообщений на new-spike.net 🚀
Выполнение
🔵 Ан immutable
class — это класс, внутреннее устройство которого не меняется в течение жизненного цикла приложения.
Вместо того, чтобы просто перечислять его свойства, давайте сделаем это немного по-другому.
🚀 Мы перейдем от простого класса к неизменяемому классу.
public class Dog {
public String name;
}
Собака.java
1️⃣ Все поля в вашем классе должны быть инициализированы только через конструктор.
public class Dog {
public String name;
public Dog(String name) {
this.name = name;
}
}
Собака.java
2️⃣ Внутренние поля также должны быть объявлены как final
и private
без методов установки для них.
Таким образом, они не могут быть изменены после инициализации и должны быть доступны только через методы получения.
public class Dog {
private final String name;
public Dog(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
Собака.java
3️⃣ Класс должен быть объявлен как final
поэтому его нельзя расширить другими классами и получить доступ к полям.
public final class Dog {
private final String name;
public Dog(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
Собака.java
Узнайте больше подобных сообщений на new-spike.net 🚀
💯 На данный момент у нас есть immutable
сорт.
❓ А что, если мы хотим добавить новое поле произвольного типа?
🔵 Допустим, мы хотим узнать место рождения собаки. Давайте создадим простой класс адресов.
public class Address {
public String streetName;
public String streetNo;
public Address(String streetName, String streetNo) {
this.streetName = streetName;
this.streetNo = streetNo;
}
}
Адрес.java
Мы добавляем его как поле внутри Dog
сорт.
Чтобы сохранить наш класс immutable
нам нужно объявить поле как private
и final
и иметь метод получения для получения сведений об адресе.
public final class Dog {
private final String name;
private final Address birthPlace;
public Dog(String name, Address birthPlace) {
this.name = name;
this.birthPlace = birthPlace;
}
public String getName() {
return this.name;
}
public Address getBirthPlace() {
return this.birthPlace;
}
}
Собака.java
❗️ Мы могли бы подумать, что это все. Мы были бы неправы!
Но как это могло быть? Мы сделали все точно так же, как и для name
поле.
Чтобы понять почему, давайте рассмотрим пример, где мы используем Dog
сорт.
public class ImmutableClassApplication {
public static void main(String[] args) {
Dog dog = new Dog("Max", new Address("Oxford", "23A"));
dog.getBirthPlace().streetName = "Bingham"; // change the street of the dog's birth place.
System.out.println("Dog name: " + dog.getName()
+ "\n Street: " + dog.getBirthPlace().getStreetName()
+ "\n Number: " + dog.getBirthPlace().getStreetNo());
}
}
Выход :
Dog name: Max
Street: Bingham
Number: 23A
Узнайте больше подобных сообщений на new-spike.net 🚀
❗️ Как видите, мы действительно можем обновить значение birthPlace
поле и неявно изменить dog
объект.
Из-за этого, помимо внутренних полей, объявленных как private
и final
и не определяя сеттеры, вы также должны взглянуть на свои внутренние поля, чтобы они были immutable
.
❗️ Разница между двумя полями в том, что String
объявляется неявно immutable
в Яве.
Взгляните на эта почта чтобы лучше понять, что происходит за кулисами со строкой!
🧩 Помимо String, в Java неизменяемы и другие предопределенные классы, например Integer
и Long
и так далее.
🔵 Сказав это, решение состоит в том, чтобы изменить Address
класс, чтобы сделать это immutable
.
public final class Address {
private final String streetName;
private final String streetNo;
public Address(String streetName, String streetNo) {
this.streetName = streetName;
this.streetNo = streetNo;
}
public String getStreetName() {
return streetName;
}
public String getStreetNo() {
return streetNo;
}
}
Адрес.java
❗️ Это решение жизнеспособно, когда мы действительно можем изменить пользовательский тип, чтобы сделать его неизменяемым.
Но что, если мы не хотим делать Address
класс неизменяемый из-за других зависимостей от него. Что мы можем теперь сделать?
🔵 Решение в этом случае состоит в том, чтобы получить клон объекта в конкретном методе получения.
1️⃣ Для этого нам нужно добавить новый конструктор в Address
класс, получив Address
объект в качестве параметра.
public final class Address {
private final String streetName;
private final String streetNo;
public Address(String streetName, String streetNo) {
this.streetName = streetName;
this.streetNo = streetNo;
}
// clone constructor
public Address(Address address) {
this.streetName = address.getStreetName();
this.streetNo = address.getStreetNo();
}
public String getStreetName() {
return streetName;
}
public String getStreetNo() {
return streetNo;
}
}
2️⃣ Теперь, когда нам нужно достать собаку birthPlace
мы получим клон этого объекта.
public final class Dog {
private final String name;
private final Address birthPlace;
public Dog(String name, Address birthPlace) {
this.name = name;
this.birthPlace = birthPlace;
}
public String getName() {
return this.name;
}
public Address getBirthPlace() {
return new Address(this.birthPlace);
}
}
3️⃣ После этого изменения запуск предыдущего кода будет иметь другой результат.
public class ImmutableClassApplication {
public static void main(String[] args) {
Dog dog = new Dog("Max", new Address("Oxford", "23A"));
dog.getBirthPlace().streetName = "Bingham"; // the change will be done on the clone and not the actual value of the dog's birth place
System.out.println("Dog name: " + dog.getName()
+ "\n Street: " + dog.getBirthPlace().getStreetName()
+ "\n Number: " + dog.getBirthPlace().getStreetNo());
}
}
Приложение ImmutableClass.java
Выход :
Dog name: Max
Street: Oxford
Number: 23A
❓ Теперь, когда мы знаем, как создать immutable
и на что обращать внимание, какова реальная цель этого?
🧩 Наиболее распространенные варианты использования:
1️⃣ Используйте пользовательский класс в качестве ключа на карте.
🔹 Причина этого в том, что хэш неизменяемого объекта всегда будет одинаковым и будет работать намного лучше с точки зрения производительности.
2️⃣ Хранить значения в многопоточном приложении.
🔹 Потому что вам не нужно беспокоиться о том, что разные потоки изменят внутреннее состояние объекта.
Узнайте больше подобных сообщений на new-spike.net 🚀