不可变对象

如果一个对象的状态在构造后不能改变,则该对象被认为是不可变的,对不可变对象的最大依赖被广泛认为是一种创建简单、可靠代码的合理策略。

不可变对象在并发应用程序中特别有用,由于它们不能改变状态,因此它们不会被线程干扰破坏或在不一致的状态下观察。

程序员通常不愿意使用不可变对象,因为他们担心创建新对象的成本而不是就地更新对象的成本,对象创建的影响经常被高估,并且可以通过与不可变对象相关联的一些效率来抵消,这些包括由于垃圾收集而减少的开销,以及消除保护可变对象免于损坏所需的代码。

以下小节采用其实例可变的类,并从中派生出具有不可变实例的类,通过这样做,它们为这种转换提供了一般规则,并演示了不可变对象的一些优点。

同步类示例

SynchronizedRGB类定义了表示颜色的对象,每个对象将颜色表示为代表主要颜色值的三个整数和一个给出颜色名称的字符串。

public class SynchronizedRGB {// Values must be between 0 and 255.private int red;private int green;private int blue;private String name;private void check(int red,int green,int blue) {if (red < 0 || red > 255|| green < 0 || green > 255|| blue < 0 || blue > 255) {throw new IllegalArgumentException();}}public SynchronizedRGB(int red,int green,int blue,String name) {check(red, green, blue);this.red = red;this.green = green;this.blue = blue;this.name = name;}public void set(int red,int green,int blue,String name) {check(red, green, blue);synchronized (this) {this.red = red;this.green = green;this.blue = blue;this.name = name;}}public synchronized int getRGB() {return ((red << 16) | (green << 8) | blue);}public synchronized String getName() {return name;}public synchronized void invert() {red = 255 - red;green = 255 - green;blue = 255 - blue;name = "Inverse of " + name;}
}

必须小心使用SynchronizedRGB以避免在不一致的状态下被查看,例如,假设一个线程执行以下代码:

SynchronizedRGB color =new SynchronizedRGB(0, 0, 0, "Pitch Black");
...
int myColorInt = color.getRGB();      //Statement 1
String myColorName = color.getName(); //Statement 2

如果另一个线程在语句1之后但在语句2之前调用color.set,则myColorInt的值将与myColorName的值不匹配,为了避免这种结果,必须将两个语句绑定在一起:

synchronized (color) {int myColorInt = color.getRGB();String myColorName = color.getName();
} 

这种不一致只适用于可变对象 — 对于不可变版本的SynchronizedRGB,它不会是一个问题。

一种定义不可变对象的策略

以下规则定义了用于创建不可变对象的简单策略,并非所有记录为“不可变”的类都遵循这些规则。这并不一定意味着这些类的创造者是草率的 — 他们可能有充分的理由相信他们类的实例在构造后永远不会改变,但是,这种策略需要复杂的分析,不适合初学者。

  1. 不要提供“setter”方法 — 修改字段或字段引用的对象的方法。
  2. 使所有字段为finalprivate
  3. 不允许子类重写方法,最简单的方法是将类声明为final,更复杂的方法是使构造函数为private并在工厂方法中构造实例。
  4. 如果实例字段包含对可变对象的引用,则不允许更改这些对象:

    • 不要提供修改可变对象的方法。
    • 不要共享对可变对象的引用,永远不要存储对传递给构造函数的外部可变对象的引用,如有必要,创建副本并存储对副本的引用,同样,必要时创建内部可变对象的副本,以避免在方法中返回原始对象。

将此策略应用于SynchronizedRGB会导致以下步骤:

  1. 这个类中有两个setter方法,第一个方法set,任意改变对象,在类的不可变版本中不存在,第二个方法invert,可以通过让它创建一个新对象而不是修改现有对象来进行调整。
  2. 所有字段都已为private,他们进一步获得final
  3. 该类本身被声明为final
  4. 只有一个字段引用一个对象,该对象本身是不可变的,因此,不需要防止改变“包含的”可变对象的状态的保护措施。

在这些更改之后,我们有ImmutableRGB:

final public class ImmutableRGB {// Values must be between 0 and 255.final private int red;final private int green;final private int blue;final private String name;private void check(int red,int green,int blue) {if (red < 0 || red > 255|| green < 0 || green > 255|| blue < 0 || blue > 255) {throw new IllegalArgumentException();}}public ImmutableRGB(int red,int green,int blue,String name) {check(red, green, blue);this.red = red;this.green = green;this.blue = blue;this.name = name;}public int getRGB() {return ((red << 16) | (green << 8) | blue);}public String getName() {return name;}public ImmutableRGB invert() {return new ImmutableRGB(255 - red,255 - green,255 - blue,"Inverse of " + name);}
}

