【119期】面试官问:了解过 JDK8 中常量池吗?说说运行时的常量池!(1)

更多:Java进阶核心知识集

包含:JVM,JAVA集合,网络,JAVA多线程并发,JAVA基础,Spring原理,微服务,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存等等

image

高效学习视频

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

#17 = NameAndType #18:#19 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

#18 = Utf8 append

#19 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;

#20 = Methodref #7.#21 // java/lang/StringBuilder.toString:()Ljava/lang/String;

#21 = NameAndType #22:#23 // toString:()Ljava/lang/String;

#22 = Utf8 toString

#23 = Utf8 ()Ljava/lang/String;

#24 = Fieldref #25.#26 // java/lang/System.out:Ljava/io/PrintStream;

#25 = Class #27 // java/lang/System

#26 = NameAndType #28:#29 // out:Ljava/io/PrintStream;

#27 = Utf8 java/lang/System

#28 = Utf8 out

#29 = Utf8 Ljava/io/PrintStream;

#30 = Methodref #31.#32 // java/lang/String.intern:()Ljava/lang/String;

#31 = Class #33 // java/lang/String

#32 = NameAndType #34:#23 // intern:()Ljava/lang/String;

#33 = Utf8 java/lang/String

#34 = Utf8 intern

#35 = Methodref #36.#37 // java/io/PrintStream.println:(Ljava/lang/String;)V

#36 = Class #38 // java/io/PrintStream

#37 = NameAndType #39:#13 // println:(Ljava/lang/String;)V

#38 = Utf8 java/io/PrintStream

#39 = Utf8 println

#40 = Methodref #36.#41 // java/io/PrintStream.println:(Z)V

#41 = NameAndType #39:#42 // println:(Z)V

#42 = Utf8 (Z)V

#43 = String #44 // 常量"ja"字符串

#44 = Utf8 ja

#45 = String #46 // 常量"va"字符串

#46 = Utf8 va

#47 = Class #48 // com/example/demo/test/TestDemo

#48 = Utf8 com/example/demo/test/TestDemo

#49 = Utf8 Code

#50 = Utf8 LineNumberTable

#51 = Utf8 LocalVariableTable

#52 = Utf8 this

#53 = Utf8 Lcom/example/demo/test/TestDemo;

#54 = Utf8 test01

#55 = Utf8 str1

#56 = Utf8 Ljava/lang/String;

#57 = Utf8 str2

#58 = Utf8 str3

#59 = Utf8 StackMapTable

#60 = Utf8 RuntimeVisibleAnnotations

#61 = Utf8 Lorg/junit/Test;

#62 = Utf8 SourceFile

#63 = Utf8 TestDemo.java

