Java 关于字符串创建和常量池

Java中的字符串是使用 String 类来实现的,String 对象创建的方式一般有两种:

1.

String s = new String("string");

这种创建方式的过程是:

(1)在常量池中寻找是否有引用指向"string",若有则在堆中开辟一块空间将常量池引用指向的内容赋值到新开辟的空间,若没有则先在堆中开辟一块空间存储"string"并在常量池创建一个引用指向这片空间.

(2)然后再在堆中开辟一块空间将刚才对象的内容复制过去,这样的话就一次性创建了两个对象(常量池引用指向的对象和 new 出来的对象)

(3)并不是所有情况下这种方式都会创建两个对象,因为上面的例子中传入了一个字符串的字面量,所以会先执行(1),若传入的字面量已经在常量池中存在或者传入的不是编译时常量(字面量)

String te = "te";
String st = "st";
String test = new String(te)+new String(st);

上面的例子中字符串常量池中只有关于 “te” 和 “st” 的引用,而没有指向 “test” 的引用,因为没有出现过这个字符串的字面量。

2.

String s = "string";

这种创建方式的过程是:先在字符串常量池中寻找是否存在引用指向堆中的对象存储有 “string” 字符串,若有:则将创建的引用指向字符串常量池的引用;若没有:则在堆中创建一块对象存储 “string”,然后在常量池中创建一个引用指向对象,将这个引用的值赋给 s 。

注意:

**在用 new 创建字符串时传入构造器一个字符串时虽然新创建的字符串和传入字符串的地址不一样,但内部使用的 char[] 数组是同一个,可以通过源码看到:**
/**
 * Initializes a newly created {@code String} object so that it represents
 * the same sequence of characters as the argument; in other words, the
 * newly created string is a copy of the argument string. Unless an
 * explicit copy of {@code original} is needed, use of this constructor is
 * unnecessary since Strings are immutable.
 *
 * @param  original
 *         A {@code String}
 */
public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

那么这两种方式的创建有什么区别:

用 new 关键字创建的String对象每次都会在堆中新开辟一块内存存储给定的字符串,就算创建的字符串内容相同,但还是在堆开辟了多个区域分别存储这些对象;而用字面量创建的字符串对象则是在对中开辟一块区域存储字符串对象,所有引用都指向字符串常量池中指向堆中对象的引用:

String s1 = new String("a");
String s2 = new String("a");
assertFalse(s1==s2);
String s3 = "a";
String s4 = "a";
assertFalse(s1==s3);
assertTrue(s3==s4);

所以这两种创建方式在性能上还是有差异的。

因为 String 类是 final 类型的,所以在修改一个 String 的值时其实是重新创建了一个 String 对象。

String的字符串常量池中保存的是对象的引用,而不是对象。

在 jdk1.7 以前,字符串常量池都是放在永久代中,在 jdk1.7 将字符串常量池转移到了堆内存中。

jdk1.7前,在每一个JVM实例中都会有一个永久代,其中的字符串常量池保存了这一个JVM实例中所有的字符串引用;这个常量池其实在底层C++中就是一个Stringtable,和Java中的hashtable差不多,存储能力有限,若存储太多字符串则会大大影响效率。

上述两种创建方式的图解:

附上这张图的链接

String .intern()

维基百科

字符串中的 intern() 方法将每个不同的字符串唯一地存在常量池中,每个单个的字符串副本被称为 intern 。Java中的所有编译时常量字符串都用此方法自动实现。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值