Java——编译与反编译

**

一、基础知识

**

1.1 编程语言

在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language)。编程语言(Programming Language)分为低级语言(Low-level Language)和高级语言(High-level Language)。

机器语言(Machine Language)和汇编语言(Assembly Language)属于低级语言,直接用计算机指令编写程序。

而C、C++、Java、Python等属于高级语言,用语句(Statement)编写程序,语句是计算机指令的抽象表示。

举个例子,同样一个语句用C语言、汇编语言和机器语言分别表示如下:

计算机只能对数字做运算,符号、声音、图像在计算机内部都要用数字表示,指令也不例外,上表中的机器语言完全由十六进制数字组成。最早的程序员都是直接用机器语言编程,但是很麻烦,需要查大量的表格来确定每个数字表示什么意思,编写出来的程序很不直观,而且容易出错,于是有了汇编语言,把机器语言中一组一组的数字用助记符(Mnemonic)表示,直接用这些助记符写出汇编程序,然后让汇编器(Assembler)去查表把助记符替换成数字,也就把汇编语言翻译成了机器语言。

但是,汇编语言用起来同样比较复杂,后面,就衍生出了Java、C、C++等高级语言。

1.2 什么是编译

上面提到语言有两种,一种低级语言,一种高级语言。可以这样简单的理解:低级语言是计算机认识的语言、高级语言是程序员认识的语言。

那么如何从高级语言转换成低级语言呢?这个过程其实就是编译。

从上面的例子还可以看出,C语言的语句和低级语言的指令之间不是简单的一一对应关系,一条a=b+1;语句要翻译成三条汇编或机器指令,这个过程称为编译(Compile),由编译器(Compiler)来完成,显然编译器的功能比汇编器要复杂得多。用C语言编写的程序必须经过编译转成机器指令才能被计算机执行,编译需要花一些时间,这是用高级语言编程的一个缺点,然而更多的是优点。首先,用C语言编程更容易,写出来的代码更紧凑,可读性更强,出了错也更容易改正。

将便于人编写、阅读、维护的高级计算机语言所写作的源代码程序,翻译为计算机能解读、运行的低阶机器语言的程序的过程就是编译。负责这一过程的处理的工具叫做编译器

现在我们知道了什么是编译,也知道了什么是编译器。不同的语言都有自己的编译器,Java语言中负责编译的编译器是一个命令:javac

javac是收录于JDK中的Java语言编译器。该工具可以将后缀名为.java的源文件编译为后缀名为.class的可以运行于Java虚拟机的字节码。

当我们写完一个HelloWorld.java文件后,我们可以使用javac HelloWorld.java命令来生成HelloWorld.class文件,这个class类型的文件是JVM可以识别的文件。通常我们认为这个过程叫做Java语言的编译。其实,class文件仍然不是机器能够识别的语言,因为机器只能识别机器语言,还需要JVM再将这种class文件类型字节码转换成机器可以识别的机器语言。

1.3 什么是反编译

反编译的过程与编译刚好相反,就是将已编译好的编程语言还原到未编译的状态,也就是找出程序语言的源代码。就是将机器看得懂的语言转换成程序员可以看得懂的语言。Java语言中的反编译一般指将class文件转换成java文件。

有了反编译工具,我们可以做很多事情,最主要的功能就是有了反编译工具,我们就能读得懂Java编译器生成的字节码。如果你想问读懂字节码有啥用,那么我可以很负责任的告诉你,好处大大的。比如我的博文几篇典型的原理性文章,都是通过反编译工具得到反编译后的代码分析得到的。如深入理解多线程(一)——Synchronized的实现原理、深度分析Java的枚举类型—-枚举的线程安全性及序列化问题、Java中的Switch对整型、字符型、字符串型的具体实现细节、Java的类型擦除等。我最近在GitChat写了一篇关于Java语法糖的文章,其中大部分内容都用到反编译工具来洞悉语法糖背后的原理。

**

二、Java的编译与反编译

**

2.1 Java 编译

Java的编译有些不同,因为Java的特性是一次编写,到处运行。做到这种效果的主要依据就是JVM。Java的编译是分为两个阶段的,首先,利用JDK自带的编译器,将源代码经过词法分析,语法分析直至语义分析,然后就会产生一个class文件。这段过程称之为前端编译,此时产生的class文件还无法被计算机识别执行,只能算是整个编译过程中产生的一个中间产物。

