当学习任何新的编程语言时,传统做法是从一个能够显示“Hello, World!”消息的程序开始,这也是在下面的小节中我们将要做的事情。
话不多说,下面就是Java中的“Hello, world”程序。
package ch01.sec01; // Our first Java program public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }
让我们一起来看看这个程序。
● Java是一种面向对象的语言。在程序中,通常需要控制 对象 (object)来让它们完成具体工作。操作的每个对象都属于特定的 类 (class),通常也称这个对象是该类的一个 实例 (instance)。类定义了对象的状态是什么,以及对象能做什么。在Java中,所有代码都是在类中定义的。第2章将详细介绍对象和类。这个程序是由一个名为HelloWorld的单一类组成的。
● main是一个 方法 (method),也就是在类中声明的一个函数。main方法是程序运行时调用的第一个方法。main方法声明为static,以表示该方法不作用于任何对象。(当调用main方法时,只有少数的预定义对象,并且它们都不是HelloWorld类的实例。)main方法也声明为void,以表示它不返回任何值。关于main方法中参数声明String[ ] args的含义,参见1.8.8小节。
● 在Java中,你可以将许多特性声明为public或private。除此之外,Java中还有一些其他可见性级别。这里将HelloWorld类和main方法都声明为public,这是类和方法中最常见的定义形式。
● 包( package ) 是一组相关类的集合。把相关类放在一个包中是一个很好的做法,这样可以将相关类组合在一起,并避免多个类在具有相同名称时可能会发生的冲突。本书使用章(Chapter)和节(Section)的编号作为包名。因此,示例中类的全名就是ch01.sec01.Helloworld。第2章会有更多关于包和包命名规范的内容。
● 以 // 开头的行是注释。编译器会忽略从 // 到行末的所有字符,这些字符仅仅用来辅助编程人员阅读程序。
● 最后,来看看main方法的主体。在示例中,它由一行命令组成,该命令的功能是向System.out输出一个消息,System.out对象代表Java程序的“标准输出”。
正如你所见,Java不是一种可以用来快速执行一些简单命令的脚本语言。它的类、包和模块(模块在第15章中介绍)等特性使得它更适合用于编写大型程序。
Java也非常简单和统一。一些编程语言不仅有全局变量和全局函数,还有类内部的变量和方法。在Java中,所有东西都在类中声明,这种统一性可能会导致代码有些冗长,但也使得理解程序的含义变得容易。
注意: 你刚刚看到了一个 // 形式的注释,它的注释效果是延伸到行末的。还可以在 /* 和 */ 分隔符之间添加多行注释。例如:
/* This is the first sample program in Core Java for the Impatient. The program displays the traditional greeting "Hello, World!". */
还有第三种注释样式,称为 文档注释 (documentation comment),使用/** 和 */作为分隔符。下一章中将会介绍。
要编译和运行一个Java程序,需要安装Java开发工具包(Java Development Kit,JDK),此外,也可以安装集成开发环境(Integrated Development Enviroment,IDE)。可以在异步社区中下载本书的示例代码。
一旦安装了JDK,就可以打开一个终端窗口,并切换到包含ch01目录的目录,然后运行以下命令:
javac ch01/sec01/HelloWorld.java java ch01.sec01.HelloWorld
然后,那条熟悉的问候语就将出现在终端窗口中,如图1-1所示。
图1-1 在控制台窗口运行Java程序
需要注意的是,执行程序需要两个步骤。首先,javac命令将Java源代码 编译 (compile)成一个与机器无关的中间表示,称为 字节码 (byte code),并将它们保存在 类文件 (class file)中;然后,java命令启动一个 虚拟机( virtual machine ) ,该虚拟机会加载类文件并执行编译后的字节码。
一旦编译完成,字节码可以在任意一个Java虚拟机中运行,无论是在你的台式计算机上或者是在遥远银河系中的某个设备上。这个“一次编写,处处运行”的承诺是Java的一个重要设计标准。
注意: javac编译器是通过文件名进行调用的,使用斜杠分隔文件路径段,文件扩展名为.java。java虚拟机的启动器是通过类名进行调用的,使用点号来分隔包的名称段,并且没有扩展名。
注意: 如果程序由单个源文件组成,那么可以跳过编译的步骤,直接使用以下命令运行程序:
java ch01/sec01/HelloWorld.java
在后台,程序将会在运行之前进行编译,但不会生成类文件。
注意: 在类Unix操作系统上,你可以按照以下步骤将Java文件转换为可执行程序。
(1)重命名文件,删除其扩展名.java。
mv HelloWorld.java hello
(2)使文件可执行。
chmod +x hello
(3)在文件顶部添加一行bash的运行标记。
#!/path/to/jdk/bin/java --source 17
现在,你就可以通过以下方式运行程序了。
./hello
如果要在IDE中运行程序,首先需要按照IDE安装说明中描述的方式创建一个项目。然后,选择HelloWorld类并通过IDE运行它。图1-2显示了程序在Eclipse中的运行情况。Eclipse是一个非常流行的IDE。除此之外,还可以选择许多其他优秀的IDE。随着对Java编程的不断学习和深入了解,还是应该多尝试几种IDE,再从中选择一个自己喜欢的。
图1-2 在Eclipse IDE中运行Java程序
好了,恭喜你刚刚完成了使用Java运行“Hello,World!”程序这一古老的传统,下面我们就准备开始学习Java语言的基础知识。
提示: 在异步社区官网中可以下载本书所有章节的示例代码。这些代码经过精心编排和组织,你可以很方便地创建一个包含所有示例程序的单个项目。建议你在仔细阅读本书中内容的同时,下载、运行和学习这些配套代码。
让我们更仔细地看看main方法中唯一的语句:
System.out.println("Hello, World!");
System.out是一个对象,它是一个名为PrintStream的类的 实例( instance ) 。PrintStream类有println、print等方法。这些方法被称为 实例方法 (instance method),因为它们对类的对象或实例进行操作。
若要在对象上调用实例方法,请使用 点符号 (dot notation)来表示:
object.methodName(arguments)
在这个例子中,main方法只有一个参数,即字符串"Hello, World!"。
让我们用另一个例子来试试,像"Hello, World!" 这样的字符串是String类的实例。String类有一个返回String对象长度的length方法。若要调用该方法,则需要再次使用点符号:
"Hello, World!".length()
length方法是通过对象"Hello, World!"调用的,且该方法没有参数。与println方法不同,length方法会返回一个结果。使用该返回结果的一种方法就是将它输出到屏幕:
System.out.println("Hello, World!".length());
一起来试试看。用这个语句来编写一个Java程序并运行它,看看字符串的长度是多少。
在Java中,需要自己 构造 (construct)大多数对象(不像System.out和"Hello, World!"这些对象,它们是已经存在的,可以直接使用)。下面是一个简单的示例。
Random类的对象可以生成随机数。可以使用new运算符来构造一个Random对象:
new Random()
在类名之后的是构造参数列表,在这个例子中该列表是空的。
你可以在构造的对象上调用方法。例如:
new Random().nextInt()
这样就可以通过这个新构造的随机数生成器,生成下一个随机整数。
如果想在一个对象上调用多个方法,那么需要将对象存储在变量中(参见1.3节)。这里我们打印两个随机数:
Random generator = new Random(); System.out.println(generator.nextInt()); System.out.println(generator.nextInt());
注意: Random类是在java.util包中声明的。为了在程序中使用这个类,需要添加import语句,示例如下。
package ch01.sec01; import java.util.Random; public class MethodDemo { ... }
我们将在第2章中更详细地了解包和import语句。
在1.1.2小节中,你看到了如何编译和运行一个Java程序。JShell程序提供了一个“读取—评估—打印循环”(read-evaluate-print loop,REPL)的方式,它允许你尝试Java代码而无须编译和运行程序。当输入Java表达式时,JShell会评估输入,并打印结果,然后等待下一次输入。如果要启动JShell,只须在终端窗口中输入jshell,如图1-3所示。
图1-3 运行JShell
JShell以问候语开头,然后显示提示符:
| Welcome to JShell -- Version 17 | For an introduction type: /help intro jshell>
现在可以输入一个Java表达式,例如:
"Hello, World!".length()
JShell会给你一个反馈,表示运行结果和下一个提示符:
$1 ==> 13 jshell>
需要注意的是,你并 没有 输入System.out.println。JShell会自动打印输入的每个表达式的值。
输出中的$1表示该结果可用于进一步的计算。例如,如果继续输入:
3 * $1 + 3
则JShell的反馈为:
$2 ==> 42
如果需要多次使用一个变量,那么可以给它指定一个更加容易记忆的名字。一定要遵循Java语法,同时指定类型和变量名(参见1.3节)。例如:
jshell> int answer = 42 answer ==> 42
可以让JShell替你填写类型。具体操作是,输入一个表达式,不要按Enter键,而是按住Shift+Tab组合键,然后按V键。例如,当输入:
new Random()
然后按Shift + Tab组合键和V键,你会看到:
jshell> Random = new Random()
这时的光标位于 = 符号之前。此时可以输入一个变量名,然后按Enter键:
jshell> Random generator = new Random() generator ==> java.util.Random@3fee9989
此外,还有一个很棒的功能是Tab补全功能,例如输入:
generator.
随后按Tab键,你将会得到一个可以在generator变量上调用的所有方法的列表:
jshell > generator. doubles( equals( getClass() hashCode() ints( isDeprecated() longs( nextBoolean() nextBytes( nextDouble( nextExponential() nextFloat( nextGaussian( nextInt( nextLong( notify() notifyAll() setSeed( toString() wait(
现在输入ne再按Tab键。方法名会补全为next,并且你会得到一个更加简短的列表:
jshell> gengerator.next nextBoolean() nextBytes( nextDouble( nextExponential() nextFloat( nextGaussian( nextInt( nextLong(
如果再按D键和Tab键,方法名会自动补全为nextDouble(。再次按Tab键,将会看见3个备选:
Signatures: double java.util.random.RandomGenerator.nextDouble(double bound) double java.util.random.RandomGenerator.nextDouble(double origin, double bound) double Random.nextDouble() <press tab again to see documentation>
按)键可以选择第3个版本:
jshell> gengerator.nextDouble() $3 ==> 0.9560346568377398
注意: 在自动完成列表中,需要参数的方法只能后跟左括号,如nextDouble(,而不需要参数的方法有一对完整括号,如nextBoolean()。
如果要重复运行命令,可以按 ↑ 键,直到看到要重新运行或编辑的行。可以用 ← 键和 → 键移动命令行中的光标,并添加或删除字符,完成后按Enter键。例如,按 ↑ 键并用Int替换Double,然后按Enter键:
jshell> generator.nextInt() $4 ==> -352355569
默认情况下,JShell将会导入以下包:
java.io java.math java.net java.nio.file java.util java.util.concurrent java.util.function java.util.prefs java.util.regex java.util.stream
这就是可以在JShell中使用Random类而不需要任何导入语句的原因。如果需要导入其他类,可以在JShell提示符下输入导入语句。或者,更方便的是,通过按住Shift+Tab组合键和I键,可以让JShell搜索它。例如,输入Duration,然后按住Shift+Tab组合键和I键,你将获得一个潜在操作的列表:
jshell> Duration 0: Do nothing 1: import: java.time.Duration 2: import: javafx.util.Duration 3: import: javax.xml.datatype.Duration Choice:
输入1,然后你将收到一个确认信息:
Imported: java.time.Duration
随后显示:
jshell> Duration
这样就完成了导入工作,然后就可以继续工作了。这些命令足以让你开始使用JShell。要获得更加详细的帮助,输入/help并按Enter键。如果要退出JShell环境,输入/exit并按Enter键,或者只须按Ctrl+D组合键。
JShell使得Java语言和相关库的学习变得轻松而有趣,且无须启用庞大的开发环境和编写复杂的public static void main等代码。