vlambda博客
学习文章列表

JDK17 |java17学习 第 1 部分 Java 编程概述

Chapter 1: Getting Started with Java 17

本章是关于如何开始学习 Java 17 和一般 Java。我们将从基础开始,首先解释什么是 Java 及其主要术语,然后是如何安装必要的工具来编写和运行(执行)程序。在这方面,Java 17 与之前的 Java 版本没有太大区别,因此本章的内容也适用于旧版本。

我们将描述和演示构建和配置 Java 编程环境的所有必要步骤。这是您的计算机上开始编程的最低要求。我们还描述了基本的 Java 语言结构,并用可以立即执行的示例来说明它们。

学习一门编程语言——或任何一种语言——最好的方法就是使用它,本章将指导读者如何使用 Java 做到这一点。我们将在本章中介绍以下主题:

  • 如何安装和运行 Java
  • 如何安装和运行集成开发环境(IDE)
  • Java 基本类型和运算符
  • 字符串类型和文字
  • 标识符(ID)和变量
  • Java 语句

Technical requirements

为了能够执行本章提供的代码示例,您将需要以下内容:

  • 装有 Microsoft Windows、Apple macOS 或 Linux 操作系统的计算机
  • Java SE 版本 17 或更高版本
  • IDE 或您首选的代码编辑器

本章稍后将提供有关如何设置 Java 标准版 (SE) 和 IntelliJ IDEA 编辑器的说明。本章的代码示例文件可在 GitHub 上的 https:// github.com/PacktPublishing/Learn-Java-17-Programming.git 存储库,位于 examples/src/main/java/com/packt/learnjava/ch01_start文件夹。

How to install and run Java

somebody 说“Java”时,它们的含义可能完全不同。他们可能指的是以下任何一项:

  • Java 编程语言:一种高级编程语言,允许以人类可读的方式表达 意图(程序)可以翻译成计算机可执行的二进制代码的格式
  • Java 编译器:一个程序 ,可以读取用 Java 编程语言编写的文本,并将其翻译成字节码,以便由将 Java 虚拟机 (JVM) 转换为 可执行的二进制代码一台电脑
  • JVM:读取已编译Java程序的字节码并将其解释为计算机可执行的二进制代码的程序
  • Java 开发工具包 (JDK):程序集合(工具和实用程序),包括 Java 编译器、JVM 和支持库,它们允许编译和执行用 Java 语言编写的程序

以下部分将引导您完成 Java 17 JDK 的安装以及基本的相关术语和命令。

What is the JDK and why do we need it?

正如我们已经提到,JDK 包括Java 编译器和JVM。编译器的任务是读取一个 .java 文件,该文件包含用 Java 编写的程序的文本(称为源代码),并将其转换(编译)为存储在.class 文件。然后JVM可以读取.class文件,将字节码解释成二进制码,发送给操作系统执行。编译器和 JVM 都必须从命令行显式调用。

Java 程序使用的语言层次结构如下:

  • 您编写 Java 代码(.java 文件)。
  • 编译器将您的 Java 代码转换为字节码(.class 文件)。
  • JVM 将字节码转换为机器级汇编指令(在硬件上运行)。

看看下面的例子:

int a = b + c;

当您编写上述代码时,编译器会将以下字节码添加到 .class 文件中:

ILOAD b
ILOAD c
IADD
ISTORE a

一次编写,随处运行 是推动全球采用的最著名的编程营销广告。甲骨文声称有超过 1000 万开发人员使用 Java,它在 130 亿台设备上运行。您编写 Java 并将其编译为 .class 文件中的字节码。 Windows、Mac、Unix、Linux 等有不同的 JVM,但相同的 .class 文件适用于所有这些。

为了支持 .java 文件编译及其字节码执行,JDK 安装还包括标准 Java 库,称为 Java 类库 (JCL)。如果程序使用第三方库,则它必须在编译和执行期间存在。它必须从调用编译器的同一命令行中引用,然后在 JVM 执行字节码时引用。另一方面,JCL 不需要显式引用。假定标准 Java 库位于 JDK 安装的默认位置,以便编译器和 JVM 知道在哪里可以找到它们。

如果您不需要编译 Java 程序并且只想运行已经编译好的 .class 文件,您可以下载并安装 Java运行时环境 (JRE)。对于 示例,它由 JDK 的子集组成,不包括编译器。

有时,JDK被称为软件开发工具包(SDK ),它是软件工具和支持库的集合的总称,允许创建使用某种编程语言编写的源代码的可执行版本。因此,JDK 是 Java 的 SDK。这意味着可以将 JDK 称为 SDK。

您可能听说过Java平台Java 版本 应用于 JDK。典型的平台是允许开发和执行软件程序的操作系统。由于JDK提供了自己的运行环境,所以也称为平台。版本是为特定目的而组装的 Java 平台 (JDK) 的变体。有 四个 Java 平台版本,如下所列:

  • Java 平台 SE (Java SE):这 包括 JVM、JCL 和其他工具和实用程序。
  • Java Platform Enterprise Edition (Java EE):这包括 Java SE、服务器(计算机< /a> 为应用程序提供服务的程序)、JCL、其他库、代码示例、教程和其他文档,用于开发和部署大规模、多层和安全的网络应用程序。
  • Java Platform Micro Edition (Java ME):这是 Java SE 的一个子集,带有一些 专门的 库,用于为嵌入式和移动设备(例如电话、个人数字助理、电视机顶盒、打印机和传感器)开发和部署 Java 应用程序。 Java ME 的一个变体(具有自己的 JVM 实现)称为 Android SDK,它是由 Google 为 Android 编程开发的。
  • Java Card:此 是 Java 版本中最小的,旨在用于在小型嵌入式设备(如智能卡)上开发和部署 Java 应用程序。它有两个版本:Java Card Classic Edition,用于智能 卡,(基于国际标准化组织(ISO) 7816 和 ISO 14443 通信)和 Java Card Connected Edition,它支持web应用模型和传输控制协议/互联网协议 (TCP/IP)作为基本协议并在高端安全微控制器上运行。
  • 因此,安装 Java 意味着安装 JDK,这也意味着在列出的版本之一上安装 Java 平台。在本书中,我们将只讨论和使用 Java SE(包括 JVM、JCL 和其他工具)以及将 Java 程序编译为字节码、将其解释为二进制代码并自动将其发送到操作系统执行所需的实用程序)。

Installing Java SE

所有最近 发布的 JDK 都列在 Oracle 官方页面 https://www.oracle.com/java/technologies/downloads/#java17(我们将其称为安装主页后面章节中的参考)。

以下是安装 Java SE 需要遵循的步骤:

  1. 使用您的操作系统选择 Java SE 选项卡。
  2. 单击适合您的操作系统和您熟悉的格式(扩展名)的安装程序的链接。
  3. 如有疑问,请单击下面的安装说明链接并阅读适用于您操作系统的安装说明。
  4. 按照与您的操作系统相对应的步骤进行操作。
  5. 当您的计算机上的 java -version 命令显示正确的 Java 版本时,JDK 安装成功,如下例所示截屏:
JDK17 |java17学习 第 1 部分 Java 编程概述

Commands, tools, and utilities

如果您按照 安装 说明,您可能已经注意到一个链接( JDK 的已安装目录结构)在目录下给出。这会将您带到一个页面,该页面描述了您计算机上安装的 JDK 的位置以及 JDK 根目录的每个目录的内容。 bin 目录包含构成 Java 命令、工具和实用程序的所有可执行文件。如果 bin 目录未自动添加到 PATH 环境变量中,请考虑手动添加,以便您可以启动 Java 可执行文件从任何目录。

