Java Immutable Class[ From ]
immutable object提供了极具价值的服务。由于他们保证自己的状态从构建之后就一定不再改变。因此他们天生具备多线程安全性。所以我们可以不必对它进行同步控制,这样可能能够提高些性能。但是实现immutable object时你必须实现clone(克隆)功能,而其代价可能不小。
要将一个类变成immutable是要通过多方面的合作才可能造就不变性:
1 将class中的所有数据声明为private。
2 只提供取值函数(getter),不提供设值函数(setter)。
3 声明class为final。
4 从获取器返回references to mutable object之前,先克隆(cloning)那些mutable object。
5 将传递给构造函数的reference to mutable object先clone
6 在构造函数中设定class内含的所有数据。
这个class不需要克隆(clone)任何数据,因为其构造函数所接受的,或其取值函数(getter)所返回的,都只是基本类型和 reference to immutable object。基本类型不是对象,String class是恒常不变的,所以也不需要对它进行clone。
上述DiskDriveInfo并不是immutable,因为在DiskDriveInfo可能改变user的值,例如:
上述代码的输出为:
AAA
BBB
想要将DiskDriveInfo类实现为immutable, 首先必须为User类实现clone()方法:
然后将DiskDriveInfo类的定义修改为:
结果上述测试代码的输出将变成:
AAA
AAA
假如DiskDriveInfo类里面的不是一个user对象 而是一个Vector,里面保存了许多user对象。难道时调用Vector里面的clone()吗?可惜Vector克隆的不是整个的对象树,而是克隆了一个Vector但是里面的指向的user对象还是以前那个user对象的。这时候我们就需要深层克隆(Deep Cloning)
如:
或者在DiskDriveInfo中提供一个cloneVector(Vector)的方法好了。
总而言之,在实现了一个immutable class(不可变类)时,请遵守下列规则。
1、声明这个class为final。
2。声明所有的数据为private。
3。只提供取值函数(getter),不提供设值函数(setter)。
4、在构造函数中设置所有的instance数据。
5、如果函数返回references to mutable objects,请先克隆那些mutable objects。
6、如果函数接受references to mutable objects,请先克隆那些mutable objects。
7、如果缺省之浅层克隆(shallow clone)不能符合immutable object的正常行为,请实现出深层克隆(deep cloning)
immutable object提供了极具价值的服务。由于他们保证自己的状态从构建之后就一定不再改变。因此他们天生具备多线程安全性。所以我们可以不必对它进行同步控制,这样可能能够提高些性能。但是实现immutable object时你必须实现clone(克隆)功能,而其代价可能不小。
要将一个类变成immutable是要通过多方面的合作才可能造就不变性:
1 将class中的所有数据声明为private。
2 只提供取值函数(getter),不提供设值函数(setter)。
3 声明class为final。
4 从获取器返回references to mutable object之前,先克隆(cloning)那些mutable object。
5 将传递给构造函数的reference to mutable object先clone
6 在构造函数中设定class内含的所有数据。
final class PinNumbers{
private String acctowner;
private int checkingApptPin;
private int savingsAcctPin;
PinNumbers(String owner,int cPin,int sPin){
acctOwner = owner;
checkingAccPin = cPin;
savingsAcctPin = sPin;
}
public String accountOwner(){
return acctOwner;
}
public int chechingPin(){
return chechingAcctPin;
}
public int savingsPin(){
return savingsAcctPin;
}
}
这个class不需要克隆(clone)任何数据,因为其构造函数所接受的,或其取值函数(getter)所返回的,都只是基本类型和 reference to immutable object。基本类型不是对象,String class是恒常不变的,所以也不需要对它进行clone。
public class User {
private String userName;
private String userID;
private int userNode;
public User(String userName, String userID, int userNode)
{
this.userName = userName;
this.userID = userID;
this.userNode = userNode;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String getUserName()
{
return userName;
}
public void setUserID(String userID)
{
this.userID = userID;
}
public String getUserID()
{
return userID;
}
public void setUserNode(int userNode)
{
this.userNode = userNode;
}
public int getUserNode()
{
return userNode;
}
}
public final class DiskDriveInfo {
private int driveSize;
private String volumeLabel;
private User driveShare;
DiskDriveInfo(int size, String volLabel,User share)
{
driveSize = size;
volumeLabel =volLabel;
driveShare = share;
}
public int size()
{
return driveSize;
}
public String label()
{
return volumeLabel;
}
public User share()
{
return driveShare;
}
}
上述DiskDriveInfo并不是immutable,因为在DiskDriveInfo可能改变user的值,例如:
public class ImmutableTest {
public static void main(String[] args)
{
User user = new User("AAA", "04308032", 10001);
DiskDriveInfo info = new DiskDriveInfo(32, "mutable", user);
System.out.println(info.share().getUserName());
user.setUserName("BBB");
System.out.println(info.share().getUserName());
}
}
上述代码的输出为:
AAA
BBB
想要将DiskDriveInfo类实现为immutable, 首先必须为User类实现clone()方法:
public class User implements Cloneable{
private String userName;
private String userID;
private int userNode;
public User(String userName, String userID, int userNode)
{
this.userName = userName;
this.userID = userID;
this.userNode = userNode;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String getUserName()
{
return userName;
}
public void setUserID(String userID)
{
this.userID = userID;
}
public String getUserID()
{
return userID;
}
public void setUserNode(int userNode)
{
this.userNode = userNode;
}
public int getUserNode()
{
return userNode;
}
public Object clone()
{
try {
User copy = (User)super.clone();
return copy;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
然后将DiskDriveInfo类的定义修改为:
public final class DiskDriveInfo {
private int driveSize;
private String volumeLabel;
private User driveShare;
DiskDriveInfo(int size, String volLabel,User share)
{
driveSize = size;
volumeLabel =volLabel;
driveShare = (User)share.clone();
}
public int size()
{
return driveSize;
}
public String label()
{
return volumeLabel;
}
public User share()
{
return (User)driveShare.clone();
}
}
结果上述测试代码的输出将变成:
AAA
AAA
假如DiskDriveInfo类里面的不是一个user对象 而是一个Vector,里面保存了许多user对象。难道时调用Vector里面的clone()吗?可惜Vector克隆的不是整个的对象树,而是克隆了一个Vector但是里面的指向的user对象还是以前那个user对象的。这时候我们就需要深层克隆(Deep Cloning)
如:
class ShareVector extends Vector{
ShareVector(int Size){
super(size);
}
public Object clone(){
ShareVector v = (ShareVector)super.clone();
int size = size();
for(int i=0;i<size;i++){
User u = (User)(this.get(i));
v.setElementAt((User)(u.clone()),i);
}
return v;
}
}
或者在DiskDriveInfo中提供一个cloneVector(Vector)的方法好了。
private Vector cloneVector(Vector v){
int size = v.size();
Vector newVector = new Vector();
for(int i=0;i<size;i++){
newVector.add((User)(v.get(i)).clone));
return newVector;
}
}
总而言之,在实现了一个immutable class(不可变类)时,请遵守下列规则。
1、声明这个class为final。
2。声明所有的数据为private。
3。只提供取值函数(getter),不提供设值函数(setter)。
4、在构造函数中设置所有的instance数据。
5、如果函数返回references to mutable objects,请先克隆那些mutable objects。
6、如果函数接受references to mutable objects,请先克隆那些mutable objects。
7、如果缺省之浅层克隆(shallow clone)不能符合immutable object的正常行为,请实现出深层克隆(deep cloning)