不变模式

不变模式就是为了尽可能的去除并行中的同步操作,提高并行程序的性能,可以使用一种不可改变的对象,依靠对象的不变性,可以确保其在没有同步操作的多线程环境中依然始终保持内部状态的一致性和正确性。并且,不变模式通过回避问题而不是解决问题的态度来处理多线程并发访问控制。

不变模式的主要使用场景

  • 当对象创建后,其内部状态和数据不再发生任何变化。
  • 对象需要被共享,被多线程频繁访问。

不变模式的实现(保证当对象被创建后,不发生任何改变)

  1. 去除setter方法以及所有修改自身属性的方法。
  2. 将所有属性设置为私有,并用final标记,确保不能被修改
  3. 确保没有子类可以重载
  4. 有一个可以创建完整对象的构造函数

对于第四点,在创建对象时,必须指定完整的数据,因为创建后,就无法进行修改了

eg:

public final class Book {
private final String name;
private final String ID; public Book(String name,String ID) {
this.name=name;
this.ID=ID;
}
public String getName() {
return name;
}
public String getID() {
return ID;
}
}

在不变模式中,final关键字起到了重要的作用。

  • 对属性的final定义确保所有数据只能在对象被构造时赋值一次,之后,就永远不发生改变。
  • 对class 的final确保了类不会有子类

注:根据里式原则,子类可以完全的替代父类。如果父类是不变的,那么子类也必须是不变的,但实际上为了防止子类做出一些意外的行为,这里干脆就把子类禁用了

关于String中的不变模式

在JDK中,不变模式有很多应用,如Integer,Long等所有元数据类的包装类,当然,最典型的就是String类了。

对于String类而言,内部是这样定义的:public final class String  是一个被final关键字修饰的类,我们来看看上面说到final关键字的作用,这就意味着:

  1. String中的数据只能在String对象被构建时赋值,之后就永远不能改变
  2. String类不会有子类重载它的方法,也确保了String类生成的对象就是String对象,而不可能是其他类的对象

为什么String要被设计成不变模式呢?

很明显,当然是为了安全

先看到String源码中的如何赋值的

    /** The value is used for character storage. */
private final char value[];

注释部分说的很明白,它是用一个final的字符数组来储存字符串的。

虽然value是不可变,但只是value这个引用地址不可变。但是Array数组是可变!!!

因为Array变量只是stack上的一个引用,数组的本体结构在堆。如图:

String类里的value用final修饰,只是说stack里的这个叫value的引用地址不可变。没有说堆里array本身数据不可变。

eg:

 final char value[]={'a','b','c'};
char value2[]={'d'};
//value=value2; //编译器报错,因为用了final修饰
value[0]='d';
for (char v : value) {
System.out.print(v);//输出 dbc
}

很明显,这个value虽然被声明成final,但是如果value溢出了,就很容被修改了。

幸好,在设计String 的时候,value不仅是final的,而且还是private的,并且在后面所有String的方法里很小心的没有去动Array里的元素,没有暴露内部成员字段。

再者,String基本约定中最重要的一条是immutable。String是几乎每个类都会使用的类,所以保护String的不可变很重要,所以整个String类被设成final,从而实现禁止继承,避免被其他人继承后破坏。

假如String没有声明为final, 那么String的子类就有可能是被复写为mutable的,这样就打破了成为共识的基本约定。并且会造成不可想象的后果,

如,Hashmap之类的集合的key值,mutable的String有非常大的风险,可能会破坏了Hashmap键值的唯一性等。

安全之外,还可以涉及到性能方面:

String在堆中维护着一个字符串常量池。如字符串one和two都赋值为"something"。它们其实都指向同一个内存地址。

String one = "someString";
String two = "someString";

这样在大量使用字符串的情况下,可以节省内存空间,提高效率。

More:

Why String is Immutable or Final in Java

 

