Вопросы для собеседования по 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 🚀

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *