两道小题目

本贴最后更新于 2730 天前,其中的信息可能已经时异事殊

两道小题目

@Test
public void test7() {
    String s1 = "abc";
    String s2 = "ab";
    String s3 = "c";
    String s4 = s2 + s3;

    String st0 = "helloworld";
    String st1 = "helloworld";
    String st2 = "hello" + "word";

    System.out.println(st0 == st2);
    System.out.println(s1 == (s2 + s3));
    System.out.println(s1 == s4);
}
@Test
public void test8() {
    int i = 0;
    i = i++;
    System.out.println(i);
}
  • 第一题结果均为 false
  • 第二题结果为 0

解析

利用 javap 反汇编查看 jvm 执行指令

第一题

public void test7();
  Code:
     0: ldc           #39                 // String abc
     2: astore_1
     3: ldc           #40                 // String ab
     5: astore_2
     6: ldc           #41                 // String c
     8: astore_3
     9: new           #19                 // class java/lang/StringBuilder
    12: dup
    13: invokespecial #20                 // Method java/lang/StringBuilder."<init>":()V
    16: aload_2
    17: invokevirtual #22                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    20: aload_3
    21: invokevirtual #22                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    24: invokevirtual #25                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    27: astore        4
    29: ldc           #42                 // String helloworld
    31: astore        5
    33: ldc           #42                 // String helloworld
    35: astore        6
    37: ldc           #43                 // String helloword
    39: astore        7
    41: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
    44: aload         5
    46: aload         7
    48: if_acmpne     55
    51: iconst_1
    52: goto          56
    55: iconst_0
    56: invokevirtual #33                 // Method java/io/PrintStream.println:(Z)V
    59: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
    62: aload_1
    63: new           #19                 // class java/lang/StringBuilder
    66: dup
    67: invokespecial #20                 // Method java/lang/StringBuilder."<init>":()V
    70: aload_2
    71: invokevirtual #22                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    74: aload_3
    75: invokevirtual #22                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    78: invokevirtual #25                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    81: if_acmpne     88
    84: iconst_1
    85: goto          89
    88: iconst_0
    89: invokevirtual #33                 // Method java/io/PrintStream.println:(Z)V
    92: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
    95: aload_1
    96: aload         4
    98: if_acmpne     105
   101: iconst_1
   102: goto          106
   105: iconst_0
   106: invokevirtual #33                 // Method java/io/PrintStream.println:(Z)V
   109: return

可以看出字符串变量相加实际上 JVM 是优化为 java/lang/StringBuilder.append, 最终输出为 java/lang/StringBuilder.toString。

new String 则是直接引用堆中的对象,而 “” 则是引用常量池中的字符串, 这就是三个输出均为 false 的原因。

第二题

public void test8();
  Code:
     0: iconst_0  -- 将常量0加载进栈中, 入栈
     1: istore_1 -- 将栈顶int赋值给变量1,出栈
     2: iload_1 -- int变量1入栈
     3: iinc          1, 1 -- 变量1自增1,不会入栈 i = 1
     6: istore_1 -- 将栈顶int赋值给变量1,出栈 i = 0
     7: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
    10: iload_1 -- int变量1入栈
    11: invokevirtual #29                 // Method java/io/PrintStream.println:(I)V
    14: return

由于执行完 iinc 1, 1 指令之后并没有将变量 i 入栈,然后直接将栈顶的 0 赋值给了变量 i

而栈顶的 0 来自于 i++ 的 0。这就导致了最终的输出结果0

对比

@Test
public void test8() {
    int i = 0;
    i++;
    System.out.println(i);
}
public void test8();
  Code:
     0: iconst_0
     1: istore_1
     2: iinc          1, 1
     5: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
     8: iload_1
     9: invokevirtual #29                 // Method java/io/PrintStream.println:(I)V
    12: return
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3167 引用 • 8207 回帖

相关帖子

9 回帖

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • yanny

    String st1 = "helloworld";
    String st2 = "hello" + "word";
    word 改成 world 是相等的

    1 回复
  • yangyujiao

    1477635091992

    这是怎么看的,,,怎么出现的这些过程。。。

    1 回复
  • yangyujiao

    1477635184397

    这样看的???

  • eddy
    作者

    是的,就是考你细心不,哈哈。

  • eddy
    作者

    javap -c classpath 比如
    javap -c ~/test.class

  • MrWang

    第一题第一个就是 true,是你把 world 写错成 word。它怎么也不会变成 true。

  • MrWang

    第二题实际上,也不用考虑这么复杂, i++ 的意思就是先使用在自加,所以那时候赋值 0

  • eddy
    作者

    补充一下 之所以 i = i++ 在执行 iinc 1, 1 自增指令之前会执行 iload_1 指令,是因为需要将 i++ 赋值给其他变量(也可赋值给 i),所以需要将 i 的初始值加载到栈中。

  • eddy
    作者

    最后再用栈顶的值给待赋值的变量(也可以是变量 i)赋值,所以最后的结果变成了 0,变量 i 也曾经为 1 过,只是没有入栈就又被赋值为了 0。

请输入回帖内容 ...