如何将 运行 整个 Java 文件作为片段添加到 JShell 中?

How to run a whole Java file added as a snippet in JShell?

我尝试安装 JDK 9 抢先体验版 172 以使用 JShell。 当我尝试打开一个简单的 java 文件并在将其添加为代码段后执行它时,它只显示修改后的 class 测试并增加了代码段编号。你能帮我看看我错在哪里吗?

|  Welcome to JShell -- Version 9-ea
|  For an introduction type: /help intro

jshell> /open G:\kavitha\Test.java

jshell> /list

   1 : public class Test{
        public static void main(String[] args){
                 int i = 1;
                 int j = 2;
             System.out.println("Sum of 1 and 2 is : " + (i+j));
        }
       }

jshell> /1
public class Test{
        public static void main(String[] args){
                 int i = 1;
                 int j = 2;
             System.out.println("Sum of 1 and 2 is : " + (i+j));
        }
}
|  modified class Test

jshell> /list

   2 : public class Test{
        public static void main(String[] args){
                 int i = 1;
                 int j = 2;
             System.out.println("Sum of 1 and 2 is : " + (i+j));
        }
       }

/open只加载文件,之后你必须告诉jshell你想执行什么。

示例:

jshell> /open Test.java

jshell> /list

   1 : class Test {
           public static void main(String[] args) {
               System.out.println("Hello Kavitha");
           }
           int rollDice() {
               return 1 + (int)(6 * Math.random());
           }
       }

jshell> Test.main(new String[0])
Hello Kavitha

jshell> new Test().rollDice()
 ==> 3

这里我执行了main方法,但我也可以根据需要使用加载的class,创建新实例,调用方法等

快捷方式 /<id> 重新 运行 具有该 ID 的代码段。在你的例子中,片段 1 只加载 class 并且什么都不执行,所以通过执行 /1 你重新加载了相同的 class,再次没有执行它。

在运行我上面的例子之后,/2会重新运行主要方法,/3会重新掷骰子:

jshell> /3
new Test().rollDice()
 ==> 1

jshell> /3
new Test().rollDice()
 ==> 6

jshell> /3
new Test().rollDice()
 ==> 2

附录:/open & 编译,class 加载,class 初始化

(试图弄清楚为什么 /open没有执行你的class的main方法,并证明它是有道理的)

当您 /open 一个文件时,JShell 将添加文件的内容 就好像您将它输入到 shell.

然后它将 编译 片段,但它不会 initialize class 如果有的话。

(不知道if会不会load classes,这是初始化前的步骤,不好说,见this post 那是一次探索 JShell 内部结构的尝试,它显示了 JShell 中的 class 名称是如何为用户翻译的,并且尝试查看加载的 classes 列表失败了——但这很重要少于编译和初始化)

如果我打开 SnippetWithError.txt 其中包含以下内容:

System.out.println("Hey")
class Foo { int n=33; } bar

(是的,它不需要是 java 文件,它实际上是您包含在 shell 中用于评估的一堆文本)

jshell> /open SnippetWithError.txt
Hey
|  Error:
|  cannot find symbol
|    symbol:   variable bar
|   bar
|   ^-^

看到它打印出来 "Hey",它包含了 class Foo:

jshell> new Foo().n
 ==> 33

所以,当你/open时,JShell 编译,它会执行语句,但如果某些语句是class或方法声明,它不会执行那些,它甚至不 初始化 classes.

请参阅下面如何将导入计算为历史记录中的单独语句,然后 class 声明在其自己的语句中(#3):

jshell> /open HasStaticInitBlock.java

jshell> /list

1 : import java.time.Duration;
2 : import java.time.Instant;
3 : class HasStaticInitBlock {
        static Instant t0 = Instant.now();
        static {
            System.out.println("Class initialized at " + t0);
        }
        static Duration timeSinceInit() {
            return Duration.between(t0, Instant.now());
        }
    }

jshell> HasStaticInitBlock.timeSinceInit()
Class initialized at 2017-06-07T06:49:06.746185Z
 ==> PT0.040414S

jshell> HasStaticInitBlock.timeSinceInit()
 ==> PT2.343019S

Class 只在需要时才进行初始化。