String、StringBuffer、StringBuild

String

public final class String implements java.io.Serializable, Comparable<String>, CharSequence
存储用的是数组,也就是数String的底层是数组,也使用了final修饰
private final char value[];

final 修饰的,final是最终形态,是不可变的,所以String是不可变的
如:

 private static StringBuffer appendStr(StringBuffer str) {
        return str.append("DEMO");
    }

    public static void main(String[] args) {
        String str = new String("STR-");
        String s = appendStr(str);
        System.out.println(s);
        System.out.println(str);

        StringBuilder bul = new StringBuilder("BUL");
        StringBuilder stringBuilder = appendStr(bul);
        System.out.println(bul);
        System.out.println(stringBuilder);

        StringBuffer buf = new StringBuffer("BUF");
        StringBuffer newbuf = appendStr(buf);
        System.out.println(buf);
        System.out.println(newbuf);
    }
结果:
STR-TEST
STR-
BULDEMO
BULDEMO
BUFDEMO
BUFDEMO

str的值没有受到影响,而StringBuild的结果发生了变化。
String 在创建新的对象的时候都会在内存中开辟一块空间给对象,在发生引用变化的时候只是引用指向发生了变化,不会影响原有的数据
-----------------------------------------------------------------------------------
如果说String是可变的会有什么影响?
一般来说,系统中所有用到的key包括spring三级缓存中的key都是string类型的,redis的key也是string类型的,项目中的Map也都是String类型的,一旦发生可变就会导致键值的唯一性。整个系统就没有了意义。

StringBuild

public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
同样实现了序列化和字符序列,只是多了父级AbstractStringBuilder

StringBuffer

public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
继承和实现与StringBuild一致,只是所有的方法都添加了synchronized关键字

它们三个类底层都是数组: char[] value;
StringBuffer 是线程安全的,但是效率低。
StringBuild 是非线程安全的,但是效率高。
String 是不可变的,每实例化一次就要在内存中开辟空间,所以在字符拼接的时候尽量使用StringBuffer 或者StringBuild,如果涉及到线程安全的话那就使用StringBuffer

== 和 equals()

== 常用于基本类型的数据比较,比较值是否相等
equals 常用于包装类型的比较,首先比较值是否相等也就是 使用了==, == 返回的结果是true则直接返回true,否则判断数据类型是否一致,使用了 instanceof,如果类型一致,则匹配长度是否一致,如果一致则继续匹配,使用循环匹配所比较的参数的每一个值是否 ==
以String为例:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

而Object的equals 更粗暴,更多的细节需要子类去重写,如果不重写的情况下,默认是使用Object 的这个,所以这个时候 == 跟equals是没有区别的了,上边String的重写就是一个例子

public boolean equals(Object obj) {
   return (this == obj);
}

String s1 = “ABC”;
String s2 = new String(“ABC”);
这种情况下 == 是 false,但是equals是true
他们所在位置是不一样的,s1是在常量池中的,s2的实例是在堆中的,所以 == 是失败的,s1 == s2.intern() 结果是成功的。看源码发现,intern会先从池中查看有没有,如果有就直接返回,否则,这个对象将被添加到并返回对该对象的引用


版权声明:本文为wdz985721191原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。