java创建一个不可变对象
Today we will learn about the immutable class in Java. What are immutable classes? The benefits and importance of deep copy for immutability.
今天,我们将学习Java中的不可变类。 什么是不可变类? 深复制对于不变性的好处和重要性。
什么是Java中的不可变类? (What is an immutable class in Java?)
Immutable objects are instances whose state doesn’t change after it has been initialized. For example, String is an immutable class and once instantiated its value never changes.
不可变对象是实例,其状态在初始化后不会改变。 例如, String是一个不可变的类,一旦实例化,其值就永远不会改变。
Read: Why String in immutable in Java
阅读 : 为什么Java中的String不可变
Java中不可变类的好处 (Benefits of Immutable Class in Java)
An immutable class is good for caching purposes because you don’t have to worry about the value changes.
不可变的类非常适合缓存,因为您不必担心值的更改。
Another benefit of immutable class is that it is inherently thread-safe, so you don’t have to worry about thread safety in case of multi-threaded environment.
不可变类的另一个好处是,它本质上是线程安全的 ,因此在多线程环境中,您不必担心线程安全。
Read: Java Thread Tutorial and Java Multi-Threading Interview Questions.
阅读 : Java线程教程和Java多线程面试问题 。
Here I am providing a way to create an immutable class via an example for better understanding.
在这里,我通过示例提供了一种创建不可变类的方法,以更好地理解。
如何用Java创建一个不可变的类? (How to Create an immutable class in Java?)
To create an immutable class in Java, you have to do the following steps.
要使用Java创建不可变的类,您必须执行以下步骤。
- Declare the class as final so it can’t be extended. 将课程声明为最终课程,因此无法扩展。
- Make all fields private so that direct access is not allowed. 将所有字段设为私有,以便不允许直接访问。
- Don’t provide setter methods for variables. 不要为变量提供setter方法。
- Make all mutable fields final so that its value can be assigned only once. 将所有可变字段定为最终值,使其值只能分配一次。
- Initialize all the fields via a constructor performing deep copy. 通过执行深度复制的构造函数初始化所有字段。
- Perform cloning of objects in the getter methods to return a copy rather than returning the actual object reference. 在getter方法中执行对象的克隆以返回副本,而不是返回实际的对象引用。
To understand points 4 and 5, let’s run the sample Final class that works well and values don’t get altered after instantiation.
为了理解第4点和第5点,让我们运行示例Final类,该类运行良好,并且实例化后值不会改变。
FinalClassExample.java
FinalClassExample.java
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<String,String> testMap;
public int getId() {
return id;
}
public String getName() {
return name;
}
/**
* Accessor function for mutable objects
*/
public HashMap<String, String> getTestMap() {
//return testMap;
return (HashMap<String, String>) testMap.clone();
}
/**
* Constructor performing Deep Copy
* @param i
* @param n
* @param hm
*/
public FinalClassExample(int i, String n, HashMap<String,String> hm){
System.out.println("Performing Deep Copy for Object initialization");
this.id=i;
this.name=n;
HashMap<String,String> tempMap=new HashMap<String,String>();
String key;
Iterator<String> 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<String,String> 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<String, String> h1 = new HashMap<String,String>();
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<String, String> hmTest = ce.getTestMap();
hmTest.put("4", "new");
System.out.println("ce testMap after changing variable from accessor methods:"+ce.getTestMap());
}
}
Output of the above example program is:
上面的示例程序的输出是:
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}
为什么Deep Copy对于不变性很重要? (Why Deep Copy is important for immutability?)
Let’s comment the constructor providing deep copy and uncomment the constructor providing a shallow copy.
让我们评论提供深拷贝的构造函数,并取消注释提供浅拷贝的构造函数。
Also, uncomment the return statement in the getTestMap()
method that returns the actual object reference.
另外,在返回实际对象引用的getTestMap()
方法中取消注释return语句。
Run the program after all the changes are done. It will produce the following output.
完成所有更改后,运行程序。 它将产生以下输出。
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}
As you can see from the output, HashMap values got changed because of shallow copy in the constructor.
从输出中可以看到,由于构造函数中的浅表复制, HashMap的值已更改。
It’s happening because of the direct reference to the original object in the getter function.
之所以发生这种情况,是因为直接在getter函数中引用了原始对象。
That’s all for an immutable class in Java. We also learned the importance of deep copy for immutable classes.
这就是Java中不可变类的全部内容。 我们还了解了深度复制对于不可变类的重要性。
Further Reading: If the immutable class has a lot of attributes and some of them are optional, we can use builder pattern to create immutable classes.
进一步阅读 :如果不可变类具有很多属性,并且其中一些是可选属性,则可以使用构建器模式来创建不可变类 。
翻译自: https://www.journaldev.com/129/how-to-create-immutable-class-in-java
java创建一个不可变对象