JAVA String类的疑难点

1.String存放位置和GC

  Jdk1.7之前常量池在方法区,jdk1.7及以后移动到堆区。str.intern()会判断字符串常量池中是否存在该对象,若果没有则在常量池中创建该对象,并且在堆中存在该对象实例,在jdk1.6及之前复制一份字面量存储在常量池中,返回的也是该字面量在常量池中的引用,jdk1.7及以后堆中实例引用复制一份到常量池中,返回的也是该堆中的实例引用地址;如果有则直接返回该对象引用。当内存充足的时候,字符串常量池对象不会被回收,当内存不足的时候,并且该字符串的没有被其它变量引用,该字符串常量会被回收。

2.String 长度限制

  String长度理论上没有限制,实际有限制,限制主要体现在底层存储String类型的容器和String构造函数上。
1)String底层使用bytess数组储存,u2是16位无符号整数,能存储的字符长度为2^16-1=65535
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
2) String构造函数
public String(char value[], int offset, int count) {

}
count是字符串长度,使用int表示,int能表示最大长度为2^31-1,
(2^31-1)216/8/1024/1024/1024 = 4GB

3.String的不可继承性

  String属于引用类型,但是类被final关键字修饰,所以无法被继承。

4.常用字符串创建方式

  常用创建一个字符串String对象的的方式有五种【实际构造函数有13种】。在Java7之前,分配在JVM的方法区中,属于常量池的一部分。在Java7之后字符串常量池被移到堆内存中,以便JVM进行垃圾回收。

(1) String str = “abc”;

  该语句创建了一个对象,判断常量池是否有等于该值的字面量,如果有,则str直接指向常量池中该字面量的地址。

String str2 = "abc";
System.out.println(str2.intern());
  System.out.println(str2.intern()==str2);//true

(2) String str = new String( “abc”);

在这里插入图片描述
  首先该条语句创建了两个对象,首先在将字面量“abc”存储在常量池中,然后再在堆上创建“abc”的实例对象,返回的也是在堆上实例对象的引用。
下面验证代码了创建了两个对象和创建的顺序。

String str1 = new String("ABC");
System.out.println(str1.intern()==str1);//false

(3)String str = “A”+“BC”;

  创建了一个对象,JVM会进行优化,只会将最终结果”ABC“(literal constant)存储在常量池中。

(4) String str1 = “A”;String str2 = str1+“BC”;或者String str2 = “BC”+str1;

  第二个语句两种形式,只会新创建了两个对象,第一个是在堆中创建一个“ABC”对象,第二个是在在常量池中存储“ABC”在堆中的引用。因为只要在字符串相加过程中存在一个变量,底层都会使用StringBuilder累的append方法,在堆上新创建一个对象,并返回该对象的引用,如果新创建的对象字面量在常量池中不存在,还会在常量池中创建一个新的字符创串常量对象。

(5) String str1 = “A”;String str2 = “BC”; String str3 = str1+str2;

  创建语句三在堆上创建了一个对象。

5.intern()用法

new String(String str)的时候会首先在常量池中创建str字面量,然后再在堆中创建一个字符串实例,当调用str.intern()的时候,发现常量池中已经有str字面量,不在将堆中实例引用存储在常量池中,而是直接返回常量池str字面量引用

String str = new String("ali");
System.out.println(str== str.intern());//false

new Builder(String str)和newString(String str)创建过程相似,会首先在常量池中创建str字面量,再在堆中创建一个字符串实例,调用str.intern()的时候,发现常量池中已经有str变量,不在将堆中实例引用存储在常量池中,而是直接返回常量池str字面量引用

String str2 = new StringBuilder("美团").toString();
System.out.println(str2 == str2.intern());//false

new StringBuilder(“58”).append(“同城”).toString();语句创建了两个对象,存储在常量池中的“58”,和存储在堆中的“58同城”, 返回的是"58同城"在堆中实例引用,调用str1.intern(),在常量池发现“58同城”不存在, 而在堆中有“58同城”实例对象,直接将该对象的引用放在常量池中(jdk1.6及以前是拷贝字面量在常量池中), 同时也是返回该对象在堆中引用,因此结果为true。

String str1 = new StringBuilder("58").append("同城").toString(); System.out.println(str1==str1.intern());//true

直接在常量池创建字符串实例,str3.intern()也是返回的常量池中字符串实例的引用,因此返回true

String str3 = "javaEESESESE";
System.out.println(str3.intern()==str3);//true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值