String 和 Stringbuild
Posted benjious
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了String 和 Stringbuild相关的知识,希望对你有一定的参考价值。
什么是不可变类
下面这段来自[java中的不可变类](https://www.cnblogs.com/zhiheng/p/6653969.html)
先来看一下可变类和不可变类。
-
不可变类(Immutable Objects):当类的实例一经创建,其内容便不可改变,即无法修改其成员变量。
-
可变类(Mutable Objects):类的实例创建后,可以修改其内容。
不可变类的优势 :
- 效率
当一个对象是不可变的,那么需要拷贝这个对象的内容时,就不用复制它的本身而只是复制它的地址,复制地址(通常一个指针的大小)只需要很小的内存空间,具有非常高的效率。同时,对于引用该对象的其他变量也不会造成影响。 此外,不变性保证了hashCode 的唯一性,因此可以放心地进行缓存而不必每次重新计算新的哈希码。而哈希码被频繁地使用, 比如在hashMap 等容器中。将hashCode 缓存可以提高以不变类实例为key的容器的性能。
- 线程安全
在多线程情况下,一个可变对象的值很可能被其他进程改变,这样会造成不可预期的结果,而使用不可变对象就可以避免这种情况同时省去了同步加锁等过程,因此不可变类是线程安全的。
在《java concurrency in practice》一书给出了一个粗略的定义:对象一旦创建后,其状态不可修改,则该对象为不可变对象。一般一个对象满足以下三点,则可以称为是不可变对象:
- 其状态不能在创建后再修改;
- 所有域都是final类型;
- 其构造函数构造对象期间,this引用没有泄露。
String 为什么是不可变类
例子
String s= "abcd"; s = "abcdel";
底层
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; .... }
可以看到String 维护的 char数组是private final 的。假如我们要是可以修改char里的内容那么,String 肯定就不是不可变类了,例如下面这种操作。
final int[] value={1,2,3} value[2]=100; //更改了第三个元素的值
** 但是String中没有提供方法对char 数组进行更改,所以String这个字符串保证了不可变。 **
String 作为不可变类安全优势的例子
public final class Fa { private int num; public static String stringAdd(String s){ s += "bbb"; return s; } public static StringBuilder stringBAdd(StringBuilder s){ s .append("bbb"); return s; } public Fa(int num) { this.num = num; } } String s = "s1"; String result = Fa.stringAdd(s); System.out.println("result : " + s); StringBuilder sb = new StringBuilder("sb"); String sbResult = Fa.stringBAdd(sb).toString(); System.out.println("sbResult : " + sb); 结果 : result : s1 sbResult : sbbbb
所以我们建议在当大量使用是字符串的时候使用 stringbuild 可以提高性能,不然新创建的String 对象会占用堆空间,可能导致频繁GC。
真的是不可变类吗
实际可以通过反射来获取char数组,从而知道了String的值,这也是很多开发中密码这类属性不建议使用String而是使用char数组的原因。当然开发中很少使用反射去这样获取。
补充
final 关键字
修改变量
final修饰常量必须为常量赋初始化值,例如 :
public class Fa { private int num; //编译出错 private final int finalTest; //编译出错 private final Zi zi; public Fa(int num) { this.num = num; } }
修饰 class
修饰某个class 则是不能被继承
修改对象
修饰对象则不能更改引用,什么意思呢?
final Fa f3 = new Fa(3); //编译出错 f3 = new Fa(4);
参考资料
- https://www.cnblogs.com/zhiheng/p/6653969.html
- https://www.zhihu.com/question/20618891/answer/114125846
以上是关于String 和 Stringbuild的主要内容,如果未能解决你的问题,请参考以下文章
StringStringBuffer和StringBuild
StringStringBuffer和StringBuild
JAVA 参数的 值传递和引用传递(特殊的String 和 StringBuild)
JAVA 参数的 值传递和引用传递(特殊的String 和 StringBuild)