爪哇 2博客
 爪哇 2博客

如何在Java中创建不可变类

在本教程中,我们将看到如何在Java中创建不可变类。
不变类是指一旦创建便无法更改其状态的类。
例: 字符串是不可变类的最佳示例。创建字符串后,将无法更改它。
不可变类很容易理解,它只有一个状态。不变类由构造函数精心实例化。不可变的类是线程安全的。这是不变类的最大优势,’无需对不可变的对象应用同步。将不可变类的对象放在HashMap中时,不可变类可能很有用,或者可以将其用于缓存目的,因为它的值赢得了’t change.

默认情况下,不可变对象是线程安全的。

创建不可变类的步骤:

  • 使您的班级最终: 
    如果将您的课程定为最终课程,则没有课程将无法对其进行扩展,因此将无法覆盖此类的方法。
  • 用private和final声明所有实例变量: 
    如果将实例变量设为私有,则没有外部类将能够访问实例变量,如果将它们设为最终变量,则无法对其进行更改。
  • 对设置方法说不:
    唐’不能为任何实例变量创建设置方法,因此将没有明确的方法来更改实例变量的状态。
  • 初始化构造函数中的所有变量:
    您可以在构造函数中初始化变量。使用可变对象时,需要特别注意。如果对象不可变,则需要进行深度复制。
  • 从getter方法返回时,执行可变对象的克隆:
    如果您从getter方法返回对象的克隆,它将赢得’t返回原始对象,因此原始对象将保持不变。我将在本教程的后面部分对此进行详细说明。

阅读: 为什么String在Java中是不可变的
让我们通过一个非常简单的示例来了解不可变的类:
让我们创建一个名为Country.java的简单类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
上市 最后 国家 {
 
私人的 最后 国家的名字;
私人的 最后 数组列表 listOfStates;
 
上市 国家 ( 国家的名字,数组列表 listOfStates) {
();
这个 .国家的名字 = 国家的名字;
这个 .listOfStates=listOfStates;
 
}
 
上市 得到 CountryName() {
返回 国家的名字;
}
 
上市 数组列表 得到 ListOfStates() {
返回 listOfStates;
}
 
上市 静态的 虚空 主要 ( args [])
{
数组列表 listOfStates= 数组列表();
listOfStates.(“中央邦”);
listOfStates.(“马哈拉斯特拉”);
listOfStates.( “古吉拉特” );
 
国家 国家 = 国家 ( “印度” ,listOfStates);
系统 .. 打印 (“国家:”+ 国家 . 得到 CountryName());
系统 .. 打印 (“状态清单:”+ 国家 . 得到 ListOfStates());
//它会被添加到列表中,因为我们没有在getListOfStates中使用clone
国家 . 得到 ListOfStates().("喀拉拉邦");
//它会被添加到列表中,因为我们没有在构造函数中使用深层复制
listOfStates.("拉贾斯坦邦");
系统 .. 打印 (“状态更新列表:”+ 国家 . 得到 ListOfStates());
 
}
}
 

运行该程序时,将获得以下输出:

1
2
3
4
5
 
国家 : 印度
清单 状态 : [ 中央邦 印度 , 马哈拉斯特拉, 古杰拉特 ]
更新 清单 状态 : [ 中央邦 印度 , 马哈拉斯特拉, 古杰拉特 , 喀拉拉邦, 拉贾斯坦邦]
 

上面的类不是一成不变的。这样做有两个原因:

  • 我们没有在getListOfStates()方法中使用克隆,因此我们能够添加“Kerala”到listOfStates。
  • 我们没有对listOfStates进行深度复制,因此我们可以添加“Rajasthan” to the list.
让我们在getListOfStates()方法中使用clone并查看其中的区别,只需将getListOfStates()更改为以下代码:

1
2
3
4
5
 
上市 数组列表 得到 ListOfStates() {
   返回   (数组列表) listOfStates. 克隆 ();
}
 

进行上述更改后运行程序时,将获得以下输出:

