String的不可变性
来源:互联网 发布:中国影子银行规模数据 编辑:程序博客网 时间:2024/06/10 03:40
String的不可变性
首先明确一点,String类被声明为final与String对象是immutable的没有必然的联系。
那么为什么说String对象是不可变的呢?
1、 我们知道String实现依靠的是char[], 那么首先看下String源码:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];
在程序内部这个数组被声明为private的,同时是个final的。
Private可以保证value数组不被调用者访问到,final可以确保数组的地址是不变的。
注意,声明数组为final的时仅仅可以保证数组的地址是不变的,并不能保证数组里面的值不变。
请看下面的例子:
总结:内部的value数组被声明为private,确保了value的值不会被外部程序改变。
2、 String类被声明为final的,它的意义是什么呢?
我们知道,类被声明为final的时候,这个类是不可以为继承的,这样就不能修改这个类里面的方法实现。
比方说如果String类可以被继承。那么我们就可以写一个方法去改变value数组,比如:
//改变value数组public void setChar(char c , int index){ value[index] = c;}//或者直接去改变String对象: public static StringBuilder append(StringBuilder stringBuilder){ return stringBuilder.append("122"); }
3、 String对象的不可变的好处
(1)以set为例
@Test public void test3() { Set<StringBuilder> stringBuilders = new HashSet<StringBuilder>(); // StringBuilder类型的变量分别指向堆上的"a" 和"ab", StringBuilder stringBuilder = new StringBuilder("a"); StringBuilder stringBuilder1 = new StringBuilder("ab"); //将这两个变量放进HashSet中 stringBuilders.add(stringBuilder); stringBuilders.add(stringBuilder1); //创建一个新的StringBuilder stringBuilder2变量指向 stringBuilder 所在的地址 StringBuilder stringBuilder2 = stringBuilder; //在stringBuilder2上追加一个字符串"b", // 注意:由于StringBuilder是可变的,此时会改变stringBuilder的值 //此时会导致Set上出现两个相等的值,从而破坏了HashSet的键值唯一性 stringBuilder2.append("b"); stringBuilders.add(stringBuilder2); }
(2)String的不可变性确保了线程安全。在并发场景下,对共享资源的写操作会引发静态条件,只有对资源进行写操作才引发资源状态的不一致,而不可变对象不可写,因此是线程安全的。
总结:String类通过将类设置为final来确保类不会被继承,从而可以保证方法不被覆盖,因此确保了String类的所有方法都唯一被SUN的工程师设计和控制。我们在使用的过程中需要注意,千万不要用可变类型做HashMap和HashSet键值,在使用自定义的对象作为键值的时候,一定要重写HashCode和Equals方法。
4、 上面讲过了String类不可以被外部修改,那么如果在内部被修改的话,同样不能保证是immutable的。
现在来看内部是如何保证String对象不可变的
首先:我们知道String是一个引用类型,如果对它本身进行修改是不需要返回的,通过观察源码可以发现,任何写操作都会返回一个新的String对象。
例如replace方法:
public String replace(char oldChar, char newChar) { if (oldChar != newChar) { int len = value.length; int i = -1; char[] val = value; /* avoid getfield opcode */ while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true); } } return this; }
总结:因为在String类的内部,程序员巧妙的保证了String的不可变,即:任何对String的写操作,都是返回新的String对象
总结:
综上:
String不可变的原因:
防止被外部改变:
(1) 类设计为final的,确保类不被继承,方法不被覆盖
(2) 内部实现上用的是private final的数组
内部实现上避免改变原字符串:
(1) 任何对String的写操作都不是在原来的字符串上进行的修改,而是创建的新对象
好处:
(1) 线程安全
(2) 在使用String作为HashMap和HashSet的key时,可以确保键值唯一性
- String的不可变性
- String的不可变性
- String的不可变性
- String的不可变性
- String类的不可变性
- String 类的不可变性
- String对象的不可变性
- String类不可变性的好处
- String 的相等性和不可变性
- java之String对象的不可变性
- c#之string的不可变性2
- String类不可变性的好处
- String类不可变性的好处
- String类不可变性的好处
- 图解Java String不可变性
- 字符串的不可变性
- 字符串的不可变性
- String 的共享行和不可变性的理解.
- NSRunloop
- netty4&5私有协议开发
- 关键字'table'附近有语法错误
- springMVC中日期格式转换问题
- eclipse之The currrently displayed page contains invalid values错误
- String的不可变性
- C++ Primer(第五版)练习6.27
- hrbust 1705 最高分【Dp】
- C#语言与面向对象技术(2)
- 浅谈算法和数据结构(11):哈希表
- 分治算法
- 10、Java入门—集合框架(下)
- 自定义摇杆控件
- 安卓博客资源分享