盘点 java 中 90% 的人都不知道的坑

150 阅读3分钟

神奇的代码注释

该代码输出循环的次数,你觉得 count 的值是多少呢?

public class MagicTest {
​
    public static void main(String[] args) {
        int count = 0;
        for (int i = 0; i < 100; i++) {
            // \u000a\u007d\u007b
            count++;
        }
        System.out.println("count = " + count);
    }
}
​

以上代码在新版idea中会提示报错,不允许这么写了,我们在文本编辑器中写,手动编译

不要有包名,有包名在运行 class 文件时会报错

  1. 新建 MagicTest.java,将上面内容复制进去,进入cmd窗口
  1. 输入 javac MagicTest.java,会生成 MagicTest.class
  1. 然后输入 java MagicTest,不要带 class后缀
  2. 可以看到输出结果:count = 1

答案是 1,不应该是100吗,我们来详细看一下

我们反编译一下刚才的 class 文件,javap -c MagicTest.class

E:\code>javap -c MagicTest.class
Compiled from "MagicTest.java"
public class MagicTest {
  public MagicTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iconst_0
       3: istore_2
       4: iload_2
       5: bipush        100
       7: if_icmpge     16
      10: iinc          2, 1
      13: goto          4
      16: iinc          1, 1
      19: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      22: new           #3                  // class java/lang/StringBuilder
      25: dup
      26: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      29: ldc           #5                  // String count =
      31: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      34: iload_1
      35: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      38: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      41: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      44: return
}

我也看不太懂,大概意思count只进行了一次++

我们将这个 MagicTest.class 文件拖到 idea中看一下

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//public class MagicTest {
    public MagicTest() {
    }
​
    public static void main(String[] var0) {
        int var1 = 0;
​
        for(int var2 = 0; var2 < 100; ++var2) {
        }
​
        ++var1;
        System.out.println("count = " + var1);
    }
}
​

可以看到,for 循环了个空,然后对 count + 1 ,接着输出了结果

原因是:Java 编译器会解析Unicode 转义序列\u000a 是换行符,\u007d 是字符“}”,\u007b 是字符“{”

所以最上面的代码就变成了

public class MagicTest {
​
    public static void main(String[] args) {
        int count = 0;
        for (int i = 0; i < 100; i++) {
            // 
        }{
            count++;
        }
        System.out.println("count = " + count);
    }
}

新版本idea不允许这么写了,这么写很容易挨打的!!

这么写会报错吗?

public class MagicTest {
​
    public static void main(String[] args) {
        https://juejin.cn/
        System.out.println("Hello world");
    }
}

答案是不会

上方的 https:是java中的 goto语法的标识,带大家回忆一下java基础,进入循环后直接跳出该循环

    public static void main(String[] args) {
        label:
        for (int j = 0; j < 10; j++) {
            if (true) {
                break label;
            }
        }
        System.out.println("hello world");
    }

Integer == 比较的坑

众所周知,JVM 中有个常量池,Integer 的范围是 [-128,127]

我们先看一下在范围内的情况

Integer integer1 = 1;
Integer integer2 = 1;
System.out.println(integer1 == integer2);
​
Integer integer3 = -128;
Integer integer4 = -128;
System.out.println(integer3 == integer4);
​
Integer integer5 = 127;
Integer integer6 = 127;
System.out.println(integer5 == integer6);

输出结果为:

true
true
true

在范围外的情况

Integer integer7 = -129;
Integer integer8 = -129;
System.out.println(integer7 == integer8);
​
Integer integer9 = 128;
Integer integer10 = 128;
System.out.println(integer9 == integer10);

输出结果为:

false
false

还有一个情况:

Integer integer11 = new Integer("1");
Integer integer12 = new Integer("1");
System.out.println(integer11 == integer12);

注意这里是 new 的对象,跟常量池就没关系了,== 比较的是对象的地址,那肯定不一样,所以输出结果为 false

总结

本文介绍了三个容易被忽略的例子,分别是Unicode 转义,goto语法,Interger == 比较的用法,如果开发过程中不加注意,可能会埋坑,所以还得加强学习呀,共勉!