Java String 性质(一)

1. Java 字符串字面量

Java中,字符串字面量(形如”abc”)是String对象实例。JVM为了提高性能和减少内存开销,内部维护了一个字符串字面量的String对象池(简称字面量池)。每当创建字符串字面量时,JVM首先检查字面量池,如果池中已经存在该字面量String对象,则返回池中的字面量对象引用,否则创建该字面量String对象并放入池中。

举例:我们先来想想以下代码会打印出什么结果?

String string1 = "hello";
String string2 = string1;

string1 = "world";

StdOut.println(string1);
StdOut.println(string2);

打印出的结果是:

world
hello

根据JVM字符串字面量常量池的机制,当String引用变量引用字符串字面量时,JVM会进行以下操作:

  1. 如果该字面量在字符串池中未出现过,则会新创建一个字面量String对象放入字面量池中,并返回该对象的引用;
  2. 如果该字面量在字面量池中出现过,则只会返回这个字面量String对象的引用。

因此,上面的代码可以这样分析:

String string1 = "hello"; //此时会在字面量池中新创建值为“hello”的字符串对象,并返回其引用给string1
String string2 = string1; //此时string1和string2都引用“hello”字面量String对象

string1 = "world"; //由于“world”在字面量池中不存在,所以会在字面量池中新创建“world”字面量String对象,并将其引用返回给string1

StdOut.println(string1); //string1引用“world”字面量String对象
StdOut.println(string2); //string2引用“hello”字面量String对象

所以,最后string1和string2分别引用不同的对象,因此打印出来的结果如上。

2. 通过new String(String str)等类似方法创建String对象

当采用此种类型的方法创建String对象时,JVM会直接在堆内存空间上创建String对象,不论该String对象的字符串值是否和堆内存上已有的String对象的字符串值相同,且这个过程与字符串字面量池中完全没有关系。举例如下:

    String string1 = new String("abc");
    String string2 = new String("abc");   
    System.out.println(string1 == string2);

输出结果是false,说明此时JVM在堆内存空间创建了两个String对象。

需要注意的是,String的intern()方法返回String对象在字符串字面量池中的对象引用,若字符串字面量池中尚未有该String对象的字符串,则创建一新的字符串字面量放置于池中。举例

String a = "Hello";
System.out.println(a == a.intern()); 
//true,因为字面量String对象的intern()方法返回对自己的引用

String b = new String("corn");
String c = b.intern(); 
System.out.println(b == c);
//false,因为此时b引用的是堆内存上的String对象,而c引用的是字面量池中的"corn"字面量String对象

String d = "corn";
System.out.println(c == d); 
//true,因为此时d和c都是引用的字面量池中的"corn"

3. String的substring()方法实现

在Java 1.7.0_06之前的版本中,String类中有4个非静态变量:
1. char[] value:共享字符数组的引用。
2. int offset:用于记录该String对象的字符串的首字母在共享数组中对应的下标。
3. int count:用于记录该String对象的字符串的长度。
4. int hash:用于缓存该String对象的哈希值。

此时String.substring()方法创建的String对象将和原String对象共享同一个内部变量char[] value,这样设计的好处是:
1. 通过共享字符串节省内存开销。
2. String.substring()方法的时间复杂度为O(1)。

但是从Java 1.7.0_06开始,String类中不再含有offset和count变量,这意味String对象和其子String对象之间不再共享一个char数组。这样String.substring()方法是线性级的时间复杂度,不再是常数级的时间复杂度,因为现在创建子String对象时需要将String实例中的char数组的相应元素逐一复制到子String对象的char数组中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值