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)

有关string stringbuff stringbuild 的区别

String,StringBuffer,StringBuild的区别