用JShell开始学习Java – 一窥Java的世界
让我们在JShell上开始学习Java吧。
为了什么而做
没有编程经验的人能够大致理解Java编程中涉及的各种概念。
基于这篇文章的内容,已经出版了“成为专业Java开发者”的书籍。
环境设置
首先从环境设置开始。
您可以从以下链接下载JDK。
http://jdk.java.net/18/
我认为对于不熟悉命令行的人来说,使用Adoptium提供的带有安装程序的软件包会更好。也可以选择17LTS版本。
https://adoptium.net/
对于Mac和Linux用户来说,可以下载tar.gz文件来
$ tar xf openjdk-18_mac-x64_bin.tar.gz
我认为这个也可以。在Windows上,您可以下载ZIP文件并将其解压到适当的文件夹中。
启动JShell
现在让我们尝试启动JShell。
使用Windows的朋友,请打开”命令提示符”,而使用Mac或Linux的朋友,请打开”终端”。
$ jshell
如果它启动了就很幸运
顺便说一句,$ jshell 是指在命令行中输入 jshell 然后按下[enter]键的格式。
如果不能启动,对于Windows系统,请尝试启动”\Program files\Eclipse Adoptium\jdk-18-hotspot\bin\jshell”。在输入”\Prog”后按下 [tab] 键会自动补全。
※ 对于Windows系统,请使用反斜杠\输入为¥。
对于Mac系统,请尝试在/Library/Java/jdk-18/Contents/Home/bin/jshell附近启动。