{

public com.example.demo.test.TestDemo();

descriptor: ()V

flags: (0x0001) ACC_PUBLIC

Code:

stack=1, locals=1, args_size=1

0: aload_0

1: invokespecial #1 // Method java/lang/Object.“”😦)V

4: return

LineNumberTable:

line 7: 0

LocalVariableTable:

Start Length Slot Name Signature

0 5 0 this Lcom/example/demo/test/TestDemo;

public void test01();

descriptor: ()V

flags: (0x0001) ACC_PUBLIC

Code:

stack=3, locals=4, args_size=1

0: new #7 // 创建 java/lang/StringBuilder 对象

3: dup

4: ldc #9 // 入栈常量池(#9)中的字符串常量hello

6: invokespecial #11 // 实例初始化将hello传入

9: ldc #14 // 入栈常量池(在#14)中的字符串常量World

11: invokevirtual #16 // StringBuilder.append方法调用传入World

14: invokevirtual #20 // 调用StringBuilder.toString方法

17: astore_1 // 将返回的值的地址引用存入到局部变量1

18: getstatic #24 // 获取打印流

21: aload_1 // 将局部变量1装载成引用类型,也就是"helloWorld"

22: invokevirtual #30 // "helloWorld"调用String.intern:()方法

25: invokevirtual #35 // 调用打印流,打印"helloWorld"

28: getstatic #24 // 获取打印流

31: aload_1 // 加载局部变量1 也就是"helloWorld"

32: aload_1 // 加载局部变量1 “helloWorld”

33: invokevirtual #30 // "helloWorld"调用intern方法

36: if_acmpne 43 // 如果条件满足就转执行43 的iconst_0也就是将0入栈

39: iconst_1 // 将int类型常量值1压入栈

40: goto 44 // 无条件转移到44

43: iconst_0 // 将0入栈

44: invokevirtual #40 // 调用方法传入也就是“ja"(对应常量池的#44)

47: new #7 // 创建StringBuilder对象

50: dup

51: ldc #43 // 加载字符串"ja"

53: invokespecial #11 // 实例化StringBuilder

56: ldc #45 // 加载字符串"va"

58: invokevirtual #16 // 调用append方法

61: invokevirtual #20 // 调用toString方法

64: astore_2 // 将toString的结果存入局部变量2中

65: getstatic #24 // 获取打印流

68: aload_2 // 加载局部变量2的值也就是加载"java"

69: invokevirtual #30 // 调用intern方法

72: invokevirtual #35 // 打印"java"

75: getstatic #24 // 获取打印流

78: aload_2 // 加载局部变量2"java"

79: aload_2 // 加载局部变量2"java"

80: invokevirtual #30 // 调用intern方法

83: if_acmpne 90 // 如果条件成立跳转到90也就是将0入栈

86: iconst_1 // 将常量值1入栈

87: goto 91 // 无条件跳转到91

90: iconst_0 // 将常量值0入栈

91: invokevirtual #40 // 打印

94: new #7 // class java/lang/StringBuilder

97: dup

98: ldc #9 // String hello

100: invokespecial #11 // Method java/lang/StringBuilder.“”:(Ljava/lang/String;)V

103: invokevirtual #20 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

106: astore_3

107: getstatic #24 // Field java/lang/System.out:Ljava/io/PrintStream;

110: aload_3

111: invokevirtual #30 // Method java/lang/String.intern:()Ljava/lang/String;

114: invokevirtual #35 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

117: getstatic #24 // Field java/lang/System.out:Ljava/io/PrintStream;

120: aload_3

121: aload_3

122: invokevirtual #30 // Method java/lang/String.intern:()Ljava/lang/String;

125: if_acmpne 132

128: iconst_1

129: goto 133

132: iconst_0

133: invokevirtual #40 // Method java/io/PrintStream.println:(Z)V

136: return

LineNumberTable:

line 13: 0

line 14: 18

line 15: 28

line 17: 47

line 18: 65

line 19: 75

line 21: 94

line 22: 107

line 23: 117

line 24: 136

LocalVariableTable:

Start Length Slot Name Signature

0 137 0 this Lcom/example/demo/test/TestDemo;

18 119 1 str1 Ljava/lang/String;

65 72 2 str2 Ljava/lang/String;

107 30 3 str3 Ljava/lang/String;

StackMapTable: number_of_entries = 6

frame_type = 255 /* full_frame */

offset_delta = 43

locals = [ class com/example/demo/test/TestDemo, class java/lang/String ]

stack = [ class java/io/PrintStream ]

frame_type = 255 /* full_frame */

offset_delta = 0

locals = [ class com/example/demo/test/TestDemo, class java/lang/String ]

stack = [ class java/io/PrintStream, int ]

frame_type = 255 /* full_frame */

offset_delta = 45

locals = [ class com/example/demo/test/TestDemo, class java/lang/String, class java/lang/String ]

stack = [ class java/io/PrintStream ]

frame_type = 255 /* full_frame */

offset_delta = 0

locals = [ class com/example/demo/test/TestDemo, class java/lang/String, class java/lang/String ]

stack = [ class java/io/PrintStream, int ]

frame_type = 255 /* full_frame */

offset_delta = 40

locals = [ class com/example/demo/test/TestDemo, class java/lang/String, class java/lang/String, class java/lang/String ]

stack = [ class java/io/PrintStream ]

frame_type = 255 /* full_frame */

offset_delta = 0

locals = [ class com/example/demo/test/TestDemo, class java/lang/String, class java/lang/String, class java/lang/String ]

stack = [ class java/io/PrintStream, int ]

RuntimeVisibleAnnotations:

0: #61()

org.junit.Test

}

