博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程学习系列 - 2 - Immutable Pattern
阅读量:4145 次
发布时间:2019-05-25

本文共 5613 字,大约阅读时间需要 18 分钟。

目录

先看看什么算是Immutable

immutable [i'mju:təbl](21世纪大英汉词典) adj.永远不变的;不可改变的;永恒的;无变化的

能够保证实例状态绝对不会改变的类,我们认为是immutable的

最常用的String就是immutable类

考虑下面Person类,看它是如何成为一个immutable类

它有属性String name和String address

public final class Person {	private final String name;	private final String address;	public Person(String name, String address){		this.name = name;		this.address = address;	}		public String getName(){		return name;	}		public String getAddress(){		return address;	}		public String toString(){		return "Person [name:" + name + "\t address:" + address + "]";	}}

类很简单,只有两个字段几个方法

首先Person非常凶猛,上场先挥刀自宫,把自己声明成final绝后,所以也就没有子类能修改父类属性的可能

然后把两个属性都声明为private,也就是说对外不可见,并且设置为final也禁止了set方法的再次赋值

至此Person功德圆满,成为了immutable类

ps:如果你使用反射,很遗憾,反射可以改变name和address的值,这里我们不考虑恶意改变,所以去除这种情况

测试代码如下

public static void main(String[] args) {	Person p = new Person("Alice", "Alaska");	System.out.println(p);;	Class
clazz = Person.class; try { Field feild = clazz.getDeclaredField("name"); feild.setAccessible(true); feild.set(p, "Bobby"); System.out.println(p); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }}

打印结果

Person [name:Alice     address:Alaska]

Person [name:Bobby     address:Alaska]

Immutable Pattern的参与者

一个字段值无法更改的类,也没有任何用来更改字段值的方法。当Immutable参与者的实例建立后,状态就完全不再变化

Immutable Pattern适用性

1.当实例产生后,状态不需要再改变时(原文为状态不再变化时,我觉得改成不需要再改变时会更好)

其实只将字段定义为private final并且没有set方法,也还是有可能是mutable类的,后面会给出例子,上面的Person确实是immutable的

2.实例需要共享,而且访问很频繁时

使用immutable类可以省去synchronized,性能会节省不少且不丧失安全性

标准类链接库里使用到的Immutable Pattern

下面只简单列举一些

java.lang.String

java.awt.Color

和基本类型的包装类

java.lang.Boolean

java.lang.Byte

java.lang.Character

java.lang.Double

java.lang.Float

java.lang.Integer

java.lang.Long

java.lang.Short

java.lang.Void

习题2.5

一个人设计的line,看看这个line是否为不可变类

public class Line {    private final Point startPoint;    private final Point endPoint;    public Line(int startx, int starty, int endx, int endy) {        this.startPoint = new Point(startx, starty);        this.endPoint = new Point(endx, endy);    }    public Line(Point startPoint, Point endPoint) {        this.startPoint = startPoint;        this.endPoint = endPoint;    }    public int getStartX() { return startPoint.getX(); }    public int getStartY() { return startPoint.getY(); }    public int getEndX() { return endPoint.getX(); }    public int getEndY() { return endPoint.getY(); }    public String toString() {        return "[ Line: " + startPoint + "-" + endPoint + " ]";    }}

Point类

public class Point {    public int x;    public int y;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    public int getX() { return x; }    public int getY() { return y; }    public String toString() {        return "(" + x + "," + y + ")";    }}

 这里我们先不考虑继承的问题,因为人家设计完了,没有其余的类了

那么看看这个line,所有字段都为private final,方法都是get并且返回int和String

我们来看看这个构造函数

public Line(Point startPoint, Point endPoint) {    this.startPoint = startPoint;    this.endPoint = endPoint;}

问题出在这个Point上

很容易看出,Point是可变的,line赋值之后Point改变了会怎样?很简单,line也被改变了

下面的代码证实了这点

public static void main(String[] args) {	Point s = new Point(1, 2);	Point e = new Point(3, 4);	Line line = new Line(s, e);	System.out.println(line);	e.x = 5;	System.out.println(line);}

 打印结果

[ Line: (1,2)-(3,4) ]

[ Line: (1,2)-(5,4) ]

成对出现的mutable与immutable

如果有这样一个对象,它的一部分属性是不可变的另一部分是可变的,可以明显的区分出来,那么我们可以考虑将它拆分为两个类

一个为immutable另一个为mutable

比如String和StringBuffer

我们在java源码中可以看到

现在来看看下面两个成对出现的类,他们是否有安全问题

习题2.6

public final class ImmutablePerson {    private final String name;    private final String address;    public ImmutablePerson(String name, String address) {        this.name = name;        this.address = address;    }    public ImmutablePerson(MutablePerson person) {        this.name = person.getName();        this.address = person.getAddress();    }    public MutablePerson getMutablePerson() {        return new MutablePerson(this);    }    public String getName() {        return name;    }    public String getAddress() {        return address;    }    public String toString() {        return "[ ImmutablePerson: " + name + ", " + address + " ]";    }}

public final class MutablePerson {    private String name;    private String address;    public MutablePerson(String name, String address) {        this.name = name;        this.address = address;    }    public MutablePerson(ImmutablePerson person) {        this.name = person.getName();        this.address = person.getAddress();    }    public synchronized void setPerson(String newName, String newAddress) {        name = newName;        address = newAddress;    }    public synchronized ImmutablePerson getImmutablePerson() {        return new ImmutablePerson(this);    }    String getName() {    // Called only by ImmutablePerson        return name;    }    String getAddress() { // Called only by ImmutablePerson        return address;    }    public synchronized String toString() {        return "[ MutablePerson: " + name + ", " + address + " ]";    }}

  题目很简单,和2.5基本一样

public ImmutablePerson(MutablePerson person) {    this.name = person.getName();    this.address = person.getAddress();}

 解释也和2.5一样,那么如何修改

在执行这个方法的时候,MutablePerson可能会改变,如何被改变,可以通过setPerson,setPerson使用了synchronized关键字,意为获得this的锁,那么我们只需也获取这个对象的锁,就可以保证setPerson和public ImmutablePerson(MutablePerson person)不会交叉执行了

代码如下

public ImmutablePerson(MutablePerson person) {	synchronized (person) {        this.name = person.getName();        this.address = person.getAddress();	}}

 这节内容较少,所以就不画图了

转贴请保留以下链接

本人blog地址

转载地址:http://oycti.baihongyu.com/

你可能感兴趣的文章
日志框架学习2
查看>>
SVN-无法查看log,提示Want to go offline,时间显示1970问题,error主要是 url中 有一层的中文进行了2次encode
查看>>
NGINX
查看>>
Qt文件夹选择对话框
查看>>
1062 Talent and Virtue (25 分)
查看>>
1061 Dating (20 分)
查看>>
1060 Are They Equal (25 分)
查看>>
83. Remove Duplicates from Sorted List(easy)
查看>>
88. Merge Sorted Array(easy)
查看>>
leetcode刷题191 位1的个数 Number of 1 Bits(简单) Python Java
查看>>
leetcode刷题198 打家劫舍 House Robber(简单) Python Java
查看>>
NG深度学习第一门课作业2 通过一个隐藏层的神经网络来做平面数据的分类
查看>>
leetcode刷题234 回文链表 Palindrome Linked List(简单) Python Java
查看>>
NG深度学习第二门课作业1-1 深度学习的实践
查看>>
Ubuntu下安装Qt
查看>>
Qt札记
查看>>
我的vimrc和gvimrc配置
查看>>
hdu 4280
查看>>
禁止使用类的copy构造函数和赋值操作符
查看>>
C++学习路线
查看>>