原文地址:http://www.zhihu.com/question/34345694
Java源码为什么会经过中间步骤转换为字节码,这样不是增加工作量吗?直接解释源代码一样跨平台。
为什么不在解释运行时直接解释源代码,而是字节码。
- 字节码更便于虚拟机读取,不用在解析字符串,所以运行速度比直接解析源代码快。
- 语法是会变的,而源代码中没有版本信息,而字节码中不但有版本信息,还可以经由编译过程抹平一些语言层面的变化(即语言语法虽然有变化,但字节码依然遵照原来的规则即可)。
- 字节码也可以由其他语言生成,如Groovy,Clojure,Scala。需要注意的事,既然这些语言可以编译成字节码,也就可以被Java或其他JVM语言调用。
- 然而归根到底,没有必须这么设计的绝对理由,很多事物之所以会这样,只是因为被设计成这样。
作者:火雨
链接:http://www.zhihu.com/question/34345694/answer/59501996
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
链接:http://www.zhihu.com/question/34345694/answer/59501996
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
其实,Java作为一个高级语言,便于开发者阅读和理解代码,jvm虚拟机用于执行代码指令,而指令就不会像源代码那样有很强可读性,另外,class文件内容紧凑,使用空间小,jvm加载类支持从网络加载class文件流,这样可以减少网络带宽,提高性能。
Javac编译过程中,并不是简单的理解为编译成虚拟机能够识别的指令那么简单,在编译过程中,需要对源码进行词法分析,语法分析,语义分析,最后生成字节码。我们都知道Java语言,内存是自动管理的,一个对象实例内存空间的申请、分配和回收都是虚拟机自己去管理的。Java内存分配有动态内存分配,也有静态内存分配,静态内存分配就是在编译时候,就确定需要分配的内存大小,如类的静态常量,对于一些大小不可知的对象,只有运行时才能确定需要申请的空间大小。所以静态分配性能相对动态分配比较高一些。由此看出,Java编译成字节码,除了将源码编译成虚拟机可执行的字节码,也做了一些其他准备工作。
因此,若将源码替代字节码,虚拟机直接执行源码的话,要么程序员将源码写成字节码那样的,这样对程序员不友好,另外就是当虚拟机加载某个类,或者实例化某个对象的时候,虚拟机做一些与编译器类似的工作,但是这样性能会收到很大的影响。
理解的比较浅,可能有很多地方不正确,希望大家一起探讨。
Javac编译过程中,并不是简单的理解为编译成虚拟机能够识别的指令那么简单,在编译过程中,需要对源码进行词法分析,语法分析,语义分析,最后生成字节码。我们都知道Java语言,内存是自动管理的,一个对象实例内存空间的申请、分配和回收都是虚拟机自己去管理的。Java内存分配有动态内存分配,也有静态内存分配,静态内存分配就是在编译时候,就确定需要分配的内存大小,如类的静态常量,对于一些大小不可知的对象,只有运行时才能确定需要申请的空间大小。所以静态分配性能相对动态分配比较高一些。由此看出,Java编译成字节码,除了将源码编译成虚拟机可执行的字节码,也做了一些其他准备工作。
因此,若将源码替代字节码,虚拟机直接执行源码的话,要么程序员将源码写成字节码那样的,这样对程序员不友好,另外就是当虚拟机加载某个类,或者实例化某个对象的时候,虚拟机做一些与编译器类似的工作,但是这样性能会收到很大的影响。
理解的比较浅,可能有很多地方不正确,希望大家一起探讨。
Java9 添加了一个新工具,JShell,然后我下了 ea 版本来尝鲜。应该说从 Java9 开始,Java 就有工具来通过直接解释源码运行程序了(指的是表面上,底层应该还是先生成字节码然后再运行)。
首先写个计算 pi 的程序:
<img src="https://i-blog.csdnimg.cn/blog_migrate/8c28b5f6a01d2bfcf5a14aa0415bbb07.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://i-blog.csdnimg.cn/blog_migrate/a181cecb79226e6c2ce395355e8accb8.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)
首先写个计算 pi 的程序:
<img src="https://i-blog.csdnimg.cn/blog_migrate/8c28b5f6a01d2bfcf5a14aa0415bbb07.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://i-blog.csdnimg.cn/blog_migrate/a181cecb79226e6c2ce395355e8accb8.png" data-rawwidth="409" data-rawheight="46" class="content_image" width="409">是的,你没有看错,以后 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.
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编译成字节码,除了将源码编译成虚拟机可执行的字节码,也做了一些其他准备工作。
因此,若将源码替代字节码,虚拟机直接执行源码的话,要么程序员将源码写成字节码那样的,这样对程序员不友好,另外就是当虚拟机加载某个类,或者实例化某个对象的时候,虚拟机做一些与编译器类似的工作,但是这样性能会收到很大的影响。
理解的比较浅,可能有很多地方不正确,希望大家一起探讨。
Javac编译过程中,并不是简单的理解为编译成虚拟机能够识别的指令那么简单,在编译过程中,需要对源码进行词法分析,语法分析,语义分析,最后生成字节码。我们都知道Java语言,内存是自动管理的,一个对象实例内存空间的申请、分配和回收都是虚拟机自己去管理的。Java内存分配有动态内存分配,也有静态内存分配,静态内存分配就是在编译时候,就确定需要分配的内存大小,如类的静态常量,对于一些大小不可知的对象,只有运行时才能确定需要申请的空间大小。所以静态分配性能相对动态分配比较高一些。由此看出,Java编译成字节码,除了将源码编译成虚拟机可执行的字节码,也做了一些其他准备工作。
因此,若将源码替代字节码,虚拟机直接执行源码的话,要么程序员将源码写成字节码那样的,这样对程序员不友好,另外就是当虚拟机加载某个类,或者实例化某个对象的时候,虚拟机做一些与编译器类似的工作,但是这样性能会收到很大的影响。
理解的比较浅,可能有很多地方不正确,希望大家一起探讨。
原文