SourceFile: “TestDemo.java”

继续向下讲解:

java

false

会发现和上面一样的流程操作,为什么前面会返回true后面返回false。为什么会出现这种情况呢?

通过阅读字节码,会发现"helloWorld"、"java"他们的字节码指令逻辑顺序是一模一样的,为何这里是false呢?公众号Java精选,回复Java面试,获取最新最全面试题,支持在线随时随地刷题。

原因在于"java"在类加载机制过程中执行了System类的System.initializeSystemClass()方法,在方法中调用了sun.misc.Version.init();就将"java"已经加载到常量池中了(字节码中的常量池只是class文件常量池不代码jvm环境的所有常量池,而运行时常量池中已经存在"java"字符串),部分截图如下,会发现"java"常量已经被使用了。

4f4a993efaf204f29c87c6b90393a251.png

故,判断语句变成了,new创建出来的"java"对象,与运行时常量池中的"java"是两个不同的对象,因此返回false。推荐文章:【104期】彻底搞懂 java8 内存结构,再也不纠结方法区和常量池了!

反过来说明,前面之所以返回true的原因在于new创建好"helloWorld"后,当调用intern方法时,不会重新创建一个新的"helloWorld",而是会将创建好的"helloWorld"存入运行时常量池中,此时intern()实际上只是做了一个地址引用(这个结论应该不正确,因为gc也会导致对象移动,我估摸着是真正的将对象移动到了Old区的字符串常量池)。因此当判断str1 == str1.intern()时,他们的地址是同一个地址,也是同一个对象,因此返回true。

总结:这道题目的前面两问区别在于"java"是在程序运行时就已经在运行时常量了,而其它字符串则没有,因此出现不同的结果,同理类似于"java"这类字符串常量的应该还有一些在某些类中有定义。

有了前面的基础后,后面一问

hello

false

不难解释,str3是通过new StringBuilder().toString();创建出来的对象,因此是一个全新的"hello"字符串对象,而调用.intern()方法后,返回的则是常量池中的"hello",两者明显不是同一个对象,因此返回false。

作者:诗水人间

blog.csdn.net/qq_41813208/article/details/109192324

精品资料,超赞福利!

>>Java精选面试题<< - 小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!

3256b2889ee5b4973ba0d0e9eb35e8cb.png

期往精选  点击标题可跳转

总结

我们总是喜欢瞻仰大厂的大神们,但实际上大神也不过凡人,与菜鸟程序员相比,也就多花了几分心思,如果你再不努力,差距也只会越来越大。

面试题多多少少对于你接下来所要做的事肯定有点帮助,但我更希望你能透过面试题去总结自己的不足,以提高自己核心技术竞争力。每一次面试经历都是对你技术的扫盲,面试后的复盘总结效果是极好的!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

期往精选  点击标题可跳转

总结

我们总是喜欢瞻仰大厂的大神们,但实际上大神也不过凡人,与菜鸟程序员相比,也就多花了几分心思,如果你再不努力,差距也只会越来越大。

面试题多多少少对于你接下来所要做的事肯定有点帮助,但我更希望你能透过面试题去总结自己的不足,以提高自己核心技术竞争力。每一次面试经历都是对你技术的扫盲,面试后的复盘总结效果是极好的!

[外链图片转存中…(img-ykze7C9Y-1715476282631)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值