备注

记录刷题和学习过程中所遇到的java中关于string的知识点。

1. 如何理解String是不可变的,为什么设计成不可变的

参考热心网友,表示感谢
String是字符串常量,而StringBuffer和StringBuilder是字符串变量。由String创建的字符内容是不可改变的,而由StringBuffer和StringBuidler创建的字符内容是可以改变的。这里的什么是不可改变,在第二个问题中会有解答。

关于String是不可变的,怎么理解:

转载作者昨夜星辰_zhangjg,把自己理解的写出来
书上的解释是: 对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化。

String s = "ABCabc";
System.out.println("s = " + s);

s = "123456";
System.out.println("s = " + s);
//打印结果
//s = ABCabc
//s = 123456

你看String不是被改变了么?其实次s非彼s,它只是一个对象的引用,实际的"ABCabc"这个字符串对象,已经被创立里,也无法去修改它内部的值,打印结果不同只是因为,s又指向新的对象了。

在JDK1.7的源码中,可以发现,内部的成员对象都是private final的,无法修改的,一旦初始化了, 也不能被改变。所以可以认为String对象是不可变的了。

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
    ...省略
}

为什么设计成不可变:

  1. 字符串常量池的需要,编译器会优化变量内存,一样的字符串会统一放在 string pool 中,这样能节约 heap 空间。

  2. 安全性,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。

  3. 允许String对象缓存HashCode, 字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存.这也是一种性能优化手段,意味着不必每次都去计算新的哈希码.

好处是什么?:

  1. 字符串池才有可能实现
  2. 安全
  3. 适合做HashMap中的键,因为在它创建的时候hashcode就被缓存了,不需要重新计算

2. String vs StringBuffer vs StringBuilder

参考热心网友资料1资料2,非常感谢
结论:
频繁的更新字符串请使用StringBuilder,String用来记录字符串常量,StringBuffer很少用。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

  1. String is immutable whereas StringBuffer and StringBuilder are mutable classes.
  2. StringBuffer is thread-safe and synchronized whereas StringBuilder is not. That’s why StringBuilder is faster than StringBuffer.
  3. String concatenation operator (+) internally uses StringBuffer or StringBuilder class.
  4. For String manipulations in a non-multi threaded environment, we should use StringBuilder else use StringBuffer class.

3. String直接赋字符串和new String的区别

参考热心网友资料1资料2

3.1 在内存中不一样

String直接赋字符串:
When we create a String using double quotes, JVM first looks for the String with the same value in the string pool. If found, it returns the reference of the string object from the pool. Otherwise, it creates the String object in the String pool and returns the reference. JVM saves a lot of memory by using the same String in different threads.

new String:
If the new operator is used to create a string, it gets created in the heap memory.

因此,直接赋值建立多个string对象,用==检验,它们都是引用同一个地址!
相反,用new string 建立多个对象,即使内容一样,但地址不一样!

public class test{
    public static void main(String[] args) {
        String str1 = "I am a student";
        System.out.println(str1.hashCode());
        String str2 = "I am a student";
        System.out.println(str2.hashCode());
        System.out.println(str1==str2);
        System.out.println(str1.equals(str2));

        StringBuilder str3 = new StringBuilder("I am student");
        System.out.println(str3.hashCode());
        StringBuilder str4 = new StringBuilder("I am student");
        System.out.println(str4.hashCode());
    }
}

返回:

-879794945
-879794945
true
true
1829164700
2018699554

在这里注意,equals() 和 == 的区别

  1. Main difference between .equals() method and == operator is that one is method and other is operator.
  2. We can use == operators for reference comparison (address comparison) and .equals() method for content comparison. In simple words, == checks if both objects point to the same memory location whereas .equals() evaluates to the comparison of values in the objects.

但是注意了,如果相比较两个stringBuilder的内容,要用到

sb1.toString().equals(sb2.toString());

3.2 频繁的拼接字符串,请使用stringBuilder

string str = "I" + "like" + "Java" + "!";

根据之前介绍的理论,String类是无法修改的,所以实际上计算机执行的是,先建立string类,先赋值"I", 然后丢弃再新建对象并拼接上"like",再丢弃新建,如此往复,非常的浪费资源。可使用Stringbuilder的append方法代替。