Java为什么解释执行时不直接解释源码?

原文地址:http://www.zhihu.com/question/34345694

Java源码为什么会经过中间步骤转换为字节码,这样不是增加工作量吗?直接解释源代码一样跨平台。

为什么不在解释运行时直接解释源代码,而是字节码。


  1. 字节码更便于虚拟机读取,不用在解析字符串,所以运行速度比直接解析源代码快。
  2. 语法是会变的,而源代码中没有版本信息,而字节码中不但有版本信息,还可以经由编译过程抹平一些语言层面的变化(即语言语法虽然有变化,但字节码依然遵照原来的规则即可)。
  3. 字节码也可以由其他语言生成,如Groovy,Clojure,Scala。需要注意的事,既然这些语言可以编译成字节码,也就可以被Java或其他JVM语言调用。
  • 然而归根到底,没有必须这么设计的绝对理由,很多事物之所以会这样,只是因为被设计成这样。

  • Java严格说来是“半解释半编译”型的语言
  • Java代码首先由javac编译成字节码(ByteCode)。ByteCode是JVM唯一能够识别的指令,JVM将ByteCode翻译成真正能够执行的机器码
  • 字节码的规范由JVM规范(The Java® Virtual Machine Specification)定义,JVM在不同的硬件平台上需要有不同实现,以达到所谓“一次编写,到处运行”的目标。
理论上,完全可以直接解释源码,这样也可以跨平台。而引入字节码有额外的好处:
  • 直接执行字节码,比解释源码再执行,会更快。
  • 生成字节码过程中,编译器可以预先作语法错误或者安全性方面的检查,出错机会更少。
  • 字节码比源码更加紧凑,文件尺寸更小,方便网络传输。
  • 有些嵌入设备,不够资源跑起完整的编译器,这些设备只需要嵌入一个小巧的JVM就行了,在额外的平台上编译源码。
  • 字节码不一定非要java源码生成,其它一些语言比如scala也可以编译生成字节码。这样其它语言就可以利用上经过多年发展的JVM。

一切源于更好的设计
1、快
2、跨平台
3、可扩展
4、《the java specification》 和 《 the JVM specification》是分开的,设计之初就承诺支持其他语言编译成字节码,比如 JRuby,scala ,Jython等

CPU从内存或者寄存器中读取数据,而不是直接从硬盘中读取数据!
和这个道理差不多!
为了跨平台,编译成的字节流文件.class,与硬件和操作系统无关,这是跨平台基础,然后具体执行,再用各自平台解释器,解释成本地机器码。另外还有一个安全性的问题,编译的结果本身保证了代码安全和版权。
作者:火雨
链接:http://www.zhihu.com/question/34345694/answer/59501996
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

