如何在Java中创建不可变类

时间:2020-02-23 14:41:28  来源:igfitidea点击:

在本教程中,我们将看到如何在Java中创建不可变类。

不可变类是程序,其状态在创建后无法更改。

示例:String是不可变类的最佳示例。
创建字符串后,我们无法更改它。

不可阻挡的类非常简单,它只有一个州。
构造函数仔细执行了不可改变的程序。
不变的程序是线程安全的。
这是不可变类的最大优势,我们无需对不可变量的同步应用同步。
在将Offutable类放在HashMap中的对象或者其可用于缓存目的,因此不可变类可能是有用的,因为它的值不会改变。

Immutable objects are by default thread safe.

创建不可变类的步骤:

  • 让你的类决赛:如果你做你的类决赛,没有程序将能够扩展它,因此将无法覆盖此类的方法。
  • 使用私有和最终声明所有实例变量:如果我们使实例变量私有,则不包含外部类将能够访问实例变量,如果我们使它们最终,则无法更改它。
  • 对Setter方法说否:不要为任何实例变量创建Setter方法,因此不会有明确的方法来更改实例变量的状态。
  • 初始化构造函数中的所有变量:我们可以初始化构造函数中的变量。使用可变对象时需要特别小心。在模仿对象的情况下,我们需要做深刻的副本。
  • 从getter方法返回时执行可变对象的克隆:如果从getter方法返回对象的克隆,则不会返回原始对象,因此原始对象将保持完整。我将在本教程的后期部分解释这一点。

让我们了解一个非常简单的例子:让我们创建一个名为国家/地区的简单类。

Java。

public final class Country{
 
 private final String countryName; 
 private final ArrayList listOfStates;
 
 public Country(String countryName,ArrayList listOfStates) {
 super();
 this.countryName = countryName;
 this.listOfStates=listOfStates;
 
 }
 
 public String getCountryName() {
 return countryName;
 }
 
 public ArrayList getListOfStates() {
 return listOfStates;
 }
 
 public static void main(String args[])
 {
 ArrayList listOfStates=new ArrayList();
 listOfStates.add("Madhya Pradesh");
 listOfStates.add("Maharastra");
 listOfStates.add("Gujrat");
 
 Country country=new Country("Netherlands",listOfStates);
 System.out.println("Country : "+country.getCountryName());
 System.out.println("List of states : "+country.getListOfStates());
 //It will be added to the list because we did not use clone in getListOfStates
 country.getListOfStates().add("Kerala");
 //It will be added to the list because we did not use deep copy in constructor
 listOfStates.add("Rajasthan");
 System.out.println("Updated List of states : "+country.getListOfStates());
 
 } 
}

运行程序时,我们将得到以下输出:

Country : Netherlands
List of states : [Madhya Pradesh, Maharastra, Gujrat]
Updated List of states : [Madhya Pradesh, Maharastra, Gujrat, Kerala, Rajasthan]

上面的程序不是不可变的。
它有两个原因:

  • 我们没有在getListofstates()方法中使用克隆,因此我们能够将"kerala"添加到listofstates。
  • 我们没有为listofstates做好副本,因此我们能够将"Rajasthan"添加到列表中。

让我们在getListofstates()方法中使用克隆,看看差异,只需将getListOfStates()更改为以下代码:

public ArrayList getListOfStates() {
  return  (ArrayList) listOfStates.clone();
 }

在进行上述更改后运行程序,我们将得到以下输出:

Country : Netherlands
List of states : [Madhya Pradesh, Maharastra, Gujrat]
Updated List of states : [Madhya Pradesh, Maharastra, Gujrat, Rajasthan]

如果我们注意到,"kerala"未添加到列表中,因为我们在getListofstates()方法中返回Listofstates的克隆,因此将"kerala"添加到country.getlistofstates()不会影响原始列表。
我们现在是一步到不可变的程序。
允许更改构造函数以使ListOfStates对象的深度副本。

public Country(String countryName, ArrayList listOfStates) {
  super();
  this.countryName = countryName;
  ArrayList tempList = new ArrayList();
 
  for (int i = 0; i < listOfStates.size(); i++) {
   tempList.add(listOfStates.get(i));
  }
  this.listOfStates = tempList;
 }

让我们检查在上述更改后我们创建的最终类。

package org.igi.theitroad.bean;
 
import java.util.ArrayList;
 
public final class Country {
    //declared private final instance variable
 private final String countryName;
 //Mutable object
 private final ArrayList listOfStates;
 
 public Country(String countryName, ArrayList listOfStates) {
  super();
  this.countryName = countryName;
  //Creating deep copy for mutable object
  ArrayList tempList = new ArrayList();
 
  for (int i = 0; i < listOfStates.size(); i++) {
   tempList.add(listOfStates.get(i));
  }
  this.listOfStates = tempList;
 }
 
 public String getCountryName() {
     //Do not need to do cloning as it is immutable object
  return countryName;
 }
 
 public ArrayList getListOfStates() {
     //Returning cloned object 
  return (ArrayList) listOfStates.clone();
 }
 
 public static void main(String args[]) {
  ArrayList listOfStates = new ArrayList();
  listOfStates.add("Madhya Pradesh");
  listOfStates.add("Maharastra");
  listOfStates.add("Gujrat");
  String countryName="Netherlands";
  Country country = new Country(countryName, listOfStates);
  System.out.println("Country : " + country.getCountryName());
  //Lets try to change local variable countryName
  countryName="China";
  System.out.println("Updated Country : " + country.getCountryName());
  System.out.println("List of states : " + country.getListOfStates());
  //It will  not be added to the list because we are using clone in
  //getListOfStates
  country.getListOfStates().add("Kerala");
  //It will not be added to the list because we are using deep copy in
  //constructor
  listOfStates.add("Rajasthan");
  System.out.println("Updated List of states : " + country.getListOfStates());
 
 }
 
}

运行上面的程序时,我们将得到以下输出:

Country : Netherlands
Updated Country : Netherlands
List of states : [Madhya Pradesh, Maharastra, Gujrat]
Updated List of states : [Madhya Pradesh, Maharastra, Gujrat]

国家类现在是不可变的程序。
正如我们所看到的,我们正在为ListOfStates做深刻的副本,因此不会将"Rajasthan"添加到Listofstates中。