String

首先了解一下怎么看java代码解析情况
javac MedianFinder.java
javap -verbose MedianFinder.classes

一.先了解创建了几个对象

1.String s =new String(“a”)创建了几个对象?

2个(默认之前常量池没有)

  • 如果常量池已经有“a”了,那么只会在堆中创建一个
  • 如果没用,则会堆和常量池各一个
    关键点就是不光直接"a"这样的字面量会在常量池创建,new也会在常量池创建,并且在堆也会创建

2.String s = “a”+"b"创建了几个对象?

1个
JVM在编译的时候就会认定为是String s = "ab"所以只会在常量池生成1个

3.String s = “a” + new String("b)创建几个对象

4个

  • 首先常量池会创建两个:“a”,“b”
  • 堆里首先会创建一个"b",然后会创建一个StringBuilder类型的"ab"

String s1 = new String("b)
String s2 = new String("b)
几个对象?

3个

  • 常量池1个
  • 堆两个

5.String s = new String(“a”) + new String(“a”);几个对象?

4个

  • 常量池1个
  • 堆3个:2个String,一个StringBuilder

6.String s = new String(“a”) + new String(“b”);几个对象?

5个

  • 常量池2个
  • 堆3个:2个String,一个StringBuilder

问题:在2中两个""相加的内容也就是”ab“会放入常量池,但是只要有new方法的相加,比如3中的”ab“、5中的”aa“、6中的”ab“都不在常量池中创建

在这里插入图片描述
而且要注意
1.“”+"“这样的包括”"都是直接在常量池创建,不在堆创建
2.只要有new的都会在堆创建,并且只要有new参与的+连接,都使用StringBuilder连接的,连接结果不会再常量池创建
3.只要有引用参与的+连接,也低于是都使用StringBuilder连接的,连接结果不会再常量池创建

再补充一点""这种空字符串,也算是和"a"一样的

二.判断地址相等

在这里插入图片描述
答案是true,因为两个"“+”"会被JVM直接看成连接后的结果,所以都统一指向一个常量池地址(也就是创建了1个对象)
在这里插入图片描述

在这里插入图片描述
答案是fasle
当多个字符串引用相加的时候,会在堆中开辟一个空间,是StringBuilder对象进行拼接
首先创建了4个对象,3个再常量池,一个堆里的StringBuilder对象
在这里插入图片描述
要注意,这种引用拼接的情况,不会再常量池里创建对象(所以SB对象的也就不会指向常量池的abcd),因此如果是没用s1,常量池中就不会有”abcd“
在这里插入图片描述
3个对象,常量池2个,堆一个
在这里插入图片描述
不过,字符串使用 final 关键字声明之后,可以让编译器当做常量来处理。
示例代码:

final String str1 = "str";
final String str2 = "ing";
// 下面两个表达式其实是等价的
String c = "str" + "ing";// 常量池中的对象
String d = str1 + str2; // 常量池中的对象
System.out.println(c == d);// true

被 final 关键字修改之后的 String 会被编译器当做常量来处理,编译器在程序编译期就可以确定它的值,其效果就相当于访问常量。

String s = "1";
String s1 = "1";
System.out.println(s == s1);

答案是true,因为都指向常量池地址(创建了一个对象)
在这里插入图片描述

String s = new String("1");
String s1 = new String("1");
System.out.println(s == s1);

答案是fasle
引用指向的是两个不同的堆地址,虽然这两个堆里的对象都指向同一个常量池地址(共创建3个对象)
在这里插入图片描述

String s = "1";
String s1 = new String("1");
System.out.println(s == s1);

答案是fasle,一个指向堆对象,一个指向常量池。堆对象的内容指向常量池(共2个对象)
在这里插入图片描述

三.加入.intern()方法

如果字符串s在字符串常量池中存在对应字面量,则intern()方法返回该字面量的地址;如果不存在,则在字符串常量池创建一个对应的字面量,并返回该字面量的地址

String对象与字面量的intern()区别

public static void main(String[] args) {
    String s1 = new String("字符串");
    String s2 = "字符串";
    System.out.println(s2 == s2.intern());
    System.out.println(s1 == s1.intern());
    System.out.println(s1.intern() == s2.intern());
}

结果是True / False / True,解释如下:

  • 对于字符串字面量s2而言,它本身就是字符串常量池中"字符串"常量的引用,因此s2.intern()返回的是字符串常量池中“字符串”常量的地址,与s2本身是相等的,所以为true
  • 对于String对象s1而言,它是一个指向堆空间String对象的引用。String对象中保存着一个final byte[]用于存储字符串的value,该成员又指向了字符串常量池中“字符串”这个字面量。因此调用s1.intern(),返回的是字符串常量池中"字符串"字面量的地址。s1本身存的是堆空间String对象的地址,因此二者不相等
  • 不管是String对象,还是字面量,只要他们的值相等,调用intern()都会返回同一个字符串常量池的引用,因此s1.intern() == s2.intern()
// 在堆中创建字符串对象”Java“
// 将字符串对象”Java“的引用保存在字符串常量池中
String s1 = "Java";
// 直接返回字符串常量池中字符串对象”Java“对应的引用
String s2 = s1.intern();
// 会在堆中在单独创建一个字符串对象
String s3 = new String("Java");
// 直接返回字符串常量池中字符串对象”Java“对应的引用
String s4 = s3.intern();
// s1 和 s2 指向的是堆中的同一个对象
System.out.println(s1 == s2); // true
// s3 和 s4 指向的是堆中不同的对象
System.out.println(s3 == s4); // false
// s1 和 s4 指向的是堆中的同一个对象
System.out.println(s1 == s4); //true
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值