在上一节中,我们已经演示了 java -version Java 命令。可以在 Java SE 文档 (https://www.oracle.com/technetwork/java/javase/documentation/index.html) 通过单击 Java 平台标准版技术文档 站点链接,然后是下一页的工具参考链接。您可以通过单击其链接了解有关每个可执行工具的更多信息。

您还可以使用以下选项之一在您的计算机上运行每个列出的可执行文件:

-?-h--help-帮助

这些将显示可执行文件及其所有选项的简要说明。

这里列出了最重要的 Java 命令:

  • javac:读取一个.java文件,编译它,并创建一个或多个对应的 .class 文件,具体取决于 .java 文件中定义了多少 Java 类。
  • java:这会执行一个 .class 文件。

这些是使编程成为可能的命令。每个 Java 程序员都必须对自己的结构和功能有很好的了解,但如果您是 Java 编程新手并使用 IDE(请参阅如何安装和运行 IDE 部分) ,您不需要立即掌握这些命令。一个好的 IDE 通过 自动编译一个 .java 文件 来隐藏它们每次您对其进行 更改。它还提供了一个图形元素,每次单击它时都会运行该程序。

另一个非常有用的 Java 工具是 jcmd。这有助于与任何当前运行的 Java 进程 (JVM) 进行通信和诊断,并且有许多选项。但以最简单的形式,没有任何选项,它列出了所有当前正在运行的 Java 进程及其进程 ID (PID)。您可以使用它来查看您是否有失控的Java 进程。如果有,您可以使用提供的 PID 终止此类进程。

How to install and run an IDE

只是一个专门的编辑器,它允许检查书面程序的语法,就像 Word 编辑器检查语法一样一个英文句子逐渐演变成一个IDE。这在名称中具有其主要功能。它在一个图形用户界面(GUI)。借助 Java 编译器的强大功能,IDE 可以立即识别语法错误, 然后通过提供与上下文相关的帮助来帮助提高代码质量和建议。

Selecting an IDE

有几个可供 Java 程序员使用的 IDE,例如 NetBeans、Eclipse、IntelliJ IDEA、BlueJ、DrJava、JDeveloper、JCreator、jEdit、JSource 和 jCRASP 等等.您可以通过以下链接阅读对顶级 Java IDE 的评论和每个的详细信息:https://www.softwaretestinghelp.com/best-java-ide-and-online-compilers。最流行的是 NetBeans、Eclipse 和 IntelliJ IDEA。

NetBeans 的开发始于 1996 年,当时是布拉格查尔斯大学的一个 Java IDE 学生项目。 1999 年,该项目和围绕该项目创建的公司被 Sun Microsystems 收购。在甲骨文收购 Sun Microsystems 之后,NetBeans 成为开源软件,许多 Java 开发人员从此为该项目做出了贡献。它与 JDK 8 捆绑在一起,成为 Java 开发的官方 IDE。 2016 年,甲骨文将其捐赠给了 Apache 软件基金会。

有一个适用于 Windows、Linux、Mac 和 Oracle Solaris 的 NetBeans IDE。它支持多种编程语言,并且可以使用插件进行扩展。在撰写本文时,NetBeans 仅与 JDK 8 捆绑在一起,但 NetBeans 8.2 也可以与 JDK 9 一起使用,并使用 JDK 9 引入的功能,例如 Jigsaw。在 netbeans.apache.org 上,您可以阅读有关 NetBeans IDE 的更多信息并下载最新版本,即 12.5在撰写本文时。

Eclipse 是使用最广泛的 Java IDE。为 IDE 添加新功能的插件列表不断增加,因此无法枚举 IDE 的所有功能。 Eclipse IDE 项目自 2001 年以来被开发为开源软件(OSS)。 Eclipse 基金会成立于 2004 年,是一个非盈利的、成员支持的公司,用于提供基础架构(版本控制系统(VCS) ,代码 审查系统、构建服务器、下载站点等)和结构化流程。 Eclipse 基金会 30 多岁的员工中没有一个在从事 150 个 Eclipse 支持的项目中的任何一个。

Eclipse IDE 插件的数量和种类之多给初学者带来了一定的挑战,因为您必须找到解决相同或相似功能的不同实现的方法,这些功能有时可能不兼容并且可能需要深入调查作为对所有依赖项的清晰理解。尽管如此,Eclipse IDE 还是非常流行的,并且拥有可靠的社区支持。您可以阅读 Eclipse IDE 并从 www.eclipse.org/ide 下载最新版本。

IntelliJ IDEA 有两个版本:付费版和免费社区版。付费版一直被评为最佳 Java IDE,但社区版也被列为三大领先的 Java IDE 之一。开发 IDE 的 JetBrains 软件公司在布拉格、圣彼得堡、莫斯科、慕尼黑、波士顿和新西伯利亚设有办事处。 IDE 以其深度智能而闻名,“在每个上下文中提供相关建议:即时和聪明的代码完成、动态代码分析和可靠的重构工具”,正如作者在其网站 (www. jetbrains.com/idea)。在安装和配置 IntelliJ IDEA 部分,我们将引导您完成 IntelliJ IDEA 社区版的安装和配置。

Installing and configuring IntelliJ IDEA

这些 是您下载和安装 IntelliJ IDEA 需要遵循的 步骤:

  1. www.jetbrains.com/idea/download 下载 IntelliJ 社区版的安装程序。
  2. 启动安装程序并接受所有默认值。
  3. 安装选项屏幕上选择.java。我们假设您已经安装了 JDK,因此您无需勾选 Download and install JRE 选项。
  4. 最后一个安装屏幕有一个 Run IntelliJ IDEA 复选框,您可以选中该复选框以自动启动 IDE。或者,您可以取消选中该复选框,并在安装完成后手动启动 IDE。
  5. 当 IDE 首次启动时,它会为您提供 Import IntelliJ IDEA settings 选项。如果您之前没有使用过 IntelliJ IDEA,请选中 Do not import settings 复选框。
  6. 接下来的几个屏幕会询问您是否接受 JetBrains 隐私政策,以及您是否愿意为许可证付费还是更愿意继续使用免费社区版或免费试用版(此取决于您获得的特定下载)。
  7. 以您喜欢的方式回答问题,如果您接受隐私政策,Customize IntelliJ IDEA 屏幕将要求您选择一个主题:white (IntelliJ) 或 dark (Darcula)。
  8. 接受默认设置。
  9. 如果您决定更改设置值,您可以稍后通过从最顶部的菜单中选择文件 | 设置,在 Windows 上,或 Preferences 在 Linux 和 macOS 上。

Creating a project

在您开始编写程序之前,您需要创建一个项目。在 IntelliJ IDEA 中创建项目有几种方法,任何 IDE 都一样,如下:

  1. 新项目:这会从头开始创建一个新项目。
  2. Open:这有助于从文件系统中读取现有项目。
  3. 从 VCS 获取:这有助于从 VCS 中读取现有项目。

在本书中,我们将仅引导您完成第一个选项——使用 IDE 提供的引导步骤序列。选项 23 包括许多通过导入具有这些设置的现有项目自动设置的设置。一旦您学会了如何从头开始创建新项目,在 IDE 中启动项目的其他方法对您来说将非常容易。

首先单击 New Project 链接,然后按以下步骤继续:

  1. 在左侧面板中选择 Maven 和 Project SDK 的值(Java 版本 17,如果您已经安装了 JDK 17),并点击下一步。
  2. Maven是一个项目配置工具,主要功能是管理项目依赖。我们将很快讨论它。现在,我们将使用它的其他职责:使用三个 Artifact Coordinates 属性来定义和保存项目代码标识(见下文)。
  3. 输入项目名称,例如 myproject
  4. Location field 设置中选择所需的项目位置(这是您的新代码所在的位置)。
  5. 点击Artifact Coordinates,会出现如下属性:
    • GroupId:这是标识组织 或开源社区内的一组项目的基本包名称。在我们的例子中,我们输入 com.mywork
    • ArtifactId:标识组内的特定项目。将其保留为 myproject
    • Version:标识项目的版本。将其保留为 1.0-SNAPSHOT

主要目标是使项目的身份在世界上所有项目中独一无二。为了帮助避免 GroupId 冲突,约定要求您从组织域名反向开始构建它。例如,如果一家公司拥有 company.com 域名,则其项目的 GroupId 属性应以 com.company。这就是为什么在这个演示中我们使用 com.mywork,而对于本书中的代码,我们使用 com.packt.learnjava GroupID 值。

  1. 点击完成。
  2. 您将看到以下项目结构和生成的 pom.xml 文件:
JDK17 |java17学习 第 1 部分 Java 编程概述

现在,如果有人想在他们的应用程序中使用您项目的代码,他们会通过显示的三个值引用 它,Maven(如果他们使用它)将带来它在(当然,如果您将项目上传到公开共享的 Maven 存储库)。在 https://maven.apache.org/guides 阅读有关 Maven 的更多信息。 GroupId 值的另一个功能是定义保存项目代码的文件夹树的根目录。 main 下的 java 文件夹将保存应用程序代码,而 java test 下的文件夹将保存测试代码。

让我们使用以下步骤创建我们的第一个程序:

  1. 右击java,选择New,然后点击Package,如以下屏幕截图所示:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 在提供的 New Package 窗口中,输入 com.mywork.myproject 并按 Enter

您应该在左侧面板中看到以下一组新文件夹:

JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 右击com.mywork.myproject,选择New,然后点击Java Class ,如下图所示:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 在提供的输入窗口中,输入HelloWorld,如下:
    JDK17 |java17学习 第 1 部分 Java 编程概述
  1. Enter,您将看到在 com 中创建的第一个 Java 类 HelloWorld。 mywork.myproject 包,如下图所示:
JDK17 |java17学习 第 1 部分 Java 编程概述

该包反映了文件系统中的 Java 类位置。我们将在 第 2 章中详细讨论这个问题Java 面向对象编程 (OOP)。现在,为了运行程序,我们 创建一个main() 方法。如果存在,则可以执行此方法作为应用程序的入口点。它具有一定的格式,如下所示:

JDK17 |java17学习 第 1 部分 Java 编程概述

这必须具有以下属性:

  • public:可从包外自由访问
  • static:应该可以在不创建所属类的对象的情况下调用

它还应具有以下内容:

  • 返回 void(无)

像我们所做的那样,接受 String 数组或 varargs 作为输入。我们将在 varargs ="italic">第 2 章Java 面向对象编程 (OOP)。现在,可以说 String[] argsString... args 基本上定义了相同的输入格式。

我们在 从命令行执行示例 部分解释了如何使用命令行运行 main 类。您可以在 https 上的 Oracle 官方文档中阅读有关 Java 命令行参数的更多信息://docs.oracle.com/javase/tutorial/essential/environment/cmdLineArgs.html。也可以从 IntelliJ IDEA 运行示例。

请注意接下来显示的屏幕截图中左侧的两个绿色三角形。通过单击其中任何一个,您可以执行 main() 方法。例如,让我们显示 Hello, world!

要执行 this,请在 main() 方法中键入以下行:

System.out.println("Hello, world!");

以下屏幕截图显示了该程序的外观:

JDK17 |java17学习 第 1 部分 Java 编程概述

然后,单击其中一个绿色三角形,您应该在终端区域中获得以下输出:

JDK17 |java17学习 第 1 部分 Java 编程概述

从现在开始,每次我们要讨论代码示例时,我们都将以相同的方式运行它们,使用 main() 方法。这样做时,我们不会截取屏幕截图,而是将结果放在评论中,因为这样的风格更容易遵循。例如,以下代码片段显示了以前的代码演示在这种样式中的外观:

System.out.println("Hello, world!"); //prints: Hello, world!

It is possible to add a comment (any text) to the right of the code line separated by a double slash //. The compiler does not read this text and just keeps it as it is. The presence of a comment does not affect performance and is used to explain the programmer’s intent to humans.

Importing a project

我们将使用本书的源代码来演示项目导入。我们假设您已经安装了 Maven (https://maven.apache.org/install.html ) 在您的计算机上并且您拥有 Git (https://gist.github.com/derhuerst/1b15ff4652a867391f03 ) 也安装了,可以使用了。我们还假设您已安装 JDK 17,如 安装 Java SE 部分所述。

要使用本书的代码示例导入项目,请执行以下步骤:

  1. 转到源存储库 (https://github.com/PacktPublishing/Learn-Java-17 -Programming),然后点击Code下拉菜单,如下截图所示:
    JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 复制提供的统一资源定位符(URL)(点击copy 符号到 URL 的右侧),如以下屏幕截图所示:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 在您的计算机上选择您希望放置源代码的目录,然后运行 ​​git clone https://github.com/PacktPublishing/Learn-Java-17-Programming.git< /code> Git 命令并观察与以下屏幕截图中所示类似的输出:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 创建了一个新的 Learn-Java-17-Programming 文件夹。

或者,您可以使用屏幕截图中显示的 Download ZIP 链接将源代码下载为 .zip 文件,而不是克隆前。在您希望放置源代码的计算机目录中解压缩下载的源代码,然后通过从其名称中删除 -master 后缀来重命名新创建的文件夹,确保文件夹的名称是 Learn-Java-17-Programming

  1. 新的 Learn-Java-17-Programming 文件夹包含 Maven 项目以及本书中的所有源代码。如果您愿意,可以随意重命名此文件夹。在我们的例子中,为了简洁起见,我们将其重命名为 LearnJava
  2. 现在,运行 IntelliJ IDEA 并单击 Open。导航到项目的位置并选择刚刚创建的文件夹(在我们的例子中为 LearnJava),然后单击 Open按钮。
  3. 如果右下角出现以下弹窗,点击加载:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 另外,点击信任项目...,如下图所示:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 然后,单击以下弹出窗口中的 Trust Project 按钮:
    JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 现在,转到 Project Structure(右上角的齿轮符号)并确保选择 Java 17 作为 SDK,如以下屏幕截图所示:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 点击应用并确保默认Project SDK设置为Java version 17 和 Project language level 设置为 17,如以下屏幕截图:
    JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 单击 Apply,然后(可选)通过选择并单击 " 删除 LearnJava 模块- ",如下:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 点击Yes,确认弹出的LearnJava模块移除,如下:
JDK17 |java17学习 第 1 部分 Java 编程概述
  1. 以下是最终模块列表的外观:
    JDK17 |java17学习 第 1 部分 Java 编程概述

单击右下角的OK,然后返回您的项目。单击左侧窗格中的示例并继续沿源代码树向下走,直到您看到以下类列表:

JDK17 |java17学习 第 1 部分 Java 编程概述

单击右侧窗格中的绿色箭头并执行您想要的任何类的 main() 方法。例如,让我们执行 PrimitiveTypes 类的 main() 方法。 您将能够在 Run 窗口中看到的结果应该类似于以下内容:

JDK17 |java17学习 第 1 部分 Java 编程概述

Executing examples from the command line

要从命令行执行 示例,请转到 examples 文件夹,其中 pom找到 .xml 文件,然后运行 ​​mvn clean package 命令。如果命令执行成功,您可以从命令行。例如,要执行 ControlFlow.java 文件中的 main() 方法,将以下命令作为一行运行:

java -cp target/examples-1.0-SNAPSHOT.jar   com.packt.learnjava.ch01_start.ControlFlow

您将看到以下结果:

JDK17 |java17学习 第 1 部分 Java 编程概述

这样,您可以运行任何包含 main() 方法的类。 main()方法的内容会被执行。

Java primitive types and operators

有了所有 main 编程工具,我们就可以开始谈论Java 作为一种语言了。语言语法由 Java 语言规范 定义,您可以在 https://docs.oracle.com/javase/specs。每当您需要澄清时,请不要犹豫,参考它——它并不像许多人想象的那样令人生畏。

Java 中的所有值都分为两类:引用类型和原始类型。我们从原始类型和运算符作为任何编程语言的自然入口点开始。在本章中,我们还将讨论一种称为 String 的引用类型(参见 String types and literals 部分)。

所有原始类型都可以分为两组:布尔类型和数字类型。

Boolean types

Java中只有两个布尔类型值:true。这样的值只能分配给 boolean 类型的变量,如下例所示:

boolean b = true;

boolean 变量通常用于控制流语句,我们将在 Java 语句 部分中讨论。这是一个例子:

boolean b = x > 2;
if(b){ 
    //do something
}

在前面的代码中,我们将 x > 的求值结果赋给 b 变量。 2 表达式。如果 x 的值大于 2,则 b 变量得到分配的值,true。然后,执行大括号内的代码 ({})。

Numeric types

Java numeric 类型分为两组:整型(bytecharshortintlong )和浮点类型(floatdouble)。

Integral types

Integral 类型 消耗以下内存量:

  • 字节:8位
  • char:16 位
  • short:16 位
  • int:32 位
  • long:64 位

char 类型是一个无符号整数,可以保存从 0 到 65,535 的值(称为代码点)。它代表一个 Unicode 字符,这意味着有 65,536 个 Unicode 字符。以下是 Unicode 字符基本拉丁语列表中的三个记录:

JDK17 |java17学习 第 1 部分 Java 编程概述

以下代码演示了 char 类型的属性(执行 main() 方法< com.packt.learnjava.ch01_start.PrimitiveTypes 类的 /a> - 请参阅 charType() 方法):

char x1 = '\u0032';
System.out.println(x1);  //prints: 2
char x2 = '2';
System.out.println(x2);  //prints: 2
x2 = 65;
System.out.println(x2);  //prints: A
char y1 = '\u0041';
System.out.println(y1);  //prints: A
char y2 = 'A';
System.out.println(y2);  //prints: A
y2 = 50;
System.out.println(y2);  //prints: 2
System.out.println(x1 + x2);  //prints: 115
System.out.println(x1 + y1);  //prints: 115

前面代码示例的最后两行解释了为什么将 char 类型视为整数类型,因为 char 值可以用于算术运算。在这种情况下,每个 char 值都由其代码点表示。

其他整数类型的取值范围如下所示:

  • byte:从 -128 到 127(含)
  • short:从 -32,768 到 32,767(含)
  • int:从 -2.147.483.648 到 2.147.483.647(含)
  • long:从 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807(含)

可以总是从对应的Java常量中检索每个原始类型的最大值和最小值,如下(执行com.packt.learnjava.ch01_start.PrimitiveTypes 类的 class="literal">main() 方法——参见 minMax () 方法):

System.out.println(Byte.MIN_VALUE);      //prints: -128
System.out.println(Byte.MAX_VALUE);      //prints:  127
System.out.println(Short.MIN_VALUE);     //prints: -32768
System.out.println(Short.MAX_VALUE);     //prints:  32767
System.out.println(Integer.MIN_VALUE);   //prints: -2147483648
System.out.println(Integer.MAX_VALUE);   //prints:  2147483647
System.out.println(Long.MIN_VALUE);      
                                 //prints: -9223372036854775808
System.out.println(Long.MAX_VALUE);
                                  //prints: 9223372036854775807
System.out.println((int)Character.MIN_VALUE); //prints: 0
System.out.println((int)Character.MAX_VALUE); //prints: 65535

最后两行中的构造 (int) 是强制转换运算符用法的一个示例。在这种转换并不总是保证成功的情况下,它会强制将值从一种类型转换为另一种类型。正如您从我们的示例中看到的那样,某些类型允许比其他类型更大的值。但是程序员可能知道某个变量的值永远不会超过目标类型的最大值,而强制转换运算符是程序员可以将自己的意见强加给编译器的方式。否则,如果没有强制转换运算符,编译器将引发错误并且不允许赋值。但是,程序员可能会弄错,值可能会变大。在这样的的情况下,会在执行期间引发运行时错误。

原则上,有些类型不能转换为其他类型,或者至少不能转换为所有类型——例如,布尔类型值不能转换为整数类型值。

Floating-point types

这组原始类型中有 两个 类型——float 和 <代码类="literal">双。这些消耗以下内存量:

  • 浮点数:32位
  • double:64 位

它们的正最大和最小可能值显示在这里(执行 com.packt.learnjava.ch01_start.PrimitiveTypes 的 main() 方法 类——参见 minMax() 方法):

System.out.println(Float.MIN_VALUE);  //prints: 1.4E-45
System.out.println(Float.MAX_VALUE);  //prints: 3.4028235E38
System.out.println(Double.MIN_VALUE); //prints: 4.9E-324
System.out.println(Double.MAX_VALUE); 
                               //prints: 1.7976931348623157E308

最大和最小负值与刚才显示的相同,只是前面有一个减号(-)。因此,实际上, Float.MIN_VALUEDouble.MIN_VALUE 值不是最小值,而是对应类型的精度.对于每种浮点类型,零值可以是 0.0 或 -0.0。

浮点类型的一个特殊功能是存在一个点 (.),用于分隔数字的整数和小数部分。默认情况下,在 Java 中,带点的数字被假定为 double 类型。例如,假设以下是 double 值:

42.3

这意味着 以下赋值会导致编译错误:

float f = 42.3;

要表明您希望它被视为 float 类型,您需要添加 fF。比如下面的赋值不会出错(执行com.packt.learnjava.ch01_start.PrimitiveTypes<的main()方法/code> 类——参见 casting() 方法):

float f = 42.3f;
float d = 42.3F;
double a = 42.3f;
double b = 42.3F;
float x = (float)42.3d;
float y = (float)42.3D;

您可能已经从前面的示例中注意到,dD 表示 double 类型,但我们能够将它们转换为 float 类型,因为我们确信 42.3 在可能的 float 类型值的范围内。

Default values of primitive types

在某些情况下,即使程序员不想这样做,也必须为 变量赋值。我们将在 第 2 章中讨论此类案例Java 面向对象编程 (OOP)。在这种情况下,默认的原始类型值在此处概述:

  • byteshortintlong 类型的默认值为 0。
  • char 类型的默认值为 \u0000,代码点为 0。
  • floatdouble 类型的默认值为 0.0。
  • boolean 类型的默认值为 false

Literals of primitive types

值的表示 称为文字。 boolean 类型有两个字面量:truefalsebyteshortintlong 整数类型默认具有 int 类型,如下所示:

byte b = 42;
short s = 42;
int i = 42;
long l = 42;

另外,要表示 long 类型的字面量,可以附加字母 lL 到最后,像这样:

long l1 = 42l;
long l2 = 42L;

字母 l 很容易与数字 1 混淆,所以使用 L(而不是 l)用于此目的是一个很好的做法。

到目前为止,我们已经在十进制数系统中表达了整数文字。同时,byteshortintlong 类型也可以用二进制(基数 2,数字 0-1)、八进制(基数 8,数字 0-7)和十六进制(基数 16,数字 0-9 和a-f) 数字系统。二进制文字以 0b(或 0B)开头,后跟以二进制系统表示的值。例如十进制的 42 表示为 101010 = 2^0*0 + 2^1*1 + 2^2*0 + 2^3 *1 + 2^4 *0 + 2^5 *1 (我们从正确的 0)。八进制文字以 0 开头,后面是八进制表示的值,因此 42 表示为 52 = 8^0*2+ 8^1*5。十六进制文字以 0x(或以 0X)开头,后跟以十六进制系统表示的值。因此,42 表示为 2a = 16^0*a + 16^1*2,因为在十六进制系统中,符号 a f(或 AF)映射到十进制值 10 到 15。这里 为演示代码(执行com.packt.learnjava.ch01_start.PrimitiveTypes<的main()方法/code> 类——参见 literals() 方法):

int i = 42;
System.out.println(Integer.toString(i, 2));       // 101010
System.out.println(Integer.toBinaryString(i));    // 101010
System.out.println(0b101010);                     // 42
System.out.println(Integer.toString(i, 8));       // 52
System.out.println(Integer.toOctalString(i));     // 52
System.out.println(052);                           // 42
System.out.println(Integer.toString(i, 10));       // 42
System.out.println(Integer.toString(i));           // 42
System.out.println(42);                            // 42
System.out.println(Integer.toString(i, 16));       // 2a
System.out.println(Integer.toHexString(i));        // 2a
System.out.println(0x2a);                          // 42

如您所见,Java 提供了将十进制系统值转换为具有不同基数的系统的方法。所有这些数值表达式都称为文字。

数字文字的一个特性使它们对人类友好。如果数字很大,则可以将其分成由下划线 (_) 分隔的三元组。例如,请注意以下事项:

int i = 354_263_654;
System.out.println(i);  //prints: 354263654
float f = 54_436.98f;
System.out.println(f);  //prints: 54436.98
long l = 55_763_948L;
System.out.println(l);  //prints: 55763948

编译器会忽略嵌入的下划线符号。

char 类型有两种文字:单个字符或转义序列。在讨论数字类型时,我们已经看到了 char 类型文字的示例,您可以在此处查看其他一些示例:

char x1 = '\u0032';
char x2 = '2';
char y1 = '\u0041';
char y2 = 'A';

如您所见,字符必须用单引号括起来。

转义序列以反斜杠 (\) 开头,后跟一个字母或其他字符。以下是转义序列的完整列表:

  • \b:退格 BS,Unicode 转义 \u0008
  • \t:水平制表符 HT,Unicode 转义 \u0009
  • \n:换行 LF,Unicode 转义 \u000a
  • \f:换页 FF,Unicode 转义 \u000c
  • \r:回车 CR,Unicode 转义 \u000d
  • \”: 双引号“, Unicode 转义 \u0022
  • \': 单引号', Unicode 转义 \u0027
  • \\: 反斜杠 \, Unicode 转义 \u005c

从八个转义序列中,只有最后三个由符号表示。当无法以其他方式显示此符号时使用它们。例如,请注意以下事项:

System.out.println("\"");   //prints: "
System.out.println('\'');   //prints: '
System.out.println('\\');   //prints: \

其余的则使用 作为控制代码,指示输出设备执行某些操作,如下例所示:

System.out.println("The back\bspace");
                                        //prints: The backspace
System.out.println("The horizontal\ttab"); 
                                   //prints: The horizontal tab
System.out.println("The line\nfeed"); 
                                        //prints: The line feed
System.out.println("The form\ffeed");      
                                        //prints: The form feed
System.out.println("The carriage\rreturn");//prints: return

如你所见,\b 删除前一个符号,\t插入一个制表符,\n 换行并开始新行,\f 强制打印机弹出当前页面并继续打印 在另一个的顶部,并且 \r 重新开始当前行。

New compact number format

java.text.NumberFormat 类以各种格式呈现数字。它还允许将格式 调整为提供的格式,包括语言环境。 Java 12 中为此类添加的一项新功能称为紧凑或短数字格式。

它以特定于语言环境的、人类可读的形式表示一个数字。观察以下内容,例如(执行 com.packt.learnjava.ch01_start.PrimitiveTypes 类的 main() 方法——请参阅 newNumberFormat() 方法):

NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
System.out.println(fmt.format(42_000));          //prints: 42K
System.out.println(fmt.format(42_000_000));      //prints: 42M
NumberFormat fmtP = NumberFormat.getPercentInstance();
System.out.println(fmtP.format(0.42));          //prints: 42%

如您所见,要访问此功能,您必须获取 NumberFormat 类的特定实例,有时基于提供的语言环境和样式。

Operators

Java 中有 44 个运算符。这些列在下表中:

JDK17 |java17学习 第 1 部分 Java 编程概述

我们不会描述不常用的&=, |=, ^ =, <<=, >>=, >>>= 赋值运算符和位运算符,但您可以在 Java 规范 (https://docs.oracle.com/javase/specs)。箭头(->)和方法引用(::)运算符将在第 14 章Java 标准流new 实例创建运算符、. 字段访问/方法调用运算符和 instanceof type 比较运算符将在 第 2 章Java 面向对象编程 (OOP)。至于强制转换运算符,我们已经在 Integral types 部分进行了描述。

Arithmetic unary (+ and -) and binary (+, -, *, /, and %) operators

大多数算术算子< /a> 和正负号(一元运算符)对我们来说非常熟悉。取模运算符 (%) 将左侧操作数除以右侧操作数并返回余数,如下所示(执行 main( com.packt.learnjava.ch01_start.Operators 类的 ) 方法——参见 integerDivision() 方法:

int x = 5;
System.out.println(x % 2);   //prints: 1

还值得一提的是,Java 中两个整数的除法丢失了小数部分,因为 Java 假定结果应该是整数2,如下:

int x = 5;
System.out.println(x / 2);   //prints: 2

如果您需要保留结果的小数部分,请将其中一个操作数转换为浮点类型。以下是执行此操作的几种方法(在许多方法中):

int x = 5;
System.out.println(x / 2.);           //prints: 2.5
System.out.println((1. * x) / 2);     //prints: 2.5
System.out.println(((float)x) / 2);   //prints: 2.5
System.out.println(((double) x) / 2); //prints: 2.5

Increment and decrement unary operators (++ and --)

++ 运算符 增加 整数类型的值减 1,而 -- 运算符将其减 1。如果放在变量(前缀),它在返回变量值之前将其值更改为 1。但是当放在变量(后缀)之后时,它会在变量值返回后将其值更改为 1。这里有几个例子(执行 com.packt.learnjava.ch01_start.Operators 类的 main() 方法——见incrementDecrement() 方法):

int i = 2;
System.out.println(++i);   //prints: 3
System.out.println(i);     //prints: 3
System.out.println(--i);   //prints: 2
System.out.println(i);     //prints: 2
System.out.println(i++);   //prints: 2
System.out.println(i);     //prints: 3
System.out.println(i--);   //prints: 3
System.out.println(i);     //prints: 2

Equality operators (== and !=)

== 运算符 表示 等于,而 != 运算符表示不等于。它们用于比较相同类型的值,如果操作数的值为 equal,则返回 true 布尔值class="literal">false 否则。观察以下,例如(执行com.packt.learnjava.ch01_start.Operators类的main()方法——参见 equality() 方法):

int i1 = 1;
int i2 = 2;
System.out.println(i1 == i2);        //prints: false
System.out.println(i1 != i2);        //prints: true
System.out.println(i1 == (i2 - 1));  //prints: true
System.out.println(i1 != (i2 - 1));  //prints: false

但是,在比较浮点类型的值时要小心,尤其是在比较计算结果时。使用关系运算符(<><=、和 >=) 在这种情况下更可靠,因为诸如 1/3 之类的计算——例如——结果 in一个永无止境的小数部分 0.33333333... 和 最终取决于精确实现(一个超出本书范围的复杂主题)。

Relational operators (<, >, <=, and >=)

关系 运算符 比较值并返回布尔值。观察以下内容,例如(执行 com.packt.learnjava.ch01_start.Operators 类的 main() 方法——请参阅 relational() 方法):

int i1 = 1;
int i2 = 2;
System.out.println(i1 > i2);         //prints: false
System.out.println(i1 >= i2);        //prints: false
System.out.println(i1 >= (i2 - 1));  //prints: true
System.out.println(i1 < i2);         //prints: true
System.out.println(i1 <= i2);        //prints: true
System.out.println(i1 <= (i2 - 1));  //prints: true
float f = 1.2f;
System.out.println(i1 < f);          //prints: true

Logical operators (!, &, and |)

逻辑算子可以定义如下:

  • 如果操作数为 false,则 ! 二元运算符返回 true;否则,它返回 false
  • 如果两个操作数都是 true,则 & 二元运算符返回 true .
  • 如果至少有一个操作数为 true| 二元运算符返回 true >。

下面是一个示例(执行 com.packt.learnjava.ch01_start.Operators 类的 main() 方法——参见logical() 方法):

boolean b = true;
System.out.println(!b);    //prints: false
System.out.println(!!b);   //prints: true
boolean c = true;
System.out.println(c & b); //prints: true
System.out.println(c | b); //prints: true
boolean d = false;
System.out.println(c & d); //prints: false
System.out.println(c | d); //prints: true

Conditional operators (&&, ||, and ? :)

&&|| 运算符 产生 与我们刚才演示的&|逻辑运算符的结果相同,如下(执行 com.packt.learnjava.ch01_start.Operators 类的 main() 方法——参见 conditional() 方法):

boolean b = true;
boolean c = true;
System.out.println(c && b); //prints: true
System.out.println(c || b); //prints: true
boolean d = false;
System.out.println(c && d); //prints: false
System.out.println(c || d); //prints: true

不同之处在于 &&|| 运算符并不总是计算第二个操作数。例如 && 运算符的情况下,如果第一个操作数为 false,则第二个操作数不是 被评估,因为整个表达式的结果将是 false 反正。类似地,在 || 运算符的情况下,如果第一个操作数是 true,则整个表达式将被明确计算为true 不计算第二个操作数。我们可以在下面的代码片段中证明这一点:

int h = 1;
System.out.println(h > 3 && h++ < 3);  //prints: false
System.out.println(h);                //prints: 2
System.out.println(h > 3 && h++ < 3); //prints: false
System.out.println(h);                //prints: 2

? : 运算符称为三元运算符。它评估一个条件(在 ? 符号之前),如果结果为 true,则将计算的值分配给变量第一个表达式(在 ?: 符号之间);否则,它分配一个由第二个表达式计算的值(在 : 符号之后),如以下代码片段所示:

int n = 1, m = 2;
float k = n > m ? (n * m + 3) : ((float)n / m); 
System.out.println(k);           //prints: 0.5

Assignment operators (=, +=, -=, *=, /=, and %=)

= 运算符只是 将一个 指定值分配给变量,如下所示:

x = 3;

其他赋值运算符在赋值之前计算一个新值,如下所示:

  • x += 42x = x + 42 的结果分配给 x代码>加法运算。
  • x -= 42x = x - 42 的结果分配给 x代码>减法运算。
  • x *= 42x = x * 42 的结果分配给 x代码>乘法运算。
  • x /= 42x = x / 42 的结果分配给 x代码>除法运算。
  • x %= 42 分配 x = x + x % 42 除法运算的余数。

以下是这些运算符的工作原理(执行 com.packt.learnjava.ch01_start.Operators 类的 main() 方法——参见 assignment() 方法):

float a = 1f;
a += 2;
System.out.println(a); //prints: 3.0
a -= 1;
System.out.println(a); //prints: 2.0
a *= 2;
System.out.println(a); //prints: 4.0
a /= 2;
System.out.println(a); //prints: 2.0
a %= 2;
System.out.println(a); //prints: 0.0

String types and literals

我们刚刚描述了Java 语言的原始值类型。 Java 中的所有其他值类型都属于引用类型的范畴。每个引用类型都是一个比值更复杂的构造。它由一个类(用作创建对象的模板)和一个包含该类中定义的值和方法(处理代码)的内存区域来描述。 new 操作符创建一个对象。我们将在 第 2 章中更详细地讨论类和对象Java 面向对象编程 (OOP)

在本章中,我们将讨论一种称为 String 的引用类型。它由 java.lang.String 类表示,如您所见,它属于 JDK 最基础的包 java .lang。我们这么早引入 String 类的原因是它在某些方面的行为与原始类型非常相似,尽管它是一个引用类型。

之所以称为引用类型,是因为在代码中,我们不直接处理这种类型的值。引用类型的值比原始类型的值更复杂。它被称为对象并且需要更复杂的内存分配,因此引用类型的变量包含内存引用。它指向(引用)对象所在的内存区域,因此得名。

当引用类型变量作为参数传递给方法时,引用类型的这种性质需要特别注意。我们将在 第 3 章中更详细地讨论这个问题>Java 基础知识。现在,我们将了解作为引用类型的 String 如何通过只存储每个 String 值一次来帮助优化内存使用.

String literals

String 表示Java 程序中的字符串。我们已经看到了几个这样的字符串。例如,我们已经看到了 Hello, world!。那是一个 String 文字。

文字的另一个例子是 null。任何引用类都可以引用 null 文字。它表示一个不指向任何对象的引用值。对于 String 类型,它看起来像这样:

String s = null;

但是由双引号括起来的字符组成的文字("abc""123""a42%$#") 只能是 String 类型。在这方面,作为引用类型的 String 类与原始类型有一些共同点。所有 String 文字都存储在称为字符串池的专用内存部分中,两个文字拼写相同以表示池中的相同值(执行 com.packt.learnjava.ch01_start.StringClass 类的literal">main() 方法——参见compareReferences()< /代码>方法):

String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2);    //prints: true
System.out.println("abc" == s1); //prints: true

JVM 作者选择了这样的实现来避免重复并提高内存使用率。前面的代码示例看起来很像涉及原始类型的操作,不是吗?但是当使用 new 运算符创建 String 对象时,新对象的内存分配在字符串池之外,因此两个 String 对象或任何其他对象的引用总是不同的,正如我们在这里看到的:

String o1 = new String("abc");
String o2 = new String("abc");
System.out.println(o1 == o2);    //prints: false
System.out.println("abc" == o1); //prints: false

如有必要,可以使用 intern() 方法将使用 new 运算符创建的字符串值移动到字符串池中, 像这样:

String o1 = new String("abc");
System.out.println("abc" == o1);          //prints: false
System.out.println("abc" == o1.intern()); //prints: true

在前面的代码片段中,intern() 方法试图将新创建的 "abc" 值移动到字符串池中,但是发现那里已经存在这样的文字,因此它重用了字符串池中的文字。这就是为什么前面例子中最后一行的引用是相等的。

好消息是您可能不需要使用 new 运算符创建 String 对象,而且大多数 Java 程序员从不这样做.但是,当 String 对象作为输入传递到您的代码中并且您无法控制其来源时,仅通过引用比较可能会导致错误的结果(如果字符串具有相同的拼写但由 new 运算符创建)。这就是为什么当两个字符串通过拼写(和大小写)相等时,为了比较两个文字或 String 对象,equals( ) 方法是更好的选择,如下所示:

String o1 = new String("abc");
String o2 = new String("abc");
System.out.println(o1.equals(o2));       //prints: true
System.out.println(o2.equals(o1));       //prints: true
System.out.println(o1.equals("abc"));    //prints: true
System.out.println("abc".equals(o1));    //prints: true
System.out.println("abc".equals("abc")); //prints: true

稍后我们将讨论 equals() 方法和 String 类的其他方法。

另一个使 String 文字和对象看起来像原始值的特性是可以使用 + 算术运算符来添加它们,就像这样(执行 com.packt.learnjava.ch01_start.StringClass 类的 main() 方法——参见 operatorAdd() 方法):

String s1 = "abc";
String s2 = "abc";
String s = s1 + s2;
System.out.println(s);              //prints: abcabc
System.out.println(s1 + "abc");     //prints: abcabc
System.out.println("abc" + "abc");  //prints: abcabc
String o1 = new String("abc");
String o2 = new String("abc");
String o = o1 + o2;
System.out.println(o);              //prints: abcabc
System.out.println(o1 + "abc");     //prints: abcabc 

没有其他算术 运算符可以应用于 String 文字或对象。

Java 15 引入了一种新的 String 文字,称为文本块。它有助于保留缩进和多行,而无需在引号中添加空格。例如,以下是程序员如何在 Java 15 之前添加缩进并使用 \n 换行:

String html = "<html>\n" +
              "   <body>\n" +
              "       <p>Hello World.</p>\n" +
              "   </body>\n" +
              "</html>\n";

以下是使用 Java 15 实现相同结果的方式:

String html = """
               <html>
                   <body>
                       <p>Hello World.</p>
                   </body>
               </html>
              """;

要查看 的工作原理,请执行 com.packt 的 main() 方法。 learnjava.ch01_start.StringClass 类——参见 textBlock() 方法。

String immutability

由于所有 String 文字 都可以共享,JVM 作者确保一旦存储,一个 String 变量无法更改。这不仅有助于避免从代码的不同位置同时修改相同值的问题,而且还可以防止对 String 值进行未经授权的修改,该值通常表示用户名或密码。

以下代码看起来像 String 值修改:

String str = "abc";
str = str + "def";
System.out.println(str);       //prints: abcdef
str = str + new String("123");
System.out.println(str);       //prints: abcdef123

但是,在幕后,原始的 "abc" 文字保持不变。相反,创建了一些新的文字:"def""abcdef"" 123""abcdef123"。为了证明这一点,我们执行了以下代码:

String str1 = "abc";
String r1 = str1;
str1 = str1 + "def";
String r2 = str1;
System.out.println(r1 == r2);      //prints: false
System.out.println(r1.equals(r2)); //prints: false

可以看到,r1r2变量指的是不同的内存,它们指的是对象 的拼写也不同。

我们将在第 5 章中详细讨论字符串字符串、输入/输出和文件

IDs and variables

从我们上学的时候开始,我们就对变量是什么有了直观的理解。我们将其视为代表价值的名称。我们使用诸如 x 加仑水或 n 英里距离等变量来解决问题。在 Java 中,变量的名称称为 ID,可以通过一定的规则构造。使用 ID,可以声明(定义)和初始化变量。

ID

根据 Java 语言规范 (https://docs.oracle.com/javase/specs),一个ID(变量名)可以是一个Unicode字符序列,代表字母、数字0-9、一美元符号 ($) 或下划线 (_)。

此处概述了其他限制:

  • ID 的第一个符号不能是数字。
  • ID 的拼写不能与关键字相同(请参阅 Java 关键字 部分) 4" linkend="ch04lvl1sec24">第 3 章Java 基础知识)。
  • 它不能拼写为 truefalse 布尔文字或 null 字面意思。
  • 从 Java 9 开始,ID 不能只是一个下划线 (_)。

以下是一些不寻常但合法的 ID 示例:

$
_42
αρετη
String

Variable declaration (definition) and initialization

变量具有名称(ID)和类型。通常,它指的是存储值的内存,但可能什么都不指(null)或根本不指任何东西(然后,它没有被初始化)。它可以表示类属性、数组元素、方法参数和局部变量。最后一种是最常用的变量。

在使用变量之前,必须声明和初始化它。在其他一些编程语言中,也可以定义变量,所以Java程序员有时会使用definition这个词作为声明的同义词,这并不完全正确。

以下是带有示例的术语回顾:

int x;      //declaration of variable x
x = 1;      //initialization of variable x
x = 2;      //assignment of variable x

初始化和赋值看起来是一样的。不同之处在于它们的顺序:第一个分配称为初始化。如果没有初始化,就不能使用变量。

声明和初始化可以组合在一个语句中。例如,请注意以下事项:

float $ = 42.42f;
String _42 = "abc";
int αρετη = 42;
double String = 42.;

var type holder

在 Java 10 中,引入了类型持有者 var 的排序 Java 语言规范 是这样定义的:“var 不是关键字,而是具有特殊含义的标识符,作为局部变量声明的类型< /em>。”

实际上,它可以让编译器找出声明变量的性质,如下所示(参见 com.xml 中的 var() 方法。 packt.learnjava.ch01_start.PrimitiveTypes 类):

var x = 1;

在前面的示例中,编译器可以合理地假设 x 具有 int 原始类型。

正如您可能已经猜到的那样,要做到这一点,仅靠声明是不够的,正如我们在这里看到的:

var x;    //compilation error

也就是说,如果没有初始化,编译器在使用var时无法判断变量的类型。

Java statements

Java 语句是可以执行的 最小构造。它描述一个动作并以分号 (;) 结束。我们已经看到了很多说法。例如,下面是三个语句:

float f = 23.42f;
String sf = String.valueOf(f);
System.out.println(sf);

第一行是一个声明语句和一个赋值语句。第二行也是一个声明语句,结合了赋值语句和方法调用语句。第三行只是一个方法调用语句。

以下是 Java 语句类型的列表:

  • 只包含一个符号的空语句,;(分号)
  • 类或接口声明语句(我们将在 第 2 章Java 面向对象编程 (OOP)
  • 局部变量声明语句:int x;
  • 同步声明:这超出了本书的范围
  • 表达式语句
  • 控制流语句

表达式语句可以是以下之一:

  • 方法调用语句:someMethod();
  • 赋值语句:n = 23.42f;
  • 对象创建语句:new String("abc");
  • 一元递增或递减语句: ++x ;或--x;或 x++;或 x--;

我们将在 表达式语句 部分详细讨论表达式语句。

控制流语句可以是以下之一:

  • 选择语句:if-elseswitch-case
  • 一个迭代语句:for, or while, or do-while
  • 异常处理语句:throwtry-catchtry-catch-finally
  • 分支语句:breakcontinue返回

我们将在 控制流语句 部分详细讨论控制语句。

Expression statements

一个表达式 语句由一个或多个 表达式组成。一个表达式通常包括一个或多个运算符。它可以被评估,这意味着它可以产生以下类型之一的结果:

  • 一个变量:x = 1,例如
  • 一个值:2*2,例如

当表达式调用返回 void 的方法时,它什么也不返回。据说这种方法只会产生副作用:例如,void someMethod()

考虑以下表达式:

x = y++; 

前面的表达式为 x 变量赋值,并具有将 y 变量的值加 1 的副作用。

另一个例子是打印一行的方法,如下所示:

System.out.println(x); 

println() 方法不返回任何内容,并且具有打印某些内容的副作用。

根据其形式,表达式可以是以下之一:

  • 主要表达式:文字、新对象创建、字段或方法访问(调用)。
  • 一元运算符表达式:例如 x++
  • 二元运算符表达式:例如 x*y
  • 三元运算符表达式:x >是吗? true : false,例如。
  • 一个 lambda 表达式:x -> x + 1(参见第 14 章 Java 标准流)。
  • 如果一个表达式由其他表达式组成,括号通常用于清楚地识别每个表达式。这样,更容易理解和设置表达式的优先级。

Control flow statements

当一个 Java 程序被执行时,它是逐语句执行的。有些语句必须根据表达式求值的结果有条件地执行。此类语句称为控制流语句,因为在计算机科学中,控制流(或控制流)是执行或评估各个语句的顺序。

控制流语句可以是以下之一:

  • A 选择 语句:if-elseswitch-case
  • 迭代语句:forwhiledo-while
  • 异常处理语句:throwtry-catchtry-catch-finally
  • 分支语句:breakcontinuereturn

Selection statements

选择 语句基于表达式 评估并有四种变体,如下所述:

  • if (表达式) {做某事}
  • if (表达式) {do something} else {do something else}
  • if (表达式) {do something} else if {do something else} else {做其他事情}
  • switch...case 语句

以下是 if 语句的一些示例:

if(x > y){
    //do something
}
if(x > y){
    //do something
} else {
    //do something else
}
if(x > y){
    //do something
} else if (x == y){
    //do something else
} else {
    //do something different
}

switch...case 语句 class="literal">if...else 语句,如下所示:

switch(x){
    case 5:               //means: if(x = 5)
        //do something 
        break;
    case 7:             
        //do something else
        break;
    case 12:
        //do something different
        break;
    default:             
        //do something completely different
        //if x is not 5, 7, or 12
}

如您所见,switch...case 语句根据变量的值分叉执行流程。 break 语句允许执行 switch...case 语句。否则,将执行以下所有情况。

在 Java 14 中,引入了一个新的 switch...case 语句 以一种不太冗长的形式,如 在这里说明:

void switchStatement(int x){
    switch (x) {
        case 1, 3 -> System.out.print("1 or 3");
        case 4    -> System.out.print("4");
        case 5, 6 -> System.out.print("5 or 6");
        default   -> System.out.print("Not 1,3,4,5,6");
    }
    System.out.println(": " + x);
}

如您所见,它使用了一个箭头(->)并且没有使用 break 语句。

执行 com.packt.learnjava.ch01_start.ControlFlow 类的 main() 方法——参见 switchStatement()方法的literal">selection()方法,如下:

switchStatement(1);    //prints: 1 or 3: 1
switchStatement(2);    //prints: Not 1,3,4,5,6: 2
switchStatement(5);    //prints: 5 or 6: 5

您可以从评论中看到结果。

如果在每种情况下都必须执行几行代码,则只需将大括号 ({}) 放在代码块周围,如下所示:

switch (x) {
    case 1, 3 -> { 
                    //do something
                 }
    case 4    -> {
                    //do something else 
                 }
    case 5, 6 -> System.out.println("5 or 6");
    default   -> System.out.println("Not 1,3,4,5,6");
}

Java 14 switch...case 语句甚至可以返回一个值,因此实际上变成了一个 switch 表达式。例如,这是一个必须根据 switch...case 语句结果分配另一个变量的情况:

void switchExpression1(int i){
    boolean b = switch(i) {
        case 0, 1 -> false;
        case 2 -> true;
        default -> false;
    };
    System.out.println(b);
}

如果我们执行 switchExpression1() 方法(参见 com 的 selection() 方法.packt.learnjava.ch01_start.ControlFlow 类),结果将如下所示:

switchExpression1(0);    //prints: false
switchExpression1(1);    //prints: false
switchExpression1(2);    //prints: true

switch 表达式的以下示例基于一个常量:

static final String ONE = "one", TWO = "two", THREE = "three", 
                    FOUR = "four", FIVE = "five";
void switchExpression2(String number){
    var res = switch(number) {
        case ONE, TWO -> 1;
        case THREE, FOUR, FIVE -> 2;
        default -> 3;
    };
    System.out.println(res);
}

如果我们 执行 switchExpression2() 方法(参见 com.packt.learnjava.ch01_start.ControlFlow 类的 ="literal">selection() 方法),结果将如下所示:

switchExpression2(TWO);            //prints: 1
switchExpression2(FOUR);           //prints: 2
switchExpression2("blah");         //prints: 3

这是 switch 表达式的另一个示例,这一次基于 enum 值:

enum Num { ONE, TWO, THREE, FOUR, FIVE }
void switchExpression3(Num number){
    var res = switch(number) {
        case ONE, TWO -> 1;
        case THREE, FOUR, FIVE -> 2;
    };
    System.out.println(res);
}

如果我们执行 switchExpression3() 方法(参见 com 的 selection() 方法.packt.learnjava.ch01_start.ControlFlow 类),结果将如下所示:

switchExpression3(Num.TWO);        //prints: 1
switchExpression3(Num.FOUR);       //prints: 2
//switchExpression3("blah"); //does not compile

如果必须根据特定输入值执行代码块,则无法 使用 return 语句 因为它已经为方法的返回值保留。这就是为什么要从块中返回值,我们必须使用 yield 语句,如下例所示:

void switchExpression4(Num number){
    var res = switch(number) {
        case ONE, TWO -> 1;
        case THREE, FOUR, FIVE -> {
            String s = number.name();
            yield s.length();
        }
    };
    System.out.println(res);
}

如果我们执行 switchExpression4() 方法(参见 com 的 selection() 方法.packt.learnjava.ch01_start.ControlFlow 类),结果将如下所示:

switchExpression4(Num.TWO);        //prints: 1
switchExpression4(Num.THREE);      //prints: 5

Iteration statements

迭代 语句可以采用以下三种形式之一:

  • while 语句
  • do...while 语句
  • for 语句,也称为 loop 语句

while 语句如下所示:

while (boolean expression){
      //do something
}

这是一个具体的例子(执行 com.packt.learnjava.ch01_start.ControlFlow 类的 main() 方法——见iteration() 方法):

int n = 0;
while(n < 5){
 System.out.print(n + " "); //prints: 0 1 2 3 4 
 n++;
}

在某些示例中,我们使用 print() 方法代替 println() 方法,该方法不提供另一行(不在其输出末尾添加换行控件)。 print() 方法在一行中显示输出。

do...while 语句的形式非常相似,如下所示:

do {
    //do something
} while (boolean expression)

它与 while 语句的不同之处在于,它总是在计算表达式之前至少执行一次语句块,如下面的代码片段所示:

int n = 0;
do {
    System.out.print(n + " ");   //prints: 0 1 2 3 4
    n++;
} while(n < 5);

如您所见,当表达式在第一次迭代时为 true 时,它的行为方式相同。但如果 表达式的计算结果为 false,则 结果不同,因为我们可以在这里看到:

int n = 6;
while(n < 5){
    System.out.print(n + " ");   //prints nothing
    n++;
}
n = 6;
do {
    System.out.print(n + " ");   //prints: 6
    n++;
} while(n < 5);

for 语句语法如下所示:

for(init statements; boolean expression; update statements) {
 //do what has to be done here
}

以下是 for 语句的工作原理:

  1. init 语句初始化一个变量。
  2. 使用当前变量值计算布尔表达式:如果 true,则执行语句块;否则,for 语句退出。
  3. update 语句更新变量,布尔表达式再次用这个新值求值:如果 true,语句块是执行;否则,for 语句退出。
  4. 除非退出,否则重复最后一步。

你可以在这里看到,如果你不小心,你可能会陷入死循环:

for (int x = 0; x > -1; x++){
    System.out.print(x + " ");  //prints: 0 1 2 3 4 5 6 ...
}

因此,您必须确保布尔表达式保证最终退出循环,如下所示:

for (int x = 0; x < 3; x++){
    System.out.print(x + " ");  //prints: 0 1 2
}

以下示例演示了多个初始化和 update 语句:

for (int x = 0, y = 0; x < 3 && y < 3; ++x, ++y){
    System.out.println(x + " " + y);
}

下面是用于演示目的的语句的前面代码的变体:

for (int x = getInitialValue(), i = x == -2 ? x + 2 : 0, 
             j = 0; i < 3 || j < 3 ; ++i, j = i) {
 System.out.println(i + " " + j);
}

如果 getInitialValue() 方法的实现类似于 int getInitialValue(){ return -2; },那么前面的两个 for 语句会产生完全相同的结果。

要遍历值数组,可以使用数组索引,如下所示:

int[] arr = {24, 42, 0};
for (int i = 0; i < arr.length; i++){
    System.out.print(arr[i] + " ");  //prints: 24 42 0
}

或者,您可以使用 for 语句的更紧凑形式产生相同的结果,如下所示:

int[] arr = {24, 42, 0};
for (int a: arr){
    System.out.print(a + " ");  //prints: 24 42 0
}

最后一种形式对集合特别有用,如下所示:

List<String> list = List.of("24", "42", "0");
for (String s: list){
    System.out.print(s + " ");  //prints: 24 42 0
}

我们将在 第 6 章中讨论集合/a>,数据结构、泛型和流行实用程序

Exception-handling statements

在 Java 中,有 类称为异常,它们表示破坏正常执行流程的事件。它们的名称通常以 Exception 结尾:NullPointerExceptionClassCastException、< code class="literal">ArrayIndexOutOfBoundsException,仅举几例。

所有异常类都扩展了 java.lang.Exception 类,而后者又扩展了 java.lang.Throwable 类(我们将在 第 2 章中解释这意味着什么Java 面向对象编程 (OOP))。这就是为什么所有异常对象都有共同的行为。它们包含有关异常情况的原因及其起源位置(源代码的行号)的信息。

每个异常对象都可以由 JVM 或应用程序代码自动生成(抛出),使用 throw 关键字。如果代码块抛出异常,您可以使用 try-catchtry-catch-finally 构造来捕获抛出异常对象并将执行流程重定向到另一个代码分支。如果周围的代码没有捕捉到异常对象,它就会从应用程序一路传播到 JVM 并强制它退出(并中止应用程序执行)。因此,在所有可能出现异常的地方使用 try-catchtry-catch-finally 是一种很好的做法引发并且您不希望您的应用程序中止执行。

下面是一个典型的异常处理示例:

try {
    //x = someMethodReturningValue();
    if(x > 10){
        throw new RuntimeException("The x value is out
                                    of range: " + x);
    }
    //normal processing flow of x here
} catch (RuntimeException ex) {
    //do what has to be done to address the problem
}

在前面的代码片段中,x>的情况下不会执行正常的处理流程。 10 。相反,将执行 do what has to be done 块。但是,在 x <= 10 的情况下,将运行正常的处理流程块并且 做必须做的事情 块将被忽略。

有时,无论如何都需要执行一段代码,无论是否抛出/捕获了异常。您可以将它放在 finally 块中,而不是在两个地方重复相同的代码块,因为 如下(执行 com.packt.learnjava.ch01_start.ControlFlowmain() 方法类——参见 exception() 方法):

try {
    //x = someMethodReturningValue();
    if(x > 10){
        throw new RuntimeException("The x value is out 
                                    of range: " + x);
    }
    //normal processing flow of x here
} catch (RuntimeException ex) {
   System.out.println(ex.getMessage());   
   //prints: The x value is out of range: ...
   //do what has to be done to address the problem
} finally {
   //the code placed here is always executed
}

我们将在 第 4 章中更详细地讨论异常处理< /em>异常处理

Branching statements

分支 语句允许中断当前执行流程并从当前块之后的第一行或从某个(标记)控制流的点。

分支语句可以是以下之一:

  • 中断
  • 继续
  • 返回

我们已经看到 break 是如何在 switch-case 语句中使用的。这是另一个示例(执行 com.packt.learnjava.ch01_start.ControlFlow 类的 main() 方法 - 请参阅branching() 方法):

String found = null;
List<String> list = List.of("24", "42", "31", "2", "1");
for (String s: list){
    System.out.print(s + " ");         //prints: 24 42 31
    if(s.contains("3")){
        found = s;
        break;
    }
}
System.out.println("Found " + found);  //prints: Found 31

如果我们需要找到第一个包含 "3" 的列表元素,我们可以在 s.contains("3" ) 条件被评估为 true。剩余的列表元素被忽略。

在更复杂的场景中,使用嵌套的 for 语句,可以设置一个标签(使用 a : column)来指示其中 for 语句必须退出,如下:

String found = null;
List<List<String>> listOfLists = List.of(
        List.of("24", "16", "1", "2", "1"),
        List.of("43", "42", "31", "3", "3"),
        List.of("24", "22", "31", "2", "1")
);
exit: for(List<String> l: listOfLists){
    for (String s: l){
        System.out.print(s + " "); //prints: 24 16 1 2 1 43
        if(s.contains("3")){
            found = s;
            break exit;
        }
    }
}
System.out.println("Found " + found);  //prints: Found 43

我们选择了标签名称exit,但我们可以称之为任何其他名称。

continue 语句的工作方式类似,如下所示:

String found = null;
List<List<String>> listOfLists = List.of(
                List.of("24", "16", "1", "2", "1"),
                List.of("43", "42", "31", "3", "3"),
                List.of("24", "22", "31", "2", "1")
);
String checked = "";
cont: for(List<String> l: listOfLists){
        for (String s: l){
           System.out.print(s + " "); 
                  //prints: 24 16 1 2 1 43 24 22 31
           if(s.contains("3")){
               continue cont;
           }
           checked += s + " ";
        }
}
System.out.println("Found " + found);  //prints: Found 43
System.out.println("Checked " + checked);  
                            //prints: Checked 24 16 1 2 1 24 22

break的区别通过说明哪个for 语句需要继续而不是退出。

return 语句用于从方法返回结果,如下所示:

String returnDemo(int i){
    if(i < 10){
        return "Not enough";
    } else if (i == 10){
        return "Exactly right";
    } else {
        return "More than enough";
    }
}

如您所见,一个方法中可以有多个 return 语句,每个语句在不同的情况下返回不同的值。如果方法不返回任何内容(void),则 return 语句是 not必需的,虽然 它经常用于更好的可读性,如下:

void returnDemo(int i){
    if(i < 10){
        System.out.println("Not enough");
        return;
    } else if (i == 10){
        System.out.println("Exactly right");
        return;
    } else {
        System.out.println("More than enough");
        return;
    }
}

通过运行 com.packt 的 main() 方法执行 returnDemo() 方法.learnjava.ch01_start.ControlFlow 类(参见 branching() 方法)。结果将如下所示:

String r = returnDemo(3);
System.out.println(r);      //prints: Not enough
r = returnDemo(10);
System.out.println(r);      //prints: Exactly right 
r = returnDemo(12);
System.out.println(r);      //prints: More than enough

语句是 Java 编程的构建块。它们就像英语中的句子——完整​​的意图表达,可以采取行动。它们可以被编译和执行。编程就像在语句中表达一个行动计划。

至此,对Java基础的讲解到此结束。恭喜你顺利通过!

Summary

本章向您介绍了令人兴奋的 Java 编程世界。我们首先解释了主要术语,然后解释了如何安装必要的工具——JDK 和 IDE——以及如何配置和使用它们。

在开发环境到位后,我们为读者提供了 Java 作为编程语言的基础知识。我们已经描述了 Java 原始类型、String 类型以及它们的字面量。我们还定义了什么是 ID 和什么是变量,最后对 Java 语句的主要类型进行了描述。讨论的所有要点都通过特定的代码示例进行了说明。

在下一章中,我们将讨论 Java 的 面向对象 (OO) 方面。我们将介绍主要概念,解释什么是类,什么是接口,以及它们之间的关系。术语overloadingoverridinghiding也将被定义和演示在代码示例中,以及 final 关键字的使用。

Quiz

  1. JDK 代表什么?
    1. Java 文档 Kronos
    2. 6 月发展空手道
    3. Java 开发工具包
    4. Java 开发者工具包
  2. JCL 代表什么?
    1. Java 经典库
    2. Java 类库
    3. 少年古典自由
    4. Java 类库
  3. Java SE 代表什么?
    1. Java 高级版
    2. Java 明星版
    3. Java 结构性选举
    4. Java 标准版
  4. IDE 代表什么?
    1. 初始开发版
    2. 集成开发环境
    3. 国际发展版
    4. 集成开发版
  5. Maven的功能是什么?
    1. 项目建设
    2. 项目配置
    3. 项目文档
    4. 项目取消
  6. 以下哪些是 Java 原始类型?
    1. 布尔
    2. 数字
    3. 整数
    4. 字符串
  7. 以下哪些是 Java 数值类型?
    1. long
    2. 字节
  8. 什么是文字
    1. 基于字母的字符串
    2. 基于数字的字符串
    3. 变量表示
    4. 价值表示
  9. 以下哪些是字面意思?
    1. \\
    2. 2_0
    3. 2__0f
    4. \f
  10. 以下哪些是 Java 运算符?
    1. %
    2. $
    3. &
    4. ->
  11. 下面的代码片段打印了什么?
    int i = 0; System.out.println(i++);
    1. 0
    2. 1
    3. 2
    4. 3
  12. 下面的代码片段打印了什么?
    boolean b1 = true; 布尔 b2 = 假; System.out.println((b1 & b2) + " " + (b1 && b2));
    1. false true
    2. false false
    3. 真假
    4. 真真
  13. 下面的代码片段打印了什么?
    int x = 10; x %= 6; System.out.println(x);
    1. 1
    2. 2
    3. 3
    4. 4
  14. 以下代码片段的结果是什么?
    System.out.println("abc" - "bc");
    1. a
    2. abc-bc
    3. 编译错误
    4. 执行错误
  15. 下面的代码片段打印了什么?
    System.out.println("A".repeat(3).lastIndexOf("A"));
    1. 1
    2. 2
    3. 3
    4. 4
  16. 以下哪个是正确的 ID?
    1. int __(两个下划线)
    2. 2a
    3. a2
    4. $
  17. 下面的代码片段打印了什么?
    for (int i=20, j=-1; i < 23 && j < 0; ++i, + +j){          System.out.println(i + " " + j + " "); }
    1. 20 -1 21 0
    2. 无限循环
    3. 21 0
    4. 20 -1
  18. 下面的代码片段打印了什么?
    int x = 10; 尝试 {     if(x++ > 10){         throw new RuntimeException("x值超出范围:" + x);     }     System.out.println("x值在范围内:" + x); } 捕捉(运行时异常前){     System.out.println(ex.getMessage()); }
    1. 编译错误
    2. x 值超出范围:11
    3. x 值在以下范围内:11
    4. 执行时间错误
  19. 下面的代码片段打印了什么?
int result = 0;
List<List<Integer>> source = List.of(
        List.of(1, 2, 3, 4, 6),
        List.of(22, 23, 24, 25),
        List.of(32, 33)
);
cont: for(List<Integer> l: source){
    for (int i: l){
        if(i > 7){
            result = i;
            continue cont;
        }
     }
}
System.out.println("result=" + result);
  1. 结果 = 22
  2. 结果 = 23
  3. 结果 = 32
  4. result = 33
  1. 选择以下所有正确的陈述:
    1. 可以声明变量。
    2. 可以分配变量。
    3. 可以定义变量。
    4. 可以确定一个变量。
  2. 从以下选择所有正确的 Java 语句类型:
    1. 可执行语句
    2. 选择声明
    3. 方法结束语句
    4. 增量语句