1
2
3
4
5
 
国家 : 印度
清单 状态 : [ 中央邦 印度 , 马哈拉斯特拉, 古杰拉特 ]
更新 清单 状态 : [ 中央邦 印度 , 马哈拉斯特拉, 古杰拉特 , 拉贾斯坦邦]
 

如果您注意到,“Kerala”未添加到列表中,因为我们正在getListOfStates()方法中返回listOfStates的副本,因此添加“Kerala”至country.getListOfStates()赢了’t影响原始清单。
现在,我们距离不可变的课程仅一步之遥。 
让更改构造函数制作listOfStates对象的深层副本。

1
2
3
4
5
6
7
8
9
10
11
12
 
上市 国家 ( 国家的名字, 数组列表 listOfStates) {
  ();
   这个 .国家的名字 = 国家的名字;
  数组列表 临时列表 = 数组列表();
 
   对于 ( 整型 i = 0; i < listOfStates. 尺寸 (); i ++ ) {
   临时列表.(listOfStates. 得到 (i));
  }
   这个 .listOfStates = 临时列表;
}
 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 
组织 . Arpit . 爪哇 2blog.;
 
进口 爪哇 . 实用程序 .数组列表;
 
上市 最后 国家 {
    //声明的私有最终实例变量
私人的 最后 国家的名字;
//可变对象
私人的 最后 数组列表 listOfStates;
 
上市 国家 ( 国家的名字, 数组列表 listOfStates) {
  ();
   这个 .国家的名字 = 国家的名字;
  //为可变对象创建深层副本
  数组列表 临时列表 = 数组列表();
 
   对于 ( 整型 i = 0; i < listOfStates. 尺寸 (); i ++ ) {
   临时列表.(listOfStates. 得到 (i));
  }
   这个 .listOfStates = 临时列表;
}
 
上市 得到 CountryName() {
     //不需要克隆,因为它是不可变的对象
   返回 国家的名字;
}
 
上市 数组列表 得到 ListOfStates() {
     //返回克隆的对象
   返回 (数组列表) listOfStates. 克隆 ();
}
 
上市 静态的 虚空 主要 ( args []) {
  数组列表 listOfStates = 数组列表();
  listOfStates.(“中央邦”);
  listOfStates.(“马哈拉斯特拉”);
  listOfStates.( “古吉拉特” );
   国家的名字= “印度” ;
   国家 国家 = 国家 (国家的名字, listOfStates);
   系统 .. 打印 (“国家:” + 国家 . 得到 CountryName());
  //让我们尝试更改局部变量countryName
  国家的名字= “中国” ;
   系统 .. 打印 (“更新的国家:” + 国家 . 得到 CountryName());
   系统 .. 打印 (“状态清单:” + 国家 . 得到 ListOfStates());
  // 它会  未添加到列表中,因为我们在使用克隆
  // 得到 ListOfStates
   国家 . 得到 ListOfStates().("喀拉拉邦");
  //它不会被添加到列表中,因为我们正在使用深度复制
  //构造函数
  listOfStates.("拉贾斯坦邦");
   系统 .. 打印 (“状态更新列表:” + 国家 . 得到 ListOfStates());
 
}
 
}
 

当您运行上述程序时,将获得以下输出:

1
2
3
4
5
6
 
国家 : 印度
更新 国家 : 印度
清单 状态 : [ 中央邦 印度 , 马哈拉斯特拉, 古杰拉特 ]
更新 清单 状态 : [ 中央邦 印度 , 马哈拉斯特拉, 古杰拉特 ]
 

国家/地区类别现在是不可变的类别。如您所见,我们正在对listOfStates进行深层复制,因此“Rajasthan”不会被添加到listOfStates中。

我希望它能帮助您在Java中创建不可变的类。

分享这个

作者

关注作者

相关文章

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *

订阅我们的新闻

获取质量教程到您的收件箱。现在订阅。


成为朋友

©2020 爪哇 2博客