不变模式

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

不变模式的主要使用场景

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

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

  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. Latex 论文elsevier,手把手如何用Latex写论文

    这几天在开始写论文,准备发的是elsevier,这个网站的instruction有问题,下载的东西基本上好多的错误,所以我就写博客记录. 首先看下:https://www.elsevier.com/a ...

  2. win10 & Ubuntu16 双系统安装

    忽然心血来潮吧,本机在已经安装了win10的背景下,想要再加一个linux系统学习学习,几经波折,终于成功. 博主笔记本里有两块固态,一个250G的装了win10,装的时间不久,镜像是在msdn上下载 ...

  3. GTK主题黑边问题

    Linux就是这样,上游一出点什么奇怪的变动,下游程序就要受影响..最近滚了一下后,不知道mesa还是xf86-intel-video哪个玩了什么新花样,所有gtk应用[主要是gnome组件]全部自带 ...

  4. Ajax中与服务器的通信【发送请求与处理响应】

    一.发送请求 Ajax中通过XMLHttpRequest对象发送异步方式的后台请求时.通常有两种方式的请求,一种是GET请求,另一种是POST请求.发送请求一般要经过4个步骤分别是: (1)初始化XM ...

  5. 快速部署PostgreSQL

    PostgreSQL通常也简称Postgres,是一个关系型数据库管理系统,适用于各种Linux操作系统.Windows.Solaris.BSD和Mac OS X.本文基于CentOS7,使用yum源 ...

  6. Python学习之二:Python 与 C 区别

    引自http://www.lxway.com/181844.htm 从开始看Python到现在也有半个多月了,前后看了Python核心编程和Dive into Python两本书.话说半个月看两本,是 ...

  7. Oracle 表空间扩充

    Oracle 表空间扩充 一.现场环境: (1)操作系统:AIX (2)数据库:Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - ...

  8. T9

    T9 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission ...

  9. Uncle Tom's Inherited Land*

    Uncle Tom's Inherited Land* Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...

  10. 使用javascript编写根据用户鼠标控制背景图片的移动

    在一家VR公司做前端. 起初进入前端就是一种内心的直觉,创造更好的用户体验,让页面更加友好,当然最起初接手web项目还是为了完成毕业设计. 一个网上图书商城,虽然不大,但五脏都有毕竟开刀所以避免不了很 ...