我关于 学习不同编程语言 的文章列出了开始学习新语言时需要理解的五个方面。当然,学习语言的一个重要部分是了解你打算用它做什么。
我发现编写简单的游戏既有趣又有助于探索语言的功能。在本文中,我将演示如何在 Java 中创建一个简单的猜数字游戏。
安装 Java
要进行此练习,您必须安装 Java。如果您没有安装,请查看以下链接以在 Linux、macOS 或 Windows 上安装 Java。
安装完成后,在终端中运行此 Java 命令以确认您安装的版本
$ java -version
猜数字
这个“猜数字”程序练习了编程语言中的几个概念:如何为变量赋值,如何编写语句,以及如何执行条件评估和循环。对于学习一门新的编程语言来说,这是一个很好的实践实验。
这是我的 Java 实现
package com.example.guess;
import java.util.Random;
import java.util.Scanner;
class Main {
private static final Random r = new Random();
private static final int NUMBER = r.nextInt(100) + 1;
private static int guess = 0;
public static void main(String[] args) {
Scanner player = new Scanner(System.in);
System.out.println("number is " + String.valueOf(NUMBER)); //DEBUG
while ( guess != NUMBER ) {
// prompt player for guess
System.out.println("Guess a number between 1 and 100");
guess = player.nextInt();
if ( guess > NUMBER ) {
System.out.println("Too high");
} else if ( guess < NUMBER ) {
System.out.println("Too low");
} else {
System.out.println("That's right!");
System.exit(0);
}
}
}
}
大约 20 行代码,不包括空格和尾随大括号。然而,从结构上看,有很多内容,我将在此处进行分解。
包声明
第一行 package com.example.guess
,在一个像这样的简单单文件应用程序中不是绝对必要的,但养成这个习惯是好的。Java 是一种大型语言,每天都在编写新的 Java 代码,因此每个 Java 项目都需要有一个唯一的标识符,以帮助程序员区分不同的库。
在编写 Java 代码时,您应该声明它所属的 package
。此格式通常是反向域名,例如 com.opensource.guess
或 org.slf4j.Logger
。与 Java 的通常情况一样,此行以分号结尾。
导入语句
代码的下一行是导入语句,它告诉 Java 编译器在构建可执行应用程序时要加载哪些库。我在此处使用的库与 OpenJDK 一起分发,因此您无需自行下载。因为它们并非严格意义上是核心语言的一部分,所以您需要为编译器列出它们。
Random 库提供对伪随机数生成的访问,而 Scanner 库允许您在终端中读取用户输入。
Java 类
下一部分创建一个 Java 类。Java 是一种面向对象的编程语言,因此其典型的构造是类。类提出了一些非常具体的代码思想,如果您是编程新手,您将在实践中掌握它们。目前,可以将类视为一个盒子,您可以在其中放置变量和代码指令,几乎就像您在构建一台机器一样。您放入类中的部分对于该类是唯一的,并且由于它们包含在一个盒子中,因此其他类看不到它们。更重要的是,由于此示例游戏中只有一个类,因此类是自给自足的:它包含执行其特定任务所需的一切。在本例中,其任务是整个游戏,但在较大的应用程序中,类通常以一种类似菊花链的方式协同工作以产生复杂的工作。
在 Java 中,每个文件通常包含一个类。此文件中的类称为 Main
,表示它是此应用程序的入口点。在像这样的单文件应用程序中,主类的意义很难理解,但在具有数十个类和源文件的较大 Java 项目中,标记一个 Main
是有帮助的。而且无论如何,使用定义的主类打包应用程序以进行分发很容易。
Java 字段
在 Java 中,与 C 和 C++ 中一样,您必须先声明变量才能使用它们。您可以在 Java 类的顶部定义“字段”。“字段”只是变量的一个花哨术语,但它特指分配给类而不是嵌入在函数中的变量。
此游戏创建了三个字段:两个用于生成伪随机数,一个用于建立初始(且始终不正确)的猜测。每个字段前面的长关键字字符串 (private static final
) 可能看起来令人困惑(尤其是在刚开始学习 Java 时),但使用像 Netbeans 或 Eclipse 这样的优秀 IDE 可以帮助您选择最佳方案。
理解它们也很重要。private 字段是仅对其自身类可用的字段。如果另一个类尝试访问私有字段,则该字段可能不存在。在像这样的单类应用程序中,使用私有字段是有意义的。
static 字段属于类本身,而不属于类实例。这在像这样的一个小演示应用程序中没有太大区别,因为只存在一个类实例。在较大的应用程序中,您可能有理由在每次生成类实例时定义或重新定义变量。
final 字段无法更改其值。此应用程序完美地演示了这一点:随机数在游戏过程中永远不会改变(移动的目标不是很公平),而玩家的猜测必须改变,否则游戏将无法获胜。因此,在游戏开始时建立的随机数是 final 的,但猜测不是。
伪随机数
两个字段创建了充当玩家目标的随机数。第一个字段创建 Random
类的实例。这本质上是一个随机种子,您可以从中提取一个相当不可预测的数字。为此,列出您要调用的类,后跟您选择的变量名,您将其设置为该类的新实例:Random r = new Random();
。与其他 Java 语句一样,这以分号结尾。
要绘制数字,您必须使用 Java 的 nextInt()
方法创建另一个变量。语法看起来有点不同,但它类似:您列出要创建的变量类型,提供您选择的名称,然后将其设置为某些操作的结果:int NUMBER = r.nextInt(100) + 1;
。您可以(并且应该)查看特定方法(如 nextInt()
)的文档,以了解它们的工作原理,但在本例中,从 r
随机种子中提取的整数限制为 100(即最大值为 99)。在结果中加 1 可确保数字永远不会为 0,功能最大值为 100。
显然,将任何超出 1 到 100 范围的数字取消资格的决定纯粹是任意的设计决定,但重要的是在坐下来编程之前了解这些约束。没有它们,很难知道您要朝着什么方向编码。如果可能,请与负责定义您正在编码的应用程序的人员合作。如果您没有人可以合作,请务必先列出您的目标,然后再戴上您的“程序员帽子”。
主方法
默认情况下,Java 会在类中查找要运行的 main
方法(或在许多其他语言中称为“函数”)。并非所有类都需要 main 方法,但此演示应用程序只有一个方法,因此它不妨是主方法。与字段一样,方法可以是公共的或私有的,静态的或非静态的,但主方法必须是公共的和静态的,Java 编译器才能识别和使用它。
应用程序逻辑
为了使此应用程序作为游戏工作,它必须在玩家猜测秘密伪随机数时继续运行。如果应用程序在每次猜测后停止,则玩家只能猜一次,并且很少会赢。计算机提供提示来指导玩家的下一次猜测也是游戏设计的一部分。
带有嵌入式 if
语句的 while
循环实现了此设计目标。while
循环本质上会持续运行,直到满足特定条件为止。(在本例中,guess
变量必须等于 NUMBER
变量。)可以将每次猜测与目标 NUMBER
进行比较,以提示有用的提示。
语法
main 方法首先创建一个新的 Scanner
实例。这与用作伪随机种子的 Random
实例的原理相同:您引用要用作模板的类,提供一个变量名(我使用 player
来表示输入猜测的人),然后将该变量设置为运行该类的主方法的结果。同样,如果您要自己编写代码,则需要查看该类的文档以获取使用它时的语法。
此示例代码包含一个调试语句,该语句显示目标 NUMBER
。这使游戏变得毫无意义,但它可以帮助您向自己证明它正在正常工作。即使是这个小的调试语句也揭示了一些重要的 Java 技巧:System.out.println
是一个打印语句,而 valueOf()
方法将整数 NUMBER
转换为字符串,以便将其作为句子的一部分而不是数学元素打印出来。
while
语句接下来开始,唯一的条件是玩家的 guess
不等于目标 NUMBER
。这是一个无限循环,只有当 guess
不等于 NUMBER
为假时才能结束。
在此循环中,提示玩家输入一个数字。Scanner 对象(称为 player
)获取玩家输入的任何有效整数,并将其值放入 guess
字段。
if
语句将 guess
与 NUMBER
进行比较,并使用 System.out.println
打印语句进行响应,以向人类玩家提供反馈。
如果 guess
既不大于也不小于 NUMBER
,则它必须等于它。此时,游戏会打印祝贺消息并退出。与 POSIX 应用程序设计的通常情况一样,此游戏以状态 0 退出,表示成功。
运行游戏
要测试您的游戏,请将示例代码另存为 Guess.java
,并使用 Java 命令运行它
$ java ./Guess.java
number is 38
Guess a number between 1 and 100
1
Too low
Guess a number between 1 and 100
39
Too high
Guess a number between 1 and 100
38
That's right!
$
正如预期的那样!
打包游戏
虽然在像这样的单文件应用程序上,它不如在复杂的项目上那么令人印象深刻,但 Java 使打包变得非常容易。为了获得最佳结果,请组织您的项目目录,使其包含源代码的位置、编译后的类的位置以及清单文件。在实践中,这在某种程度上是灵活的,并且使用 IDE 可以为您完成大部分工作。但是,偶尔手动执行一次也很有用。
如果您尚未创建项目文件夹,请创建一个。然后创建一个名为 src
的目录来保存您的源文件。将本文中的示例代码另存为 src/Guess.java
$ mkdir src
$ mv sample.java src/Guess.java
现在,创建一个目录树,该目录树镜像您的 Java 包的名称,该名称出现在代码的最顶部
$ head -n1 src/Guess.java
package com.example.guess;
$ mkdir -p com/example/guess
创建一个名为 Manifest.txt
的新文件,其中只有一行文本
$ echo "Manifest-Version: 1.0" > Manifest.txt
接下来,将您的游戏编译为 Java 类。这会在 com/example/guess
中生成一个名为 Main.class
的文件
$ javac src/Guess.java -d com/example/guess
$ ls com/example/guess/
Main.class
您已准备好将您的应用程序打包到 JAR(Java 归档)中。jar
命令与 tar 命令非常相似,因此许多选项可能看起来很熟悉
$ jar cfme Guess.jar \
Manifest.txt \
com.example.guess.Main \
com/example/guess/Main.class
从命令的语法中,您可能会猜测它创建了一个名为 Guess.jar
的新 JAR 文件,其所需的清单数据位于 Manifest.txt
中。其主类定义为包名称的扩展名,类为 com/example/guess/Main.class
。
您可以查看 JAR 文件的内容
$ jar tvf Guess.jar
0 Wed Nov 25 10:33:10 NZDT 2020 META-INF/
96 Wed Nov 25 10:33:10 NZDT 2020 META-INF/MANIFEST.MF
1572 Wed Nov 25 09:42:08 NZDT 2020 com/example/guess/Main.class
您甚至可以使用 xvf
选项提取它。
使用 java
命令运行您的 JAR 文件
$ java -jar Guess.jar
将您的 JAR 文件从 Linux 复制到 macOS 或 Windows 计算机并尝试运行它。无需重新编译,它也能按预期运行。如果您的比较基础是,例如,恰好在任何地方运行的简单 Python 脚本,这可能看起来很正常,但想象一个具有多个多媒体库和其他依赖项的复杂项目。使用 Java,这些依赖项与您的应用程序一起打包,并且所有内容都可以在任何平台上运行。欢迎来到精彩的 Java 世界!
2 条评论