作者:丶Pz  
来源:https://www.cnblogs.com/panzi/p/11956782.html

在之前的面试经历中,对于String的考察还是挺频繁的,大致考察以下几个知识点:

  • String 常量池

  • new String()

  • == 和 equals 的区别

  • native 方法 String.intern()

虽然面试中大体答对了,但是今天早上微信群里的一个问题我却答不上来,这个问题是这样的:

String str3 = "what";
String str4 = str3 + " a nice day";
//运行时, + 相当于 new,所以堆中会有 "what a nice day"对象,常量池中会有"what"," a nice day"两个对象,而不会有 "what a nice day"对象。
//这句话大佬们看看对不对啊,我怎么感觉不对啊
//常量池不会有"what a nice day" 对象吗?

看完这个问题,说实话我也是有点懵的,我只是知道 "what a nice day"不会在常量池,但是不知道具体的原因,后来群里的同学说 + 号是调用了 StringBuffer 的append 方法。我去证实了,发现确实调用了 append 方法,但是当时没有 调用toString()方法,我很疑惑。(最后经过证实,是StringBuilder的append 方法,不是StringBuffer)。

代码验证

public static void main(String[] args) {//#1String str1 = "what";//#2String str2 = str1 + " a nice day";//#3System.out.println("what a nice day".equals(str2));//#4System.out.println("what a nice day" == str2);
}

现在有以下几个问题,小伙伴们看看是否能答出来,即使答出来了,你知道为什么吗?

  1. str1 存放位置?

  2. str2 存放位置?

  3. 结果是 true 还是 false?

  4. 结果是 true 还是 false?

  5. "what a nice day" 存放在哪个位置呢?

解答分析(基于JDK1.8)

下面也不靠猜,我们直接查看生成的字节码:

localhost:test didi$ javap -verbose -p Main.class
Classfile /develop/project/string-test/out/production/classes/com/fanpan26/string/test/Main.classLast modified 2019-11-29; size 972 bytesMD5 checksum 1d1f1a23bfe85c2f88d2f767e8aac314Compiled from "Main.java"
public class com.fanpan26.string.test.Mainminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #13.#34        // java/lang/Object."<init>":()V#2 = String             #35            // what#3 = Class              #36            // java/lang/StringBuilder#4 = Methodref          #3.#34         // java/lang/StringBuilder."<init>":()V#5 = Methodref          #3.#37         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#6 = String             #38            //  a nice day#7 = Methodref          #3.#39         // java/lang/StringBuilder.toString:()Ljava/lang/String;#8 = Fieldref           #40.#41        // java/lang/System.out:Ljava/io/PrintStream;#9 = String             #42            // what a nice day#10 = Methodref          #43.#44        // java/lang/String.equals:(Ljava/lang/Object;)Z#11 = Methodref          #45.#46        // java/io/PrintStream.println:(Z)V#12 = Class              #47            // com/fanpan26/string/test/Main#13 = Class              #48            // java/lang/Object#14 = Utf8               <init>#15 = Utf8               ()V#16 = Utf8               Code#17 = Utf8               LineNumberTable#18 = Utf8               LocalVariableTable#19 = Utf8               this#20 = Utf8               Lcom/fanpan26/string/test/Main;#21 = Utf8               main#22 = Utf8               ([Ljava/lang/String;)V#23 = Utf8               args#24 = Utf8               [Ljava/lang/String;#25 = Utf8               str1#26 = Utf8               Ljava/lang/String;#27 = Utf8               str2#28 = Utf8               StackMapTable#29 = Class              #24            // "[Ljava/lang/String;"#30 = Class              #49            // java/lang/String#31 = Class              #50            // java/io/PrintStream#32 = Utf8               SourceFile#33 = Utf8               Main.java#34 = NameAndType        #14:#15        // "<init>":()V#35 = Utf8               what#36 = Utf8               java/lang/StringBuilder#37 = NameAndType        #51:#52        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#38 = Utf8                a nice day#39 = NameAndType        #53:#54        // toString:()Ljava/lang/String;#40 = Class              #55            // java/lang/System#41 = NameAndType        #56:#57        // out:Ljava/io/PrintStream;#42 = Utf8               what a nice day#43 = Class              #49            // java/lang/String#44 = NameAndType        #58:#59        // equals:(Ljava/lang/Object;)Z#45 = Class              #50            // java/io/PrintStream#46 = NameAndType        #60:#61        // println:(Z)V#47 = Utf8               com/fanpan26/string/test/Main#48 = Utf8               java/lang/Object#49 = Utf8               java/lang/String#50 = Utf8               java/io/PrintStream#51 = Utf8               append#52 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;#53 = Utf8               toString#54 = Utf8               ()Ljava/lang/String;#55 = Utf8               java/lang/System#56 = Utf8               out#57 = Utf8               Ljava/io/PrintStream;#58 = Utf8               equals#59 = Utf8               (Ljava/lang/Object;)Z#60 = Utf8               println#61 = Utf8               (Z)V
{public com.fanpan26.string.test.Main();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 6: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   Lcom/fanpan26/string/test/Main;public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=3, locals=3, args_size=10: ldc           #2                  // String what2: astore_13: new           #3                  // class java/lang/StringBuilder6: dup7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V10: aload_111: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;14: ldc           #6                  // String  a nice day16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;22: astore_223: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;26: ldc           #9                  // String what a nice day28: aload_229: invokevirtual #10                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z32: invokevirtual #11                 // Method java/io/PrintStream.println:(Z)V35: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;38: ldc           #9                  // String what a nice day40: aload_241: if_acmpne     4844: iconst_145: goto          4948: iconst_049: invokevirtual #11                 // Method java/io/PrintStream.println:(Z)V52: returnLineNumberTable:line 9: 0line 11: 3line 13: 23line 15: 35line 16: 52LocalVariableTable:Start  Length  Slot  Name   Signature0      53     0  args   [Ljava/lang/String;3      50     1  str1   Ljava/lang/String;23      30     2  str2   Ljava/lang/String;StackMapTable: number_of_entries = 2frame_type = 255 /* full_frame */offset_delta = 48locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ]stack = [ class java/io/PrintStream ]frame_type = 255 /* full_frame */offset_delta = 0locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ]stack = [ class java/io/PrintStream, int ]
}
SourceFile: "Main.java"