上一篇:守护阻塞

Java™ 教程(不可变对象)相关推荐

  1. java中不可变对象(immutable object)是什么,有什么意义

    不可变对象顾名思义不可改变的对象 一旦构造器完成执行,该实例即无法改变 意味着可以传递对象的引用,不用担心改变其内容,特别是在处理并行时,不可变对象不存在锁的问题,易于构造使用 final class ...

  2. 如何优雅的创建一个Java不可变对象类,JDK源码中也是这么干的!

    前面有篇文章当介绍了Java的不可变对象的一些特性,以及它的一些好处,但是并没有介绍如何实现一个不可变对象类.今天就来看看如何实现一个不可变对象类. Java中常用的不可变对象类 String类应该是 ...

  3. java创建一个不可变对象_如何在Java中创建不可变类?

    java创建一个不可变对象 Today we will learn about the immutable class in Java. What are immutable classes? The ...

  4. [Java教程]15.实现可变数组与时间类的使用

    Java教程专栏:https://blog.csdn.net/qq_41806966/category_9929686.html hello,I'm shendi 本节将使用数组实现一个类便于使用,以 ...

  5. python基础教程:对可变对象和不可变对象的详解

    数据类型分为可变.不可变.可变对象表示可以原处修改该数据对象,不可变对象表示必须创建新对象来保存修改后的数据. 在基础数据类型中: 数值.字符串.元组.frozenset是不可变对象 列表.set.d ...

  6. java高并发(八)不可变对象

    有一种对象一旦发布了,那么他就是安全对象,这就是不可变对象. 不可变对象需要满足的条件: 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没 ...

  7. 使用可变对象作为Java Map的key,会带来潜在风险的一个例子

    package hashMap;import java.util.HashMap; import java.util.Map;/* * 可变对象是指创建后自身状态能改变的对象.换句话说,可变对象是该对 ...

  8. java属于面相_[Java教程]面相对象

    [Java教程]面相对象 0 2018-09-13 16:00:26 面向对象 那什么是面向对象? 在Java 中,我们是一切皆对象,所有的方法都是围绕着对象来的.面相对象是相对面向过程而来的,他们都 ...

  9. java创建一个不可变对象_使用不可变对象创建值对象

    java创建一个不可变对象 在回答我最近的文章中AutoValue:生成的不可变的值类 , 布兰登认为,这可能是有趣的,看看如何AutoValue比较项目Lombok和Immutables和凯文借调这 ...

最新文章

  1. SQL Server-聚焦WHERE Column = @Param OR @Param IS NULL有问题?
  2. 单片机位寻址举例_单片机学习:51单片机寻址方式详解
  3. mysql 排序字段索引吗_Mysql 排序优化与索引使用(转)
  4. Macbook换SSD硬盘 备份OS、Win10双系统 完全攻略
  5. html返回按钮 超链接,ppt中怎么添加超链接返回按钮
  6. 【DIY分享】示波器(原理图+源码+仿真)
  7. AR5B22网卡折腾记录
  8. 计算机桌面出现蓝色底色,电脑桌面图标有蓝色阴影 - 电脑桌面图标有蓝底怎么办 - 安全专题...
  9. Python证件照背景自定义改色,带Tkinter界面,代码全文解释!
  10. Github骚操作绑定中国+86手机号码实现两步验证
  11. C++常见的预定义宏
  12. 网络电视盒子用OTT TV系统定制3大关键问题
  13. windows10录屏快捷键是什么
  14. 企业责任彰显品牌价值,EBC金融集团助力投资者财富增值
  15. 腾讯地图InfoWindow太大
  16. 向量组等价、矩阵等价与方程组可互推的关系
  17. 皮尔兹继电器774730 PNOZ X4 24VDC 3n/o 1n/c
  18. hough森林 matlab,霍夫变换(Hough
  19. Cap26_知识产权与标准规范
  20. Python神经网络编程(一)之神经网络如何工作

热门文章

  1. php的ftp怎么代理访问,利用PHP登陆FTP实现服务器资源同步 | Lancer's Blog
  2. 前端自动化测试概览【超全面介绍】包你学废
  3. websocket python unity_Unity 连接WebSocket(ws://)服务器
  4. 字符串反转python 测试_Python中的反转字符串问题
  5. 求数组中最长连续递增子序列
  6. 聊一聊使用airtest-selenium做Web自动化的常见问题
  7. mysql删除myisam表数据影响_Mysql 下 Myisam表delete 后 数据恢复问题
  8. oracle进行日志切换,Oracle存档日志切换案例操作
  9. FaceWarehouse: a 3D Facial Expression Database for Visual Computing
  10. 常见面试算法:k-近邻算法原理与python案例实现