然后JVM将读取到的二进制文件进行深度编译,将其编译成与具体平台相关的指令代码,这个过程是后端编译,它主要依赖于JVM。前端编译是与操作系统平台无关的,最终生成的class文件是可以在各个JVM平台进行深度编译;而后端编译就需要跟具体操作系统平台相关了,因为JVM有不同平台的版本,可以将这种统一格式的class文件进一步深度编译,将其转换成与具体平台相关的指令代码。

在这里插入图片描述

对于编译器,Java内置的有javac工具,此外很多IDE工具也内置了编译工具,但是这些都是前端编译器,主要功能就是把【.java】文件编程成【.class】文件。

2.1.1 词法分析器

这个阶段是将源程序文件从左到右一个字符一个字符地读入,将字符序列转换为标记(token)序列的过程。这里的标记是一个字符串,是构成源代码的最小单位,该过程中,词法分析器还会对标记进行分类。

词法分析器通常不会关心标记之间的关系(分析关系主要在语法分析阶段)。如:源程序中会有很多括号,但是词法分析器只是将其识别为标记,但是它并不关心这些括号是否能正确匹配(即:如果只有“{”,而没有“}”,词法分析中不会发现问题)。

2.1.2 语法分析器

它是在词法分析的基础上,将单词序列组合成各种短语,如“程序”、“语句”、“表达式”等等。语法分析能够判断源程序在结构上是否正确。

2.1.3 语义分析

该阶段是程序编译的一个逻辑阶段。它是对结构正确的源程序进行上下文有关性质的审查。它主要是审查源程序是否含有语义错误,同时也为代码的生成阶段收集类型信息。
语义分析中的一个很重要的部分就是类型审查,比如很多语言要求数组下标必须为整数,如果使用浮点数作为下标,编译器就会报错;再比如很多程序允许某些类型之间能够进行自动转换等等。
经历过上面的过程之后,就开始生成中间代码,中间代码具有两个很重要的性质:易于生成、能够轻松翻译成目标机器上的语言。著名的解语法糖操作就是在javac中完成的

2.1.4 后端编译

Java在经历过前端编译之后,如果需要执行编译后的class文件,需要借助于JVM,JVM会将class文件中的内容逐条翻译成机器指令,这个解释的过程就是JVM的解释器(Interpreter)的功劳。很明显,这个解释是比较浪费时间的,为了提高这种解释的效率,Java引入了JIT技术。

虽然引入了JIT,Java仍然使用解释器进行代码解释,但是在解释的过程中,随着代码的不断执行,会识别出代码中执行比较频繁的代码段,这段代码就会被标记为“热点代码”。JIT就会将这段热点代码编译后的机器代码进行优化后,缓存起来,下次再执行到这段代码,直接跳过编译过程,使用缓存的机器码。

HotSpot虚拟机中内置了两种JIT编译器:Client Compiler和Server Compiler。目前主流的方式就是采用其中一种编译器与解释器配合工作的方式。那为什么不将其全部编译成热点代码呢?主要是出于资源最大化利用的考虑:在程序中,不可能所有代码都是热点代码,真正频繁执行的代码只是占据很少一部分,如果将那些只执行了一遍就再也不执行的代码也进行缓存,完全就是在浪费缓存资源。另外在将代码转换成热点代码过程中是需要经过一个编译过程的,如果这种只执行一次的代码也要编译,其实也是浪费时间。

在这里插入图片描述

热点检测

要想触发JIT编译,就必须满足热点代码的检测,目前主要有两种热点代码探测的方式:

  1. 基于采样的方式探测(Simple Based Hot Spot Detection):周期性的检测各个线程的栈顶,如果发现某个方法经常出现在栈顶,就可以认为是热点方法。它的缺点很明显:无法精确确认一个方法的热度,另外也容易受到线程阻塞或者别的原因干扰。
  2. 基于计数器的热点探测(Counter Based Hot Spot Detection):虚拟机会为每个方法,甚至是每个代码块建立计数器,统计方法和代码块的执行次数,一旦超过某个阈值就认为是热点方法,触发JIT编译。

HotSpot虚拟机采用的就是上面第二种探测方式,准备了两个计数器:方法计数器和回边计数器。它们分别对应方法调用次数统计和代码循环执行次数统计。

编译优化

其实JIT除了具有缓存的功能,还会对代码做各种优化,例如:逃逸分析、锁消除、锁膨胀、方法内联、空值检查消除、类型检测消除、公共子表达式消除等等。可以搜索相关概念介绍,了解其原理,这里暂时不再赘述。

2.2 Java 反编译

2.2.1 Java反编译工具

常见的Java的反编译工具:javap、jad、jd-gui和cfr

其中,jd-gui提供了UI界面,使用起来很方便

在这里插入图片描述