关于String中的不变模式的更多相关文章

  1. Java的String中的subString()方法

    方法如下: public String substring(int beginIndex, int endIndex) 第一个int为开始的索引,对应String数字中的开始位置, 第二个是截止的索引 ...

  2. Here String 中不该进行分词

    我们知道,在 Shell 中,一个变量在被展开后,如果它没有被双引号包围起来,那么它展开后的值还会进行一次分词(word splitting,或者叫拆词,分词这个术语已经被搜索引擎相关技术占用了)操作 ...

  3. C++string中有关字符串内容修改和替换的函数浅析

    1.assign() 原型: //string (1) basic_string& assign (const basic_string& str); //substring (2) ...

  4. 从源代码的角度聊聊java中StringBuffer、StringBuilder、String中的字符串拼接

    长久以来,我们被教导字符串的连接最好用StringBuffer.StringBuilder,但是我们却不知道这两者之间的区别.跟字符串相关的一些方法中总是有CharSequence.StringBuf ...

  5. Java-J2SE学习笔记-查找一个String中,subString的出现次数

    1.查找一个String中,subString的出现次数 2.代码 package Test; public class TestStringContain { public static void ...

  6. string中常用的函数

    string中常用的函数 发现在string在处理这符串是很好用,就找了一篇文章放在这里了.. 用 string来代替char * 数组,使用sort排序算法来排序,用unique 函数来去重1.De ...

  7. String 中的秘密

    Navigation:  数据类型相关 > Delphi 的字符及字符串 > [3] - String 中的秘密   //String 的指针地址及实际的内存地址 var str: str ...

  8. String中的==与Empty

    1.String中的==与Equals方法执行结果一样吗? 我们都知道对于引用类型"=="比较的是引用而不是具体的值,但c#中有一种神奇的叫做操作符重载的东西.官方对String类 ...

  9. Java 字符串比较,String 中的一些方法 == 和 equals 的详解

    "==" 是比较的是两个对象的内存地址,而equals方法默认情况下是比较两个对象的内存地址. 1.String str = "hello"  生成的字符串,首 ...

随机推荐

  1. 张高兴的 Windows 10 IoT 开发笔记:BMP180 气压传感器

    注意:海拔高度仅供参考 GitHub : https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/BMP180Demo

  2. win10 uwp 截图 获取屏幕显示界面保存图片

    本文主要讲如何保存我们的屏幕显示的,保存为图片,也就是截图,截我们应用显示的. UWP有一个功能,可以截图,RenderTargetBitmap 我们首先写一个Grid,我们需要给他名字,我这里给他S ...

  3. Vue directive 回调运用

    Vue的官方自定义directive,基本调用简洁如下: Vue.directive('my-directive', { bind: function () {},// 指令与被绑定元素第一次绑定时触 ...

  4. 快速排序算法分析--C++版

    快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试喜欢考这个. 快速排序是C.R.A.Hoar ...

  5. ELK系列~Nxlog日志收集加转发(解决log4日志换行导致json转换失败问题)

    本文章将会继承上一篇文章,主要讲通过工具来进行日志的收集与发送,<ELK系列~NLog.Targets.Fluentd到达如何通过tcp发到fluentd> Nxlog是一个日志收集工具, ...

  6. JPA之helloWorld

    在 Eclipse 下创建 JPA 工程 1.在eclipse上安装JPA插件(网上自行百度) 2.new 一个Jpa工程 3:点击下一步,下一步,第一次运行jpa插件会让我们装相关类库如下图,等到再 ...

  7. MySql sql按时间分组

    select DATE_FORMAT(f.upload_time,'%Y%u') weeks,count(*),sum(p.download_times),sum(p.collection_times ...

  8. LeetCode 538. Convert BST to Greater Tree (把二叉搜索树转换成较大树)

    Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original B ...

  9. CNCC2017梳理

    大牛云集的中国计算机大会:大会日程表:http://cncc.ccf.org.cn/cn/news/schedule_empty 早上的论坛可以在爱奇艺下载视频 下午的分论坛是多个同时进行的,我也只去 ...

  10. Lua与javascript的差异

    Lua与javascript的差异 2010-03-08 Lua模拟器js方案 1.语法级模拟 lua与js语言差异 1.1注释 js 为//,lua为--. 1.2变量 js利用var来声明全局变量 ...