介绍
本文提供了如何在Java编程中创建一个不变的类的概述。
例如, String
是一个不变的类,一旦实例化,一个‘String’对象的值永远不会改变。
由于不可变的对象无法更新,因此程序需要为每个状态变更创建一个新对象,但是不可变的对象也有以下优点:
- 一个不变的类适合缓存,因为你不必担心值的变化。 * 一个不变的类本质上是 [线程安全]( / 社区 / 教程 / 线程安全-in-java),所以你不必担心多线程环境中的线程安全。
了解更多关于 Java 多链接(/community/tutorials/multithreading-in-java)的信息,并浏览 Java 多链接面试问题(/community/tutorials/java-multithreading-concurrency-interview-questions-answers)。
在Java中创建不可变的类
要在 Java 中创建一个不变的类,你需要遵循以下一般原则:
- 联合国 宣布该类为"最终",因此不能延长.
- 联合国 使所有领域 " 私营 " ,不允许直接进入。 3个 不要为变量提供设置方法. 4.四. 使所有可变字段`最终',以便一个字段的值只能分配一次。 5 (韩语). 采用[构 (/社区/讲 /构 (java) 方法初始化所有字段,进行深抄.
- 在获取器方法中对物体进行克隆,以返回副本,而不是返回实际对象的参考。 .
下列类是一个示例,说明了不可变性的基本面。‘FinalClassExample’类定义了字段,并提供了使用深副本来初始化对象的构造方法。
创建一个名为FinalClassExample.java
的新文件,并将其复制到以下代码:
1[label FinalClassExample.java]
2import java.util.HashMap;
3import java.util.Iterator;
4
5public final class FinalClassExample {
6
7 // fields of the FinalClassExample class
8 private final int id;
9
10 private final String name;
11
12 private final HashMap<String,String> testMap;
13
14
15 public int getId() {
16 return id;
17 }
18
19 public String getName() {
20 return name;
21 }
22
23 // Getter function for mutable objects
24
25 public HashMap<String, String> getTestMap() {
26 return (HashMap<String, String>) testMap.clone();
27 }
28
29 // Constructor method performing deep copy
30
31 public FinalClassExample(int i, String n, HashMap<String,String> hm){
32 System.out.println("Performing Deep Copy for Object initialization");
33
34 // "this" keyword refers to the current object
35 this.id=i;
36 this.name=n;
37
38 HashMap<String,String> tempMap=new HashMap<String,String>();
39 String key;
40 Iterator<String> it = hm.keySet().iterator();
41 while(it.hasNext()){
42 key=it.next();
43 tempMap.put(key, hm.get(key));
44 }
45 this.testMap=tempMap;
46 }
47
48 // Test the immutable class
49
50 public static void main(String[] args) {
51 HashMap<String, String> h1 = new HashMap<String,String>();
52 h1.put("1", "first");
53 h1.put("2", "second");
54
55 String s = "original";
56
57 int i=10;
58
59 FinalClassExample ce = new FinalClassExample(i,s,h1);
60
61 // print the ce values
62 System.out.println("ce id: "+ce.getId());
63 System.out.println("ce name: "+ce.getName());
64 System.out.println("ce testMap: "+ce.getTestMap());
65 // change the local variable values
66 i=20;
67 s="modified";
68 h1.put("3", "third");
69 // print the values again
70 System.out.println("ce id after local variable change: "+ce.getId());
71 System.out.println("ce name after local variable change: "+ce.getName());
72 System.out.println("ce testMap after local variable change: "+ce.getTestMap());
73
74 HashMap<String, String> hmTest = ce.getTestMap();
75 hmTest.put("4", "new");
76
77 System.out.println("ce testMap after changing variable from getter methods: "+ce.getTestMap());
78
79 }
80
81}
编译和运行程序:
1javac FinalClassExample.java
2java FinalClassExample
注意: 在编译文件时,您可能会收到以下消息: 注意: FinalClassExample.java 使用未经检查或不安全的操作',因为输出方法使用从
HashMap<String,String>到
Object` 的未经检查的投放。
你会得到以下的输出:
1[secondary_label Output]
2Performing Deep Copy for Object initialization
3ce id: 10
4ce name: original
5ce testMap: {1=first, 2=second}
6ce id after local variable change: 10
7ce name after local variable change: original
8ce testMap after local variable change: {1=first, 2=second}
9ce testMap after changing variable from getter methods: {1=first, 2=second}
输出显示 HashMap 值没有改变,因为构造器使用深度复制,而 getter 函数返回原始对象的克隆。
当你不使用深度复制和克隆时会发生什么
您可以对FinalClassExample.java
文件进行更改,以显示当您使用浅副本而不是深副本时会发生什么,然后返回插入副本的对象。
- 删除提供深度副本的构建方法,并添加在下面的示例中突出显示的提供浅度副本的构建方法. * 在输入函数中,删除
return (HashMap<String, String>) testMap.clone();
并添加return testMap;
。
示例文件现在应该是这样的:
1[label FinalClassExample.java]
2import java.util.HashMap;
3import java.util.Iterator;
4
5public final class FinalClassExample {
6
7 // fields of the FinalClassExample class
8 private final int id;
9
10 private final String name;
11
12 private final HashMap<String,String> testMap;
13
14
15 public int getId() {
16 return id;
17 }
18
19 public String getName() {
20 return name;
21 }
22
23 // Getter function for mutable objects
24
25 public HashMap<String, String> getTestMap() {
26 return testMap;
27 }
28
29 //Constructor method performing shallow copy
30
31 public FinalClassExample(int i, String n, HashMap<String,String> hm){
32 System.out.println("Performing Shallow Copy for Object initialization");
33 this.id=i;
34 this.name=n;
35 this.testMap=hm;
36 }
37
38 // Test the immutable class
39
40 public static void main(String[] args) {
41 HashMap<String, String> h1 = new HashMap<String,String>();
42 h1.put("1", "first");
43 h1.put("2", "second");
44
45 String s = "original";
46
47 int i=10;
48
49 FinalClassExample ce = new FinalClassExample(i,s,h1);
50
51 // print the ce values
52 System.out.println("ce id: "+ce.getId());
53 System.out.println("ce name: "+ce.getName());
54 System.out.println("ce testMap: "+ce.getTestMap());
55 // change the local variable values
56 i=20;
57 s="modified";
58 h1.put("3", "third");
59 // print the values again
60 System.out.println("ce id after local variable change: "+ce.getId());
61 System.out.println("ce name after local variable change: "+ce.getName());
62 System.out.println("ce testMap after local variable change: "+ce.getTestMap());
63
64 HashMap<String, String> hmTest = ce.getTestMap();
65 hmTest.put("4", "new");
66
67 System.out.println("ce testMap after changing variable from getter methods: "+ce.getTestMap());
68
69 }
70
71}
编译和运行程序:
1javac FinalClassExample.java
2java FinalClassExample
你会得到以下的输出:
1[secondary_label Output]
2Performing Shallow Copy for Object initialization
3ce id: 10
4ce name: original
5ce testMap: {1=first, 2=second}
6ce id after local variable change: 10
7ce name after local variable change: original
8ce testMap after local variable change: {1=first, 2=second, 3=third}
9ce testMap after changing variable from getter methods: {1=first, 2=second, 3=third, 4=new}
输出显示,HashMap 值被更改,因为构建方法使用浅副本,在 getter 函数中直接引用原始对象。
结论
您已经了解了一些在创建不变类在Java中要遵循的一些一般原则,包括深度复制的重要性。 继续学习更多 Java 教程。