2.2.2 如何防止反编译

由于我们有工具可以对Class文件进行反编译,所以,对开发人员来说,如何保护Java程序就变成了一个非常重要的挑战。但是,魔高一尺、道高一丈。当然有对应的技术可以应对反编译咯。但是,这里还是要说明一点,和网络安全的防护一样,无论做出多少努力,其实都只是提高攻击者的成本而已。无法彻底防治。

典型的应对策略有以下几种:

  1. 隔离Java程序(让用户接触不到你的Class文件)
  2. 对Class文件进行加密(提高破解难度)
  3. 代码混淆(将代码转换成功能上等价,但是难于阅读和理解的形式)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313758.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

程序员自家种水果,新鲜包邮配送

上次猕猴桃的活动<好多小伙伴&#xff0c;买了一箱尝过后又下单了好几箱。事实证明&#xff0c;品质才是销量的最佳保证。有些粉丝找到我说&#xff0c;自己家也有果园自己种水果&#xff0c;都是当天采摘当天发货的纯天然水果。于是他们给我寄了一些自家种的苹果、香瓜、冬…

2016-2017 ACM-ICPC CHINA-Final(7 / 12)

2016-2017 ACM-ICPC CHINA-Final A. Number Theory Problem&#xff08;规律、签到&#xff09; #include <bits/stdc.h>using namespace std;int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdo…

【招聘(广州)】-年薪30W起-自助打印领域业内第一

印萌是一家为高校打印店提供整套“无人自助打印”解决方案的互联网科技公司&#xff0c;已获得数百万元融资&#xff0c;公司正向盈利。目前产品覆盖清华大学、北京大学、中山大学、复旦大学、浙江大学等700多所高校&#xff0c;多达1800间打印店&#xff0c;累计为全国1200万大…

尾递归

1、递归 简单的来说递归就是一个函数直接或间接地调用自身&#xff0c;是为直接或间接递归。一般来说&#xff0c;递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时&#xff0c;递归前进&#xff1b;当边界条件满足时&#xff0c;递归返回。 用递归需要注意以…

小 Q 与函数求和 1(牛客练习赛 81 E)

