String 字符串
String 重写了 equals() 方法;
因为 object 的 equals 方法是比较的对象的内存地址,String 的 equals() 方法比较的是对象的值。
- 当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用,如果没有就在常量池中重新创建一个 String 对象。
1 | public boolean equals(Object anObject) { |
常量池 (constant pool)
Java 1.6 及以前,常量池在方法区;
Java 1.7 常量池在堆中的永久代;
Java 1.8 常量池在元空间;
常量池指的是在编译期被确定,并被保存在已编译的.class
文件中的一些数据。
除了包含代码中所定义的各种基本类型(如int、long等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如:
- 类和接口的全限定名;
- 字段的名称和描述符;
- 方法和名称和描述符;
如果是编译期(直接用双引号定义的)已经创建好的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于 equals 相等的字符串,在常量池中永远只有一份,在堆中有多份。
常量池分类
- Class文件常量池 — 编译阶段
- 存放
字面量
和符号引用
;
- 存放
- 运行时常量池 — 方法区
- 全局字符串常量池
- 基本类型包装类对象常量池
String str1 = new String();
1 | String str1 = new String("ab"); //TODO str1 为一个引用,String对象存储在堆中 |
String s1 = “ab”;
1 | String s1 = "ab"; //TODO 第一次常量池中没有,放在常量池中 |
“a” + new String(“b”)
1 | String s1 = "ab"; //TODO 放在常量池中 |
引用 String
1 | String a = "a"; |
final String
1 | String strab = "abb"; |
Method
1 | String a = "ab"; |
String 不可变
每做一次 + 就产生个StringBuffer对象,然后append后就扔掉。下次循环再到达时重新产生个StringBuffer对象,然后 append 字符串,如此循环直至结束。如果我们直接采用 StringBuffer 对象进行 append 的话,我们可以节省 N - 1 次创建和销毁对象的时间。所以对于在循环中要进行字符串连接的应用,一般都是用StringBuffer或StringBulider对象来进行 append操作。
1 | String xyz = "x" + "y" + "z"; |
因为String不可变,所以 final 对象不能更改指向;至于它所指向的对象的变化,final是不负责的。
1 | final StringBuffer a = new StringBuffer("111"); |
StringBuffer/Builder 不可变
1 | public final class StringBuffer |
StringBuffer 线程安全,方法上有synchronized关键字加锁;适用于多线程
StringBuilder 线程不安全,适用于单线程;
感谢阅读
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !