当前位置: 首页 > 科技观察

为什么在Java代码中加一个空行,class文件就翻脸不认人了?_0

时间:2023-03-15 01:28:13 科技观察

为了写出这几行优美的代码,主要是让它输出优美的音符,我下了苦功夫。别以为简单,我打印出来给普通保洁阿姨看,阿姨们连xjjdog都认不出来了。别说代码了,中英混血秒杀一众高官。publicclassHelloWorld{publicstaticvoidmain(String[]args){System.out.println("lovexjjdog");}}说爱我有那么难吗?为什么有那么多废话?本次讨论的主要问题是,给Java源文件添加一个空行后,它生成的字节码会不会发生变化?1.背对人。Java号称一次编译到处运行,大概是class文件的缘故吧。不同的Java版本编译出来的class文件肯定是不一样的,因为里面有个版本号,肯定会影响到它们的内容。我们来看一下,如果在上面的代码中加入一个空行,它的class文件会不会发生变化。这个空行不能随便加。可能在xjjdog上面,也可能在下面。它可能在{中,也可能在文件末尾。(1)打脸之前,先看一下当前class文件的md5值。我很喜欢被打脸,所以我们先来看一个加空行也无所谓的情况。重新编译后看md5值,果然是被打脸了。好在我已经练就了不心动不脸红的能力,所以我就硬着脸皮接受了这个结果。(二)上药为了呼应主题,抚慰受伤的心灵,我们把空行母搬到了这里。再次编译后,看md5值(怎么感觉这句话已经说完了)。变了。这次真的变了。使用hexdump命令分析两次生成的字节码,发现只有一个数字发生了变化。2.Saodeis特别不喜欢分析这种二进制的东西。虽然魔数CAFEBABE在第一行就很形象。咖啡宝贝?为什么听起来像某个数字?下面我们用javap来看一下它的原型。javap-p-vHelloWorld.class通过对比两次生成的字节码,我们最终发现这个变化是由一个叫做LineNumberTable的结构引起的。使用asmtools.jar深入了解此结构会显示相同的信息。LineNumberTable显示了Java源代码行号和字节码指令的对应关系。前面的数字代表Java源代码中的行号,冒号后面的代表字节码中每一行指令的映射关系。调试代码时,可以快速定位,顺利进行。也就是说,这些都是辅助信息,我们可以在编译的时候把它擦掉。如何擦除它?给javac一个参数就可以了。像javac-g:noneHelloWorld.java这样编译后的字节码,简洁优雅,无用。无论添加多少空行,生成的字节码都是一样的。但是,我们不能再自由调试了。{publicHelloWorld();descriptor:()Vflags:ACC_PUBLICode:stack=1,locals=1,args_size=10:aload_01:invokespecial#1//Methodjava/lang/Object."":()V4:returnpublicstaticvoidmain(java.lang.String[]);描述符:([Ljava/lang/String;)Vflags:ACC_PUBLIC,ACC_STATICCode:stack=2,locals=1,args_size=10:getstatic#2//Fieldjava/lang/System.out:Ljava/io/PrintStream;3:ldc#3//StringHelloxjjdog5:invokevirtual#4//Methodjava/io/PrintStream.println:(Ljava/lang/String;)V8:return}如果你想让字节码在开发阶段香喷喷的,可以直接使用参数-g开启所有调试信息。IDEA可以在编译选项中开启这个参数。很多同学在编译后的代码中找不到局部变量的符号表,也是没有启用这个参数造成的。END麻雀虽小,五脏俱全。能写出HelloWorld就证明你已经凌驾于大多数人之上,能够理解这些东西就证明你已经凌驾于大多数人之上。难怪大家都说:少了一个程序员。HelloWorld,表面上看是五六个人,其实背后都有自己的小99。