小 Q 与函数求和 1 ∑i1n∑j1nϕ(ijgcd⁡(i,j)K)∑i1n∑j1ngcd⁡(i,j)Kϕ(ij)∑i1n∑j1ngcd⁡(i,j)Kϕ(i)ϕ(j)gcd⁡(i,j)ϕ(gcd⁡(i,j))∑i1n∑j1ngcd⁡(i,j)K1ϕ(i)ϕ(j)ϕ(gcd⁡(i,j))∑d1ndK1inv(ϕ(d))∑i1nd∑j1ndϕ(id)ϕ(jd)[gcd⁡(i,j)1]∑d1ndK1inv(phi(d))∑k1ndϕ(…

asp.net core 中使用 signalR(二)

asp.net core 使用 signalR&#xff08;二&#xff09;Intro上次介绍了 asp.net core 中使用 signalR 服务端的开发&#xff0c;这次总结一下web前端如何接入和使用 signalR&#xff0c;本文主要分两部分&#xff0c;一是直接使用 aspnet/signalr 这个微软开发好的 signalR 的客…

Java位运算实现加、减、乘、除、取余(Mark)

先mark&#xff0c;后续再搞 位运算基础&#xff1a; https://blog.csdn.net/goskalrie/article/details/52796360 加减乘除 1&#xff1a;https://blog.csdn.net/zuochao_2013/article/details/79183621 2&#xff1a;https://www.jianshu.com/p/7bba031b11e7 https://ww…

小 Q 与树(dsu on tree + segment tree)牛客练习赛 81 D

小 Q 与树 给定一棵带权的树&#xff0c;每条边的距离都为111&#xff0c;要我们求∑u1n∑v1nmin(au,av)dis(u,v)\sum\limits_{u 1} ^{n} \sum\limits_{v 1} ^{n}min(a_u, a_v)dis(u, v)u1∑n​v1∑n​min(au​,av​)dis(u,v)&#xff0c; min(au,av)dis(u,v)min(au,av)(dep…

多场景抢红包业务引发.NETCore下使用适配器模式实现业务接口分离

事情的起因我们公司现有一块业务叫做抢红包&#xff0c;最初的想法只是实现了一个初代版本&#xff0c;就是给指定的好友单发红包&#xff0c;随着业务的发展&#xff0c;发红包和抢红包的场景也越来越多&#xff0c;目前主要应用的场景有&#xff1a;单聊发红包、群聊发红包、…

设计模式——创建型模型

目录 单例模式&#xff08;singleton&#xff09;构建模式&#xff08;Builder&#xff09;原型模式&#xff08;Prototype&#xff09;工厂方法模式&#xff08;Factory&#xff09;抽象工厂模式&#xff08;Abstract Factory&#xff09; ** 一、5种创建型模型 ** 1.1 单…

Mr. Panda and Kakin(拓展欧几里得 + O(1)快速乘)

Mr. Panda and Kakin 给定n,cn, cn,c&#xff0c;要我们找到nnn是两个相邻质数的乘积&#xff0c;要我们找到xxx&#xff0c;满足x2303≡c(modn)x ^{2 ^{30} 3} \equiv c \pmod nx2303≡c(modn)&#xff0c;1010≤n≤1018,0<c<n10 ^{10} \leq n \leq 10 ^ {18}, 0 <…

【C】KoobooJson在asp.net core中的使用

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。本文链接&#xff1a;https://blog.csdn.net/j_teng/article/details/100924973“KoobooJson是一款体积小巧没有任何依赖且性能表现强劲的Json工具…

单例模式的创建方式

说明&#xff1a; 以下均为线程安全的实现方式。 懒汉、饿汉的非线程安全的意义不大&#xff0c;未实现。 1. 饿汉模式 类初始化时直接创建对象 public class Singleton {private static Singleton singleton new Singleton();//饿汉模式&#xff0c;类初始化时直接创建pub…

P3899 [湖南集训]谈笑风生(线段树合并)

P3899 [湖南集训]谈笑风生 给定一颗以111号节点为根的树&#xff0c;如果a≠ba \neq ba​b&#xff0c;且aaa是bbb的祖先&#xff0c;则aaa比bbb更厉害&#xff0c;如果a≠ba \neq ba​b&#xff0c;且dis(a,b)≤xdis(a, b) \leq xdis(a,b)≤x&#xff0c;xxx为给定的一个…

【DevOps进行时】C/S端界面自动化测试:微软UIAutomation实践

在界面自动化测试领域里存在许多流行的自动化测试工具&#xff0c;例如目前比较受欢迎的开源自动化工具Selenium、Katalon&#xff1b;HP旗下知名的商业软件Unified Functional Testing(更名前叫QTP)&#xff1b;隶属于IBM以数据驱动测试的RTF&#xff08;Rational Functional …

代码编辑器横评:为什么 VS Code 能拔得头筹

2015 年 4 月 29 日的 Build 大会上&#xff0c;微软发布了 Visual Studio Code 第一个预览版本。短短四年时间里&#xff0c;VS Code 高速成长。根据 2019 年 2 月的 PYPL Top IDE index 的排名&#xff0c;VS Code 的涨势迅猛&#xff0c;在所有编辑器与 IDE 中排名第六&…

A. Slackline Adventure(思维 + 莫比乌斯)(2018-2019 ACM-ICPC Brazil Subregional Programming Contest)

A. Slackline Adventure 考虑枚举每个矩形的长跟宽&#xff0c;再统计这个矩形能在坐标轴上出现几次&#xff08;同行相邻同列相邻的单独算&#xff09;&#xff0c;然后有如下式子&#xff1a; 2∑i1n−1∑j1m−1(n−i)(m−j)[gcd⁡(i,j)1][L2≤i2j2≤R2]2 \times \sum_{i 1…

设计模式——结构型模型

一&#xff1a;目录 1. 装饰者模式&#xff08;Decorator&#xff09; 2. 代理模式&#xff08;Proxy&#xff09; 3. 组合模式&#xff08;Composite&#xff09; 4. 桥接模式&#xff08;Bridge&#xff09; 5. 适配器模式&#xff08;Adapter&#xff09; 6. 蝇量模式&#…

D. Best Edge Weight(最小生成树 + 树链剖分)(Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals))

D. Best Edge Weight 给定一个有nnn个点mmm条边的无向连通图&#xff0c;有mmm次询问&#xff0c;每次询问第iii条边的权值最大为多少&#xff0c;这张图的所有最小生成树的方案中&#xff0c;一定包含第iii条边。 先跑一边最小生成树&#xff0c;得到最小生成树&#xff0c;…

利用Helm简化Kubernetes应用部署(1)

目录利用Helm简化Kubernetes应用部署 Helm基础 安装Helm 使用Visual Studio 2019为Helm编写一个简单的应用 利用Helm简化Kubernetes应用部署Helm是Kubernetes生态系统中的一个软件包管理工具&#xff0c;有点类似于Linux操作系统里面的“apt-get”和“yum”。结合上一节内容&am…