Java9不出意外的又跳票了,传闻Java9加入了JEP 222,所以用OpenJDK体验了一把JShell并分析了下其实现。
JShell简述
JShell是一个能够执行Java代码片段、表达式的Shell,从外表看上去像是一个Java的解释器,实际上它是一个Read-Eval-Print Loop,接受命令、代码片段输入,输出运算结果或者一个变更状态。
JShell简易使用指北
- 通过${JAVA_HOME}/bin/jshell便可以启动一个JShell。
- 如其他Java工具一样,JShell已自带普通话补丁,在其OepnJDK源码资源文件也可以看到有
l10n_zh_CN.properties
的多语言支持。 - 执行命令
类似于IPython,JShell除了可以执行Java代码,还内置了部分命令,键入\help
便可以获得命令列表。 - 表达式执行
JShell可以直接执行一个算术表达式,输出计算值或者函数的返回值。对于单条语句,可以省略句尾句号 - import
JShell同时可以支持import外部包,使用Tab进行自动补全等功能。这里import还可以使用\evn
指令导入的合法classpath下的任意jar。也就是说导入 - 类创建初始化
JShell同时可以创建初始化类实例,调用实例方法。
JShell基础对象
MemoryFileManager
JShell编译器内存文件API的管理器,同时具有一个OutputMemoryJavaFileObject的Map用于类文件的缓存。
TaskFactory
编译器用于解析、分析、在内存编译class文件的API基本接口,其中CompileTask、AnalyzeTask、ParseTask均继承自BaseTask,这几个Task均为TaskFactory的内部类,通过TaskFactory的工厂方法产生对应的实例。
Eval
赋值引擎,将source 封装成方法、属性等等,在外部封装了imports和class,为整个JShell的核心部分
编译 声明 重定义 替换 执行
Snippet
代表传递的Java代码片段,同一个片段是不可变的,这一特性也就意味着它的任意方法都会有相同的返回,并且是线程安全的。
Snippet为抽象类,只有继承终点为实现类,其中派生Snippet结构如图所示。
ExpressionSnippet为表达式片段,StatementSnippet为声明片段,ErroneousSnippet为非法片段,PersistentSnippet为被存储影响后续代码结果的片段。DeclarationSnippet为值片段,其下属值、类型、函数都是其实现类。
SnippetEvent
直接/间接通过 JShell.eval(String)或者JShell.drop(Snippet), 或者Snippet被直接生成的关于这个变化描述的片段
ReplParserFactory
继承自com.sun.tools.javac.parser.ParserFactory
解析器工厂,通过com.sun.tools.javac.util.Context
初始化了,com.sun.tools.javac.parser.ScannerFactory
用于产生Scanner。
DiagList
一个存放Snippet诊断信息的向量,这些包含是否有不可达、未声明、无法解析等错误。
MaskCommentsAndModifiers
对一个输入的String,通过Context隐藏其注释和修饰符细节。
Warp
将源输入包装成方法,成员变量,等等。
JShell源码分析
由于时间有限,这里先把程序的主要执行逻辑写在这里,以后有时间绘成流程图。
JShell eval
通过以上源码分析,我们我们可以通过建立一个JShell对象来尝试执行一个简单的Java程序块。
|
虽然执行过程稍微长了一点,但是程序成功输出了xdsjsd,实验成功。
总结
JShell为开发者提供了一个稳定的交互式终端,程序开发者可以通过JShell进行一些简单的程序执行结果验证,同时它还赋予了Java应用程序动态执行Java代码的能力,如果不出意外接下来会有很多基于JShell机制的Virtual Runtime,OJ平台出现,大家拭目以待吧!