Java面试题 String储存 常量池

每个代码款中内容都是单独的,没有上下文关系

new String

new必会在堆中开辟空间创建对象

String str1 = “abc”;最多创建一个String对象,最少不创建String对象。
如果常量池中,已经存在“abc”,那么str1直接引用,此时不创建String对象,否则,先在常量池先创建“abc”,再引用。
String str2 = new string(“ABCD”);最多创建两个String对象,至少创建一个String对象。

// 每次new String时都要先在常量池中寻找
// 创建两个对象 先在字符串常量池中创建abc,再在堆中对象指向常量池中
String abc = new String("abc");
// 字符串常量池已有abc,仅在堆中创建对象,让其指向abc
String d = new String("abc");
// 结果false
System.out.println(abc==d);
// 创建五个对象 常量池中a,b ,堆中指向常量池的两个对象,存储ab的对象
 String s =  new String("a")+new String("b");
// 创建两个对象,字符串常量池中ab,堆中对象,指向ab 不单独创建a和b
String s = new String("a" + "b");
// 仅在常量池中创建ab 不单独创建a和b
        String s= "a"+"b";

字面量相加与字符量相加

在这里插入图片描述
结果 false true
字面变量赋值在常量池中
字符变量相加在堆空间中开辟空间 ,(实际使用的是StringBuilder.append(s1).apeend(s2)),堆中对象存储abc,常量池中无abc(new对象情况下仅堆中对象仅存储常量池引用)
字面常量相加在常量池中开辟空间,且仅在常量池中存储结果
故s3,s4指向地址不同
因"abcxyz"已存在常量池中,s5直接指向这个地址,s4,s5地址相同

在这里插入图片描述

在这里插入图片描述
true true(JDK1.8之后)false true(JDK1.7之前)

intern方法

如果长量池中存在,则直接返回常量池对象引用
JDK1.6之前:如果常量池中没有,就把对象复制一份放到常量池中,返回****常量池中对象的引用

JDK1.7之后用如果常量池中没有,就把对象引用复制到常量池中,返回****常量池中的对象引用(这个引用是指向常量池外的对象的),

也说明字符串常量中不止存在字符串,还存在引用,

这里说1.7之后:
s3地址指向堆中“abcxyz”,调用intern()后,由于常量池中没有,把对象引用(“s3中地址”)放到常量池中,把地址赋值返回给s4(并不是指向这个地址,要是指向,肯定是false,JDK1.6之前是把堆中值复制过去,s4指向常量池,故是false),故s3,s4相同
在这里插入图片描述

在这里插入图片描述
true

特殊
在这里插入图片描述
false

java等一些特殊字符已经在常量池中,intern会直接返回常量池中地址,而s3是指向堆中的

扩展

final String s1="a ";
final String s2="b";
String s3="a b";
String s4=s6+s7;
System.out.println(s8=s9);

结果true
s3,s4都是引用#4 故相等
在这里插入图片描述

String s=new String("a")+new String("b");
// 反编译实际执行了
String s2 = (new StringBuilder()).append(new String("a")).append(new String("b")).toString();

共创建了6个对象,常量池的 a,b;堆中的StringBuilder对象,a,b对象,以及toString方法产生的一个对象(不会再常量池中创建对象),s是指向这个toString方法创建的对象

// StringBuilder赋值给String对象,会调用此方法
public String toString() {
        // Create a copy, don't share the array
        // 但此种构造方法不会在常量池创创建ab对象
        return new String(value, 0, count);
    }

intern详解

如果长量池中存在,则直接返回常量池对象引用
JDK1.6之前:如果常量池中没有,就把对象复制一份放到常量池中,返回****常量池中对象的引用

JDK1.7之后用如果常量池中没有,就把对象引用复制到常量池中,返回 常量池中的对象引用(这个引用是指向常量池外的对象的)

以下仅解释1.7之后的,

String s= new String("ab");
String intern = s.intern();
System.out.println(intern==s);

1.6 1.7 false
第一行会创建两个对象,堆中一个,String Pool中一个,第二行发现常量池中已存在,则直接返回ab对象地址,s指向堆,intern指向 常量池

String s1= "abc";
String s2= "xyz";
String s = s1 + s2;
System.out.println(s==s.intern());

s.intern()会返回指向肚子红abcxyz的引用

String s=new String("a")+new String("b");
s.intern();
String s1="ab";
System.out.println(s==s1);

第二行将堆中ab的引用放入常量池,s1赋值时从常量池中发现堆中已有ab,则直接将这个引用赋值给s1

字符串赋值字面量时,会先从常量池中查找有没有,如果有则直接返回,没有时才创建,这个查找包括 字符串常量 和 intern放入的引用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值