如何在 Java 中创建不可变类

介绍

本文提供了如何在Java编程中创建一个不变的类的概述。

例如, String是一个不变的类,一旦实例化,一个‘String’对象的值永远不会改变。

由于不可变的对象无法更新,因此程序需要为每个状态变更创建一个新对象,但是不可变的对象也有以下优点:

  • 一个不变的类适合缓存,因为你不必担心值的变化。 * 一个不变的类本质上是 [线程安全]( / 社区 / 教程 / 线程安全-in-java),所以你不必担心多线程环境中的线程安全。

了解更多关于 Java 多链接(/community/tutorials/multithreading-in-java)的信息,并浏览 Java 多链接面试问题(/community/tutorials/java-multithreading-concurrency-interview-questions-answers)。

在Java中创建不可变的类

要在 Java 中创建一个不变的类,你需要遵循以下一般原则:

  1. 联合国 宣布该类为"最终",因此不能延长.
  2. 联合国 使所有领域 " 私营 " ,不允许直接进入。 3个 不要为变量提供设置方法. 4.四. 使所有可变字段`最终',以便一个字段的值只能分配一次。 5 (韩语). 采用[构 (/社区/讲 /构 (java) 方法初始化所有字段,进行深抄.
  3. 在获取器方法中对物体进行克隆,以返回副本,而不是返回实际对象的参考。 .

下列类是一个示例,说明了不可变性的基本面。‘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 教程

Published At
Categories with 技术
Tagged with
comments powered by Disqus