当你在JShell中输入任何内容并按下[Enter]键,JShell会将该输入解释为Java代码并执行。这次输入的只是一个简单的计算,但它仍然是Java程序的一部分。
因此,我们的第一个Java程序变成了12 + 23。太棒了!
以后,将以以下方式表示对jshell的输入和结果。
jshell> 12 + 23
$1 ==> 35
请在JShell中输入12+23并按下[enter]键,这样就会显示35。暂时不必考虑$1 == > 部分。
处理值
运算
刚才进行了加法运算。那么接下来试试减法吧?我来试一下4减3。
jshell> 4 - 3
$2 ==> 1
在数学中,我们使用*来表示乘法,/来表示除法。此外,我们可以用%来计算除法的余数。
jshell> 8 * 2
$3 ==> 16
jshell> 8 / 2
$4 ==> 4
jshell> 7 % 5
$5 ==> 2
3+4*2是怎么样的呢?
jshell> 3 + 4 * 2
$6 ==> 11
对不起,我只能以英文回答您的问题。请注意,以下是对句子的一种翻译,可能会有诸多表达方式。中文翻译如下:
嗯,乘法先计算了。如果用括号括起来3+4,就会先计算加法。
jshell> (3 + 4) * 2
$7 ==> 14
各种各样的类型 (kè gè de
顺便问一下,关于22/7的事情会如何发展呢?
jshell> 22 / 7
$8 ==> 3
当进行计算时,被视为一个整数。若想要小数点后的结果,也就是希望以实数的形式进行计算,可以使用22.0/7。
jshell> 22.0 / 7
$9 ==> 3.142857142857143
在Java中,如果给数字加上小数点,它就会被视为实数。另外,如果运算的任一项是实数,计算也会以实数进行。因此,在Java中,整数和实数是有区别的,计算方式也不同。
文本字符串和方法 hé
迄今為止,我們一直在處理數字。在程式中,我們也經常處理連續的字符,例如單詞、句子等等。在程式的世界中,這種連續的字符被稱為字符串。在Java中,我們使用雙引號將字符串括起來表示。
jshell> "aaa"
$10 ==> "aaa"
方法
对于字符串,我们会想要执行各种操作。例如,让我们将字符串转换为大写字母。输入”test”.toUpperCase()进行尝试。输入到 “toU” 然后按下 [Tab] 键,应该会自动补全。这种功能称为 “自动补全”。
jshell> "test".toUpperCase()
$12 ==> "TEST"

让我们尝试使用其他方法。请执行”test”.repeat(3)的代码。
jshell> "test".repeat(3)
$13 ==> "testtesttest"
测试重复了3次的字符串被显示出来了。repeat方法是一个指定字符串重复次数的方法。就像这样,有时候我们需要向方法提供一些特定的值。这些特定的值称为”参数(引数)”。
在charAt方法中,您可以提取指定位置的字符。
jshell> "test".charAt(2)
$13 ==> 's'
在这里,需要注意的是第一个字符是0号。在程序中,大多数情况下,0表示第一个元素,1表示第二个元素。
再来一个例子,我们试着使用replace方法。让我们执行”test”.replace(“st”,””)。
jshell> "test".replace("st","")
$14 ==> "te"
replace(替换)方法是一个用于替换字符串的方法,它接受替换前的字符串和替换后的字符串作为参数。当有两个或更多参数时,我们可以使用逗号来分隔参数。””代表空字符串。通过将”st”替换为””,我们将从字符串中省略了”st”。
您还可以将方法调用连接起来。
jshell> "test".repeat(3).replace("st","")
$15 ==> "tetete"
“test”重复3次成为”testtesttest”,并且省略了”st”变成了”tetete”。
练习:使用repeat方法创建一个重复四次的字符串”hi”。
练习:使用replace方法将”grape”的字母p替换为d。
练习:使用toLowerCase方法将”HELLO”转换为小写。
练习:使用substring方法从”minute”中提取第二个字符开始的三个字符,创建一个新的字符串。
在中文中,我们使用“+”运算符来连接字符串。
jshell> "te" + "st"
$11 ==> "test"
对于减法,会怎样呢?如果用”test”减去”st”得到”te”,那么就很方便了。
jshell> "test" - "st"
| エラー:
| 二項演算子'-'のオペランド型が不正です
| 最初の型: java.lang.String
| 2番目の型: java.lang.String
| "test" - "st"
| ^-----------^
发生了错误。这里所说的 “操作数” 是指运算符的项。它指出 – 运算符不能用于字符串。希望您能正确阅读这样的错误信息,但目前对于 – 运算符不能用于字符串的认识就够了。对于字符串,只能使用 + 运算符作为运算符。
操作JShell
当你按上方向键时,先前输入的内容将会出现。这对于想要再次执行先前输入的内容的情况非常有用。
要结束JShell,可以使用/exit命令。
jshell> /exit
| 終了します
$
如果在JShell中,当按下[Enter]键时,可以确定输入已经到了一个好的位置,那么JShell将执行该表达式。但是,如果输入在中途换行或者括号不完整等情况下结束得不完整,JShell将要求继续输入。
jshell> "test".repeat(
...>
当您输入长行时自行换行时并没有问题。但是,当您认为已经输入了一行但实际上括号不匹配导致行未结束时,这样的情况会很麻烦,有时重新输入会更快。在这种情况下,您可以使用[Ctrl]+[c]进行取消操作。
变量
顺便说一下,如果这个值接近于圆周率,我们可以用它来代替圆周率进行各种运算。据说古巴比伦时期就使用它作为圆周率。但是每次输22.0/7太麻烦了。
当我重新审视并计算22.0 / 7时,结果显示如下。
jshell> 22.0 / 7
$9 ==> 3.142857142857143
这表明可以使用值为9的名称。
jshell> $9
$9 ==> 3.142857142857143
然而,记住这个数字很麻烦。如果只有一个值那就好了,但是希望记住的值会不断增加。给值取个更容易记忆和理解含义的名字就很方便了。这就是变量的作用。变量可以通过var 变量名=值来定义。
jshell> var pi = 22.0 / 7
pi ==> 3.142857142857143
通过这段代码,变量pi被定义且被赋值为3.142857142857143。当输入pi时,会显示被赋值的值。
jshell> pi
pi ==> 3.142857142857143
我們將使用這個公式來計算半徑為5的圓的周長。圓的周長等於直徑乘以圓周率。我們可以將變數作為計算的值來使用。
jshell> 5*2*pi
$16 ==> 31.428571428571427
面积是半径乘以半径再乘以圆周率。
jshell> 5*5*pi
$17 ==> 78.57142857142857
以这种方式,可以使用变量来重复使用值。
顺便说一下,当在位置$17定义变量pi时,显示为pi。换句话说,这表示将78.57142857142857分配给变量$17。
jshell> $17
$17 ==> 78.57142857142857
顺便说一句,在Java中,实际上使用Math.PI可以保持较高精度的圆周率。
jshell> Math.PI
$82 ==> 3.141592653589793
Math类的PI字段,我们将在另外学习时详细讨论。
如果我们将这个值作为圆周率来使用,那么半径为5的圆的面积将会是如下的数值。
jshell> 5*5*Math.PI
$81 ==> 78.53981633974483
让我们将Math.PI分配给变量pi。
jshell> pi=Math.PI
pi ==> 3.141592653589793
如下所示,可以重新为变量分配值。
重新计算5*5*pi,结果与使用Math.PI得到的结果相同。
jshell> 5*5*pi
$84 ==> 78.53981633974483
变量的类型
让我们把一个字符串赋给先前提到的变量pi。
jshell> pi="circle ratio"
| エラー:
| 不適合な型: java.lang.Stringをdoubleに変換できません:
| pi="circle ratio"
| ^------------^
出错了。提示无法将String转换为double。
在Java中,变量被分配的值的类型是确定的。这种类型的概念被称为“类型”。换句话说,变量的类型是确定的。
到目前为止,整数是int,小数是double,字符串是String。
那么,让我们来确认变量的类型。在JShell中,可以使用/var命令来确认变量的类型。
jshell> /var pi
| double pi = 3.141592653589793
这表示变量pi的类型是double,并且被赋予了值3.141592653589793。double是处理实数的类型。
让我们来看看字符串的情况。首先,准备一个变量str,并为其分配字符串”circle”。
jshell> var str="circle"
str ==> "circle"
让我们使用/var命令来确认类型。
jshell> /var str
| String str = "circle"
字符串被表示为String类型。这意味着字符串以String类型表示。
如果尝试分配实数,就会出现错误。
jshell> str=3.14
| エラー:
| 不適合な型: doubleをjava.lang.Stringに変換できません:
| str=3.14
| ^--
到目前为止,我们一直使用var来声明变量。使用var可以自动确定变量的类型。在这里,也可以指定类型来声明变量。
jshell> String message="hello"
message ==> "hello"
而且,也可以对这种变量调用方法。
jshell> message.length()
$325 ==> 5
在中国,方法可以根据类型进行调用。length方法和repeat方法是为String类型准备的方法。而double类型没有可调用的方法。
也可以将方法返回的值赋给变量。
jshell> var count=message.length()
count ==> 5
在这里,变量count是int类型。
jshell> /var count
| int count = 5
int类型是处理整数的数据类型。
练习:使用var,将实数1.414赋给变量root2。
练习:不使用var,将字符串”apple”赋给变量word。
练习:对上述准备好的word调用toUpperCase方法。
方法的定义
在Java中,可以通过定义方法来重复使用表达式,这对于类似半径乘以半径乘以圆周率的表达式非常方便。
请尝试运行一下稍长的代码:double menseki(double r){return r*r*pi;}
jshell> double menseki(double r){return r*r*pi;}
| 次を作成しました: メソッド menseki(double)
这样,面积方法已经被定义了。可以按照以下方式使用。
jshell> menseki(5)
$34 ==> 78.53981633974483
jshell> menseki(3)
$33 ==> 28.274333882308138
你可以重复使用这个表达式。
那么让我们稍微详细地看一下方法的定义。如果我们随意换行方法的定义,就会变成以下这样。
double menseki(double r) {
return r*r*pi;
}
这个定义如下所示。
結果の型 メソッド名(引数の型 引数を扱う変数) {
return 式;
}
这次定义了一个名为menseki的方法,接收实数并返回实数。使用变量r来接收传入的参数,r代表半径。在返回值时使用return语句。在这里,返回值是接收到的半径乘以2再乘以圆周率的结果。
在JShell中,您也可以通过换行来定义变量。
jshell> double menseki(double r) {
...> return r*r*pi;
...> }
| 次を変更しました: メソッド menseki(double)
练习:参数的名称不一定要为r。请尝试定义一个与相同功能的方法menseki2,将参数命名为a。
练习:请定义一个接受半径并返回圆周长的方法。
摇摆
你有没有觉得光看文字很无聊呢?为了不只是看文字,我们来执行一些其他的东西吧。
我们将显示一个窗口。在Java中,已经准备了一个名为Swing的GUI工具包。GUI工具包是用于显示窗口和布置按钮等组件的部分。
显示窗口
首先准备一个窗口。
jshell> var f = new javax.swing.JFrame("test")
f ==> javax.swing.JFrame[fram ... bled=true]
我有点不太明白,但变量f已经被分配了某些内容。
接下来,我将调用show()方法。
jshell> f.show()

jshell> f.setSize(400,300)

类和对象
在创建窗口时,我执行了以下代码: var f = new javax.swing.JFrame(“test”)。
在Java中,我们将程序处理的窗口、按钮等对象称为“对象”。在这里,变量f被分配了一个窗口对象。Swing中使用javax.swing.JFrame类型来表示窗口。对象是基于某种类型生成的。用于生成对象的基本类型被称为“类”。javax.swing.JFrame就是一个类。
当从类中生成对象时,我们使用new运算符,并以new 类(参数)的方式生成。参数由类确定。
从某种角度来看,生成对象时似乎还在调用特殊的方法。我们称之为“构造函数”。构造函数是与类同名,需要通过new运算符进行调用的方法。
Java文档
javax.swing.JFrame的文档可以在此处找到:
https://docs.oracle.com/en/java/javase/18/docs/api/java.desktop/javax/swing/JFrame.html
如果你想使用日语的话,这是链接给你:
https://docs.oracle.com/javase/jp/17/docs/api/java.desktop/javax/swing/JFrame.html
这个文档的格式被称为「JavaDoc」。Java的API文档大多采用这个格式。
搜索「javadoc JFrame」等等,用javadoc + 类名即可找到大部分的JavaDoc。

通过观察这段代码,我们可以知道在这里使用的是JFrame的构造函数(String title)。还提供了无参数的构造函数,因此可以生成没有指定标题的窗口。
可能需要更多的学习Java语言才能理解这些内容,但通过查阅JavaDoc可以了解到我们所写的代码的意义,并对Java语言有更好的理解。
另外,一般来说,解释书籍并不能解释所有内容,所以参考这种一手资料来准确地理解也非常重要。
练习:请在JavaDoc中查找之前使用过的String的replace方法。
提示:在右上角的搜索框中进行搜索会很方便。
包和导入
既然窗口已经能够显示出来了,那么我们就开始布置文本区域吧。文本区域是一个可以输入多行字符的组件。在Swing中,文本区域使用javax.swing.JTextArea类来处理。而将这样的组件放在窗口上,我们称之为”组件”。
为了布置文本区域,首先需要生成一个文本区域的对象。要生成对象,就要调用与类名相同的方法,也就是构造函数,在其前面加上new运算符。但是javax.swing.JTextArea这个名字太长,每次输入都很麻烦。
实际上,javax.swing.JTextArea被分为两部分,最后一个分隔符是类名,前面的部分是包名。也就是说javax.swing指的是javax.swing下的JTextArea类。”包”是Java中用来分类类的机制。
因此,使用import语句可以省略包名。例如,使用import javax.swing.*可以省略javax.swing包的包名,并只用类名表示。
jshell> import javax.swing.*
虽然我之前一直忽略了,但是我注意到了String类型会以java.lang.String的形式显示出来。String类型被包含在java.lang包中,由于预先进行了导入(import)操作,因此可以省略包名。
那么,让我们创建一个表示文本区域的JTextArea类的对象。
jshell> var textarea = new JTextArea()
textarea ==> javax.swing.JTextArea[,0,0,0x0,i ... rap=false]
需要将这个放置在窗口中。可以通过调用add方法将其添加到表示窗口的JFrame对象中。
jshell> f.add(textarea)
$14 ==> javax.swing.JTextArea[,0,0,0x0,inval ... se,wrap=false]
然而,如果不进行重新组织,它将不会显示在窗口上,因此需要重新组织窗口。通过调整窗口的大小,可以进行重新组织,可以尝试拖动窗口的边缘来改变大小,或者调用setSize方法。当使用setSize方法指定大小时,如果窗口大小没有改变,将不会执行任何操作,因此需要稍微调整大小。
jshell> f.setSize(400,301)
现在显示了文本区域,您可以输入文字。

对于文本输入框,您可以使用append方法来添加字符串。
jshell> textarea.append("te")
jshell> textarea.append("st")

换行用”\n”表示。(在Windows中用”¥n”表示)
jshell> textarea.append("\ntester\n")

添加按钮
好的,现在让我们来添加一个按钮。在 Swing 中,按钮是通过 JButton 类来处理的。你可以通过构造函数的参数来指定按钮的标签字符串。
jshell> var button = new JButton("Hello")
button ==> javax.swing.JButton[,0,0,0x0,inval...pable=true]

将第一个参数指定为添加位置,并将第二个参数指定为要添加的组件。
jshell> f.add("North", button)
$27 ==> javax.swing.JButton[,0,0,0x0,inval...ltCapable=true]
如果拼写错误了”North”这个词,就会出现这样的错误。请注意大小写的区别。
jshell> f.add("Nort", button)
| Exception java.lang.IllegalArgumentException: cannot add to layout: unknown constraint: Nort
| at BorderLayout.addLayoutComponent (BorderLayout.java:468)
| at BorderLayout.addLayoutComponent (BorderLayout.java:429)
| at JRootPane$1.addLayoutComponent (JRootPane.java:507)
| at Container.addImpl (Container.java:1151)
| at Container.add (Container.java:1028)
| at JFrame.addImpl (JFrame.java:553)
| at Container.add (Container.java:459)
| at (#31:1)
顺便说一下,这个错误与以前试图将字符串赋给变量pi时发生的错误完全不同。它也不同于拼写错误添加add的情况。
jshell> f.ad("North", b)
| エラー:
| シンボルを見つけられません
| シンボル: メソッド ad(java.lang.String,javax.swing.JButton)
| 場所: タイプjavax.swing.JFrameの変数 f
| f.ad("North", b)
| ^--^
这些错误发生的时间不同,尝试为add或变量pi分配字符串时的错误是在解释程序时发生的错误,当错误地输入”North”时是在执行解释过的处理时发生的错误。
将解释程序时发生的错误称为编译错误,将运行时错误称为异常。
现在两种错误都在输入指令并按下回车键时发生,所以很难区分,但在实际开发中应该可以明确区分。现在,只要您能感受到错误有两种类型,就可以了。
话虽这样说,即使add操作成功执行,按钮仍然不会显示出来。
但是如果使用setSize方法重新构建窗口,按钮就会显示出来。
jshell> f.setSize(400,300)

但是,即使按下这个按钮也什么都不会发生。需要编写一些处理。请尝试以下输入方式。addActionListener有点长,但是输入addAc然后按下[tab]键,应该会自动补充剩下的。
jshell> button.addActionListener(ae -> textarea.append("Hello!\n"))

要添加按钮点击时的处理,需要使用addActionListener方法。
在这里,我们将参数ae->textarea.append(“Hello!\n”)指定为addActionListener方法。addActionListener方法需要传递一些处理,相当于“当按钮被点击时,请调用此处理”。这里的处理是textarea.append(“Hello!\n”),但如果要将处理作为值传递,需要使用类似“Lambda表达式”的方式。
Lambda表达式的写法如下。
引数 -> 処理
当按下按钮时,需要处理的情况下,将ActionEvent对象作为参数进行接收,在此处我们将其命名为ae,但如果可以理解,可以使用任何名称。我们目前没有使用接收到的参数。
从文本框接收输入
我们再多努力一点吧。
我会尝试做一个当按下按钮时,在文本框中显示输入的文本字符串的功能。
我想添加文本框和按钮,但在JFrame的布局方式下无法直接添加。因此,我将使用JPanel组件。
jshell> var panel = new JPanel()
jshell> f.add("South", panel)

添加文本字段。文本字段是一种只能输入一行的组件,使用JTextField组件。
jshell> var textfield = new JTextField()
jshell> textfield.setColumns(15)
jshell> panel.add(textfield)
通过 setColumns 方法设置宽度。


让我们最后尝试添加按钮。
jshell> var printButton = new JButton("Print")
jshell> printButton.addActionListener(ae -> textarea.append(textfield.getText() + "\n"))
jshell> panel.add(printButton)

练习:添加一个按钮,当点击时在文本区域显示”Yeah!”。
练习:添加一个按钮,将输入框中的字符串转换为大写字母,并将结果输出到文本区域。要将字符串中的字母转换为大写,可以使用toUpperCase方法。请先在JShell上尝试一下toUpperCase方法的使用方法。
离开 JShell 来编写 Java 程序
最后,让我们将之前在JShell中试验过的内容写成一个独立的Java程序。请在记事本或文本编辑器中输入以下源代码,并将其保存为名为”FirstWindow.java”的文件放置在桌面上。
import javax.swing.*;
public class FirstWindow {
public static void main(String... args) {
var frame = new JFrame("test");
var textarea = new JTextArea();
frame.add(textarea);
var textfield = new JTextField();
textfield.setColumns(15);
var button = new JButton("Print");
button.addActionListener(ae -> textarea.append(textfield.getText() + "\n"));
var panel = new JPanel();
panel.add(textfield);
panel.add(button);
frame.add("North", panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.show();
}
}
在JShell中添加了一些之前没有的内容。此外,输入到JShell的命令后面都有分号(semicolon)。但是,与开始这个教程之前相比,你可能会有一种“我能读懂了!”的感觉,对吗?
现在,让我们尝试运行这段源代码。
请打开命令提示符。这次不使用JShell。
使用cd命令切换到桌面。
$ cd Desktop
接着,使用javac命令编译先前输入的源代码。
$ javac FirstWindow.java
如果发生错误,请进行更正并保存,然后再进行编译。
当错误消失时,请检查所创建的文件。
在Windows中使用dir命令,在Mac和Linux中使用ls命令。
$ dir FirstWindow.*
第一個視窗的.class檔案已經建立了,這就是Java的執行程式碼。要執行它,我們需要使用java命令。
$ java FirstWindow

请从这里开始进行Java的深入学习。