从Constant pool: 中的信息可以看到,#2 、#6、#9 可以解答上文中的1,5两个问题。

  • str1 是存放在常量池的

  • "what a nice day" (非str2)也是存放在常量池的

下面我们看一下 + 操作做了什么事情,可以在Code中看到,该操作调用了 StringBuilder.append 方法

11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc           #6                  // String  a nice day
16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

那么到这里一切都答案都出来了

  • str2 是存放在堆中

  • equals 为 true

  • == 为 false

所以说其实 str1 + " a nice day" 就相当于 new StringBuilder().append(str1).append(" a nice day");

//这两种写法生成的字节码是一样的。
//String str2 = str1 + " a nice day";
String str2 = new StringBuilder().append(str1).append(" a nice day").toString();

而StringBuilder 的toString 方法如下:

@Override
public String toString() {// 所以说 str2 其实是一个 new String,是不在常量池里面的。return new String(value, 0, count);
}

总结

通过类的字节码可以查看底层具体用什么方式实现,所以说虽然看似一个简单的String问题,其实往深处挖掘还是考察了对生成的字节码的理解。还有,遇到一个问题,不能死记答案,有些人告诉你,+ 操作就是 new 对象,但是具体到底是不是或者为什么是有没有思考过呢?上文中如有错误,欢迎指出。

试一试

/*** 以下程序输出的结果是什么?* */
public static void main(String[] args) {String str1 = "what";String str2 = str1 + " a nice day";System.out.println("what a nice day".equals(str2));System.out.println("what a nice day" == str2);
}
/*** 以下程序输出的结果是什么?* */
public static void main(String[] args) {String str1 = "what a nice day";String str2 = new String("what a nice day");System.out.println(str1.equals(str2));System.out.println(str1 == str2);
}
/*** 以下程序输出的结果是什么?* */
public static void main(String[] args) {String str1 = "what";String str2 = str1.concat(" a nice day");System.out.println("what a nice day".equals(str2));System.out.println("what a nice day" == str2);System.out.println("what a nice day"==str2.intern());
}

