Рубрики
Без рубрики

Как создать неизменяемый класс в Java?

Как создать неизменяемый класс в Java? Узнайте, как сделать класс неизменяемым в Java и что такое неизменяемый класс. Неизменяемые классы являются потокобезопасными.

Автор оригинала: Pankaj Kumar.

Сегодня мы узнаем о неизменяемом классе в Java. Что такое неизменяемые классы? Преимущества и важность глубокого копирования для неизменности.

Что такое неизменяемый класс в Java?

Неизменяемые объекты – это экземпляры, состояние которых не меняется после инициализации. Например, String является неизменяемым классом, и после создания экземпляра его значение никогда не меняется.

Прочитайте : Почему строка в неизменяемом в Java

Преимущества неизменяемого класса в Java

Неизменяемый класс хорош для целей кэширования, потому что вам не нужно беспокоиться об изменениях значений.

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

Прочитайте : Учебник по потокам Java и Вопросы для многопоточного интервью Java .

Здесь я предлагаю способ создания неизменяемого класса на примере для лучшего понимания.

Как создать неизменяемый класс в Java?

Чтобы создать неизменяемый класс в Java, вам необходимо выполнить следующие действия.

  1. Объявите класс окончательным, чтобы его нельзя было расширить.
  2. Сделайте все поля закрытыми, чтобы прямой доступ был запрещен.
  3. Не предоставляйте методы настройки для переменных.
  4. Сделайте все изменяемые поля окончательными , чтобы его значение можно было присвоить только один раз.
  5. Инициализируйте все поля с помощью конструктора , выполнив глубокое копирование.
  6. Выполните клонирование объектов в методах получения, чтобы вернуть копию, а не фактическую ссылку на объект.

Чтобы понять пункты 4 и 5, давайте запустим пример конечного класса, который хорошо работает, и значения не изменяются после создания экземпляра.

Чтобы понять пункты 4 и 5, давайте запустим пример конечного класса, который хорошо работает, и значения не изменяются после создания экземпляра.

package com.journaldev.java;

import java.util.HashMap;
import java.util.Iterator;

public final class FinalClassExample {

	private final int id;
	
	private final String name;
	
	private final HashMap testMap;
	
	public int getId() {
		return id;
	}


	public String getName() {
		return name;
	}

	/**
	 * Accessor function for mutable objects
	 */
	public HashMap getTestMap() {
		//return testMap;
		return (HashMap) testMap.clone();
	}

	/**
	 * Constructor performing Deep Copy
	 * @param i
	 * @param n
	 * @param hm
	 */
	
	public FinalClassExample(int i, String n, HashMap hm){
		System.out.println("Performing Deep Copy for Object initialization");
		this.id=i;
		this.name=n;
		HashMap tempMap=new HashMap();
		String key;
		Iterator it = hm.keySet().iterator();
		while(it.hasNext()){
			key=it.next();
			tempMap.put(key, hm.get(key));
		}
		this.testMap=tempMap;
	}
	
	
	/**
	 * Constructor performing Shallow Copy
	 * @param i
	 * @param n
	 * @param hm
	 */
	/**
	public FinalClassExample(int i, String n, HashMap hm){
		System.out.println("Performing Shallow Copy for Object initialization");
		this.id=i;
		this.name=n;
		this.testMap=hm;
	}
	*/
	
	/**
	 * To test the consequences of Shallow Copy and how to avoid it with Deep Copy for creating immutable classes
	 * @param args
	 */
	public static void main(String[] args) {
		HashMap h1 = new HashMap();
		h1.put("1", "first");
		h1.put("2", "second");
		
		String s = "original";
		
		int i=10;
		
		FinalClassExample ce = new FinalClassExample(i,s,h1);
		
		//Lets see whether its copy by field or reference
		System.out.println(s==ce.getName());
		System.out.println(h1 == ce.getTestMap());
		//print the ce values
		System.out.println("ce id:"+ce.getId());
		System.out.println("ce name:"+ce.getName());
		System.out.println("ce testMap:"+ce.getTestMap());
		//change the local variable values
		i=20;
		s="modified";
		h1.put("3", "third");
		//print the values again
		System.out.println("ce id after local variable change:"+ce.getId());
		System.out.println("ce name after local variable change:"+ce.getName());
		System.out.println("ce testMap after local variable change:"+ce.getTestMap());
		
		HashMap hmTest = ce.getTestMap();
		hmTest.put("4", "new");
		
		System.out.println("ce testMap after changing variable from accessor methods:"+ce.getTestMap());

	}

}

Результатом приведенного выше примера программы является:

Performing Deep Copy for Object initialization
true
false
ce id:10
ce name:original
ce testMap:{2=second, 1=first}
ce id after local variable change:10
ce name after local variable change:original
ce testMap after local variable change:{2=second, 1=first}
ce testMap after changing variable from accessor methods:{2=second, 1=first}

Почему глубокое копирование важно для неизменности?

Давайте прокомментируем конструктор, предоставляющий глубокую копию, и раскомментируем конструктор, предоставляющий неглубокую копию.

Кроме того, раскомментируйте оператор return в методе getTestMap () , который возвращает фактическую ссылку на объект.

Запустите программу после того, как все изменения будут сделаны. Это приведет к следующему результату.

Performing Shallow Copy for Object initialization
true
true
ce id:10
ce name:original
ce testMap:{2=second, 1=first}
ce id after local variable change:10
ce name after local variable change:original
ce testMap after local variable change:{3=third, 2=second, 1=first}
ce testMap after changing variable from accessor methods:{3=third, 2=second, 1=first, 4=new}

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

Это происходит из-за прямой ссылки на исходный объект в функции getter.

Это все для неизменяемого класса в Java. Мы также узнали о важности глубокого копирования для неизменяемых классов.

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