其实,Java作为一个高级语言,便于开发者阅读和理解代码,jvm虚拟机用于执行代码指令,而指令就不会像源代码那样有很强可读性,另外,class文件内容紧凑,使用空间小,jvm加载类支持从网络加载class文件流,这样可以减少网络带宽,提高性能。
Javac编译过程中,并不是简单的理解为编译成虚拟机能够识别的指令那么简单,在编译过程中,需要对源码进行词法分析,语法分析,语义分析,最后生成字节码。我们都知道Java语言,内存是自动管理的,一个对象实例内存空间的申请、分配和回收都是虚拟机自己去管理的。Java内存分配有动态内存分配,也有静态内存分配,静态内存分配就是在编译时候,就确定需要分配的内存大小,如类的静态常量,对于一些大小不可知的对象,只有运行时才能确定需要申请的空间大小。所以静态分配性能相对动态分配比较高一些。由此看出,Java编译成字节码,除了将源码编译成虚拟机可执行的字节码,也做了一些其他准备工作。
因此,若将源码替代字节码,虚拟机直接执行源码的话,要么程序员将源码写成字节码那样的,这样对程序员不友好,另外就是当虚拟机加载某个类,或者实例化某个对象的时候,虚拟机做一些与编译器类似的工作,但是这样性能会收到很大的影响。
理解的比较浅,可能有很多地方不正确,希望大家一起探讨。
Java9 添加了一个新工具,JShell,然后我下了 ea 版本来尝鲜。应该说从 Java9 开始,Java 就有工具来通过直接解释源码运行程序了(指的是表面上,底层应该还是先生成字节码然后再运行)。
首先写个计算 pi 的程序:
<img src="https://pic4.zhimg.com/34a2775021ca4db77ac604d6d84a74b3_b.png" data-rawwidth="859" data-rawheight="326" class="origin_image zh-lightbox-thumb" width="859" data-original="https://pic4.zhimg.com/34a2775021ca4db77ac604d6d84a74b3_r.png">
然后用 JShell 来运行:
<img src="https://pic1.zhimg.com/97078a23dbd40e7a559fb308a83236ac_b.png" data-rawwidth="409" data-rawheight="46" class="content_image" width="409">是的,你没有看错,以后 Java 居然也可以当脚本语言来用了。当然,比起 Scala 和 Groovy,Java写起来时稍微啰嗦了一点(虽然在这个例子中不是很明显)。不过,这已经很棒了(毕竟这是 Java 嘛 :) ) 是的,你没有看错,以后 Java 居然也可以当脚本语言来用了。当然,比起 Scala 和 Groovy,Java写起来时稍微啰嗦了一点(虽然在这个例子中不是很明显)。不过,这已经很棒了(毕竟这是 Java 嘛 :) )
目前 JShell 的缺点第一在于启动时间较长(JVM的启动时间+JShell自身的启动时间),后期应该会有所改善;第二就是目前内置的方法太少,好吧其实目前只内置了 printf 一个方法...;第三个问题应该是在于Java语言本身,缺少一个 var 关键字(JEP 286 考虑为 Java 添加这一特性,应该有希望在 Java10 中能实现, JEP 286: Local-Variable Type Inference

我就补充点R大的回复。。

Interpreation the source code is OK, but might be slow in many places because of absent of any optimization. By translation, the generate code can be somewhat optimized or simplified.

Norammly, there are a lot of mode for interpretation.
1) Interprete source code directly.
2) Interprete IR, eg. bytecode.
3) between 1) and 2), e.g., interprete AST tree.
4) Translate AST to native code and execute.
5) ..
Many interpreters would mix above four modes. For example, JIT compilation for Java/JavaScript which mixes of bytecode interpretation and native code execution in many projects.

The decison is made for the performance/memory/ factors. For example, the interpreter in CRuby under 1.9 is AST interpreter that does not generate bytecode. However, it generates bytecode since V1.9 for the performance purpose. Similarly, the JRuby+Truffle take the idea of early CRuby. The interpreter walks on the AST tree and then Truffle(Graal) compiles the code and execution. This is also performance purpose.

其实,Java作为一个高级语言,便于开发者阅读和理解代码,jvm虚拟机用于执行代码指令,而指令就不会像源代码那样有很强可读性,另外,class文件内容紧凑,使用空间小,jvm加载类支持从网络加载class文件流,这样可以减少网络带宽,提高性能。
Javac编译过程中,并不是简单的理解为编译成虚拟机能够识别的指令那么简单,在编译过程中,需要对源码进行词法分析,语法分析,语义分析,最后生成字节码。我们都知道Java语言,内存是自动管理的,一个对象实例内存空间的申请、分配和回收都是虚拟机自己去管理的。Java内存分配有动态内存分配,也有静态内存分配,静态内存分配就是在编译时候,就确定需要分配的内存大小,如类的静态常量,对于一些大小不可知的对象,只有运行时才能确定需要申请的空间大小。所以静态分配性能相对动态分配比较高一些。由此看出,Java编译成字节码,除了将源码编译成虚拟机可执行的字节码,也做了一些其他准备工作。
因此,若将源码替代字节码,虚拟机直接执行源码的话,要么程序员将源码写成字节码那样的,这样对程序员不友好,另外就是当虚拟机加载某个类,或者实例化某个对象的时候,虚拟机做一些与编译器类似的工作,但是这样性能会收到很大的影响。
理解的比较浅,可能有很多地方不正确,希望大家一起探讨。

直接解释源代码,而且跨平台。
这样的编程语言真的有啊,php,python。要说效率,还是java高些。
本来编译型就比解释型的要快一些,另外jvm在运行时还会优化代码。

原文








本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部