java.lang.String 的 + 号操作,这个谜终于要解开了!相关推荐

  1. 常用类库-java.lang.String

    文章目录 常用类库-java.lang.String 简介 构造方法 常用方法: charAt codePointAt codePointBefore compareTo compareToIgnor ...

  2. JDK1.8源码(三)——java.lang.String 类

    String 类也是java.lang 包下的一个类,算是日常编码中最常用的一个类了,那么本篇博客就来详细的介绍 String 类. 1.String 类的定义 public final class ...

  3. MyBatis中提示:invalid comparison: java.util.LinkedHashMap and java.lang.String

    场景 在使用MyBatis传递多个参数并且传递的参数作为判断条件时提示: invalid comparison: java.util.LinkedHashMap and java.lang.Strin ...

  4. 【Java】- Incompatible types. Found: java. lang. String', required:' byte, char, short or int'

    IDEA项目编译报错:Incompatible types. Found: java. lang. String', required:' byte, char, short or int',swit ...

  5. 【Java】java.lang.String

    文章目录 String的创建和初始化 String的不可变性 String的底层存储 String的hashCode方法 String的创建和初始化 Java中的String是一个不可变的对象,即一旦 ...

  6. java.lang.String的使用

    java.lang.String的使用 概述:String:字符串,使用一对" "引起来表示 String声明为final的,不可被继承 String实现了Serializable ...

  7. java.util.IllegalFormatConversionException: d != java.lang.String

    今天使用过sparksql编写代码的时候因为业务需求要保留小数据最后5位数,我就使用的是formatted进行的一个操作,将小数点第六位四舍五入. java.util.IllegalFormatCon ...

  8. 【异常】java.lang.Integer cannot be cast to java.lang.String

    目录 目录 一.问题描述 二.问题分析 1/ 2 关于BootStrapLoader的问题 2 / 3 java.lang.Integer cannot be cast to java.lang.St ...

  9. 无法解析构造函数‘Employee(int,java.lang.String,java.lang.String,int,com.kuang.pojo.Department)‘

    前言:在写这篇博客的时候,本来博客名字打算叫:"在给Java伪造数据库里面的伪数据的相关字段插入数据时,插入失败,是什么原因导致的?",后来思前想后,还是决定直接拷贝使用编译器上面 ...

最新文章

  1. 上传Android或Java库到Maven central repository(转载)
  2. java中表示根号三_Java命名规范
  3. python爬酷狗音乐_良心推荐!一个Python高手必读的库,真香!
  4. 在多重Catch的情况下得到异常的完整信息
  5. 董明珠宣布开启抖音直播卖货首秀,对刚“半价”直播罗永浩?
  6. DateTime 操作详解
  7. 什么是服务的熔断降级
  8. Android 仿PhotoShop调色板应用(一)概述
  9. 传统武术家为什么看起来厉害?谈实战的重要性
  10. 能当「公务员」、服务员,商用服务机器人今年为啥这么火?
  11. 汇编语言(十二)颜色搭配显示+BIOS功能调用表+INT 10H功能详细列表
  12. box-sizing 的使用
  13. 美国主要经济指标(2)
  14. 2022年场(厂)内专用机动车辆安全管理考试模拟100题模拟考试平台操作
  15. PRN(20210421):Task-Free Continual Learning
  16. python Django 快捷键
  17. h5跳转微信公众号文章,小程序,任意站跳转链接制作方法?
  18. MFC制作Windows画图程序(二)
  19. Android开发交流群
  20. 在SQL中删除重复记录(多种方法) [转]

热门文章

  1. 数字图像处理:第二章 图象获取、显示、表示与处理
  2. 《分布式操作系统》知识点(22~28)四
  3. 区块链项目开发:双因素身份验证应用程序如何帮助保护你的加密帐户
  4. SharePoint PowerShell 修改计时器任务
  5. 酷狗音乐在线试听下载
  6. Crash/Instance Recovery与Media Recovery的本质区别
  7. 3月30日高项作业(采购、信息和配置管理)
  8. 让图片算好高宽再显示
  9. 【Python】Numpy库之符号函数sign()的介绍及用法
  10. JavaScript 如果拥有多线程能力会怎样?