为什么.class文件查看不了_为什么给Java代码加个空行,class文件就翻脸不认人了?...

1da8eeb925f31758bfc4403b028df8e0.gif

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("love xjjdog");
     }
}

为了写出这几行优美的代码,主要是为了让它输出优美动听的乐符,我下了一番功夫。你不要觉得简单,我把它打印出来给普通的保洁阿姨去看,阿姨竟然连xjjdog都认不出来。别说代码了,中英文混血,就秒杀一大堆高干分子。

想说爱我就那么难么?怎么这么多的废话呢?这次探讨的主要问题是,给Java源文件加个空行之后,它生成的字节码,会有变化么?

1、翻脸不认人

Java号称一次编译到处运行,大概就是class文件的功劳。不同的Java版本编译之后的class文件那是肯定不一样的,因为里面有一个版本号,那肯定影响了它们的内容。

我们就看一下,如果给上面的代码,加一个空行,它的class文件会不会变。

这个空行还不能随便加。它可能在xjjdog上面,也可能在下面。可能在{中,也可能在文件末尾。

1.1、打脸

在验证之前,我们先看一下当前的class文件md5值。

dbb3af34811a59793a25f82e3da7e2e6.png

我非常喜欢被打脸,所以先看一种加空行也无所谓的情况。9f230d08bfe35a0cf1193c17fc7848c0.png

再次编译之后看md5值,果然被打脸了。还好我已经练就了脸不红心不跳的本领,这个结果厚着脸皮接受。

b7a05ef8b19348f481b1846b8f3b9129.png

1.2、抹药

为了和主题遥相呼应,安慰一下受伤的心灵,我们把空行转移到了这里。c09079144d1dc3a136d58ed914ed1859.png

再次编译之后,看md5值(怎么感觉这句话已经说过了呢)。

变了。这次真的变了。b7b1639de567af760c90bc8f1756f8c0.png

使用hexdump命令分析两次生成的字节码,发现其中只不过变了一个数字。

ce34548ab9c4e7c5c0e76cd7bd50d273.png

2、骚戴斯乃

特别不喜欢分析这种二进制的东西。虽然CAFEBABE这个魔数在第一行历历在目。咖啡宝贝?怎么听着像是某个番号?

我们还是用javap来看一下它的原型。

javap -p -v HelloWorld.class

通过对比两次生成的字节码,我们终于发现了这个变动,是一个叫做LineNumberTable的结构引起的。

49543c93f775afbaffcc2b3f605511d2.png

使用asmtools.jar深入分析这个结构,可以看到同样的信息。

f7e19d76b6829d3b6780dc0f6e03f9be.png

LineNumberTable展示了Java源码行号和字节码指令的对应关系。前面的数字代表Java源代码中的行号,而冒号后面的则代表字节码里每行指令的映射关系。在对代码进行调试的时候,能够快速定位,顺利进行。

也就是说,这些是辅助信息,我们可以在编译的时候抹掉它。怎么抹掉呢?给javac一个参数就ok了。

javac -g:none HelloWorld.java

这样编译后的字节码,紧凑、优雅、无用。不管你加多少空行,生成的字节码都是一样的。可是,我们再也不能畅快淋漓的进行调试了。

{
public HelloWorld();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello xjjdog
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}

要想在开发阶段让字节码又香又有用,可以直接使用参数-g开启所有调试信息。IDEA可以在编译选项里对这个参数进行开启。有很多同学在编译之后的代码里找不到局部变量的符号表,也是由于这个参数没有开启所引起的。

18d7f1b7b6aa1b7f27b8a2ad78f7f873.png

END

麻雀虽小,五脏俱全。能写HelloWorld,就证明已经凌驾于大部分人之上,能了解这些东西,就证明已经是人上之人。怪不得大家都说:就差一个程序员了。

HelloWorld,表面上看起来人五人六,原来背地里都有自己的小99啊。

作者简介:小姐姐味道  (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。

近期热门文章

《996的乐趣,你是无法想象的》魔幻现实主义,关爱神经衰弱

《一切荒诞的傲慢,皆来源于认知》不要被标题给骗了,画面感十足的消遣文章

《必看!java后端,亮剑诛仙》后端技术索引,中肯火爆。全网转载上百次。

《学完这100多技术,能当架构师么?(非广告)》精准点评100多框架,帮你选型

45c58fa2b64d749c227322d83a03406d.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值