Java-初学者的自动化测试实用指南-全-

Java 初学者的自动化测试实用指南(全)

原文:zh.annas-archive.org/md5/2fe4dbe3a91a5b3bffbf3ffa1b79bc31

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Java 是程序员和开发者最常用的软件语言之一。如果你来自非技术背景,并希望掌握 Java 以满足你的自动化需求?那么这本书就是为你准备的。

这本书是一本指南,描述了有效处理 Java 相关自动化/项目的有效技术。你将学习如何在 Java 中处理字符串及其功能。随着我们的进展,你将掌握类、对象及其用法。这本书将帮助你通过实际示例了解继承和异常的重要性。

在本书结束时,你将获得关于 Java 的全面知识,这将帮助你通过任何工作面试。

这本书面向的对象

这本书旨在为想要进入软件质量保证领域并使用测试框架进行自动化测试的软件开发者编写。本书假设读者有 Java 编程经验以编写测试。

要充分利用这本书

在本书的学习过程中,任何关于 Java 的先验知识都将有所帮助。

下载示例代码文件

你可以从www.packt.com的账户下载这本书的示例代码文件。如果你在其他地方购买了这本书,你可以访问www.packt.com/support并注册,以便将文件直接通过电子邮件发送给你。

你可以通过以下步骤下载代码文件:

  1. www.packt.com登录或注册。

  2. 选择“支持”选项卡。

  3. 点击“代码下载与勘误表”。

  4. 在搜索框中输入书名,并遵循屏幕上的说明。

文件下载完成后,请确保使用最新版本的以下软件解压缩或提取文件夹:

  • WinRAR/7-Zip for Windows

  • Zipeg/iZip/UnRarX for Mac

  • 7-Zip/PeaZip for Linux

本书代码包也托管在 GitHub 上,地址为github.com/PacktPublishing/Hands-On-Automation-Testing-with-Java-for-Beginners。如果代码有更新,它将在现有的 GitHub 仓库中更新。

我们还有其他来自我们丰富的图书和视频目录的代码包可供选择,地址为github.com/PacktPublishing/。查看它们吧!

使用的约定

在整本书中使用了多种文本约定。

CodeInText:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“要检查我们的机器上是否安装了 Java,请导航到C:\Program Files。”

代码块设置如下:

package coreJava;
public class finaldemo {
           public static void main(String[] args) {
               //TODO Auto-generated method stub

当我们希望引起你对代码块中特定部分的注意时,相关的行或项目将以粗体显示:

protected void abc() {
    //TODO Auto-generated method stub
  System.out.println("Hello");
}

任何命令行输入或输出都按照以下方式编写:

$ import package.classname

粗体:表示新术语、重要单词或屏幕上看到的单词。例如,菜单或对话框中的单词在文本中显示如下。以下是一个示例:“继续点击“下一步”,以便在机器中成功配置 Java。”

警告或重要注意事项看起来像这样。

小贴士和技巧看起来像这样。

联系我们

我们始终欢迎读者的反馈。

一般反馈:如果您对本书的任何方面有疑问,请在邮件主题中提及书名,并通过customercare@packtpub.com给我们发邮件。

勘误表:尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在这本书中发现了错误,如果您能向我们报告这一点,我们将不胜感激。请访问www.packt.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入详细信息。

盗版:如果您在互联网上发现我们作品的任何非法副本,如果您能提供位置地址或网站名称,我们将不胜感激。请通过copyright@packt.com与我们联系,并提供材料的链接。

如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为书籍做出贡献,请访问authors.packtpub.com

评论

请留下评论。一旦您阅读并使用了这本书,为何不在购买它的网站上留下评论呢?潜在读者可以查看并使用您的客观意见来做出购买决定,Packt 公司可以了解您对我们产品的看法,我们的作者也可以看到他们对书籍的反馈。谢谢!

如需了解 Packt 的更多信息,请访问packt.com

第一章:Java 编程的第一步

欢迎来到《Java 初学者实战自动化测试》。这是你在互联网上能找到的唯一一本教你成为强大的 Java 自动化测试者的所有主题的书。它包含了简单易懂的教学和简单技术,以有效地处理与 Java 相关的自动化/项目。考虑到我们将详细解释核心 Java 的每个主题,这将真正帮助我们开发和评估我们自己的 Java 自动化项目。

所有核心 Java 概念都是从零开始解释的。我们不假设读者有任何先验知识,因此我们认为所有读者都来自非编码背景,我们不仅教授每个主题,还通过我们将在实时中使用到的例子来支持他们。因此,我们不会只停留在理论上。

当你在市场上检查课程时,你应该尝试学习一个新概念。你只看到三条定义的线条后面跟着例子;这就是全部。但在这里,我们将了解为什么、何时以及在哪里在 Java 中使用面向对象编程系统OOPS)的概念。还将有适当的编程示例,展示在实时使用中的特定 OOPS 概念。这样,我们的书将通过实时项目进行驱动;这完全是关于实践学习。这将在我们开始 Java 集合时发挥作用,例如核心 Java,这是本书的主要概念之一,因为绝对需要你开始基础知识并开发你工作场所的自动化框架。此外,由于 Java 集合是核心部分之一,在整个书中,我们将非常注意为我们将讨论的每个 Java 集合提供所有必要的实际场景。

我们将处理棘手的 Java 程序,查看打印输出、素数、斐波那契数列和金字塔。我们将按降序排序打印,查看数组矩阵,并打印最大列数。这本书将为你提供在接近和设计这些程序逻辑时所需的具体策略和技巧。这将帮助你超越界限,获得编写困难 Java 程序所需的逻辑。

本书讨论的程序来源于许多公司在面试中经常问到的问题。你将获得这些问题,包括详细的解决方案和接近该逻辑的方法。因此,这本书主要关注核心 Java。我们不涉及 Swing 和按钮,这些内容超出了本书中 Java 学习的范围。

在这本书中,我们将学习核心 Java、集合以及其他概念,如循环、类和数组。这些已经足够你开始并开发 Java 项目。无论你处于哪个领域,从这本书中获得的知识将帮助你立即开始自动化项目的测试。

本章将涵盖以下概念:

  • Java 及其安装简介

  • 使用 Java 编辑器工具

  • 编写您的第一个可执行 Java 程序

Java 及其安装简介

当我们谈论 Java 时,首先想到的是它是平台无关的。这个特性使得 Java 成为市场上的热门编程工具。那么,平台无关性究竟意味着什么呢?

我们编写的代码与环境无关;无论是 Windows、Unix、Linux 还是 Solaris。基本上,当我们编写一个 Java 程序时,Java 编译器将程序转换为字节码。当我们运行 Java 代码时,Java 编译器将整个编程代码转换为字节码。例如,我们正在 Windows 机器上工作。当我们运行程序并且 Java 编译器运行并为我们创建字节码时,这个字节码可以在任何其他平台上执行,例如 Linux、macOS 和 Unix。这意味着我们在 Windows 上开发字节码,而这个字节码可以在任何其他平台上运行。所以这就是我们所说的平台无关性。

这是我们 Java 编程中的一项真正酷炫的特性。每次你要求某人下载 Java 时,你首先会被问到的第一个问题是,它是 JDK 还是 JRE?人们往往会在这两个术语之间感到困惑。在我们开始在我们的机器上下载和配置 Java 之前,我们需要对此有清晰的认识。让我们来看看这两个:

  • JRE 代表 Java 运行时环境:它负责运行我们的 Java 程序。如果我们的目标是仅仅运行一个纯 Java 核心代码,那么 JRE 就足够了。

  • JDK 代表 Java 开发工具包:它用于调试我们的 Java 代码,或者如果我们想拥有 Java 文档或其他类似的东西。

JDK 包含 JRE、Java 文档、调试工具和其他酷炫的东西。这是一个完整的 Java 套件,我们将从中获取所有组件。所以,我们下载什么取决于我们,但我建议我们只下载 JDK 以确保安全。如果我们只想练习和运行我们的程序,JRE 也足够了,但让我们坚持使用 JDK。

因此,现在让我们回到互联网上下载 Java,并尝试在我们的机器上配置它。要下载 Java,导航到以下页面:java.com/en/download/。当你点击免费 Java 下载按钮时,如图所示,将下载 JRE 版本:

但我们打算在我们的程序中使用 JDK,因此导航到以下网站:www.oracle.com/technetwork/java/javase/downloads/index.html。在这里,有多个 JDK 版本。目前市场上最新的版本是 Java SE 10.0.2。点击下载,如图所示,以便将所有组件下载并配置到我们的机器上:

这需要一些时间,因为配置它需要相当多的步骤。继续点击“下一步”,以便在机器上成功配置 Java。要检查 Java 是否已安装在我们的机器上,导航到C:\Program Files。如果我们那里找到一个名为Java的文件夹,这意味着 Java 已成功安装在我们的机器上。Java文件夹如下面的截图所示:

图片

这里需要记住的一个重要点是,如果我们处于 64 位系统,那么我们才会看到“程序文件”中的这个Java文件夹。如果我们的机器是 32 位,那么我们需要回到程序文件(x86)以获取Java文件夹。

我们可以通过前往控制面板并点击“系统”来检查我们的系统类型。我正在工作的系统是 64 位,如下面的截图所示:

图片

下载成功后,我们进入Java文件夹,并观察到 JDK 和 JRE 都已下载。我们进入 JDK 文件夹并复制整个文件路径。我们这样做是因为我们需要设置环境变量。设置环境变量意味着我们正在让系统知道 Java 文件夹的位置。

在我们的案例中,Java 文件夹位于C:/Program Files/Java/JDK,但 Windows 不知道它确切的位置。因此,为了使我们的系统知道 JDK 的主目录路径,我们将它放置在我们的系统变量中。这将帮助我们的机器知道 Java 文件夹的位置,这样每次我们运行程序时,它都会识别确切的 JDK 版本并运行我们的程序。为了在系统环境变量中更新此信息,我们复制整个 JDK 路径。前往控制面板,选择“系统和安全”,选择“系统”,然后点击“高级系统设置”。在高级系统设置中,选择“环境变量”。当我们点击“环境变量”时,会出现以下窗口:

图片

当我们在“拉胡尔的用户变量”部分点击“新建”时,我们会得到一个提示,要求添加一个新的用户变量。我们将名称设置为JAVA_HOME,将 JDK 路径粘贴到变量值文本框中,然后点击“确定”,如下面的截图所示:

图片

这就是我们的系统如何知道Java文件夹的确切位置。我们还需要更新另一个变量。为此,我们回到 JDK 文件夹并进入bin文件夹。我们会看到多个.exe文件,如下面的截图所示:

图片

我们复制bin文件夹的位置路径,然后返回到我们的系统属性窗口。在系统变量中,我们会看到一个名为Path的变量。双击它将显示一个提示,要求编辑系统变量,如下面的截图所示:

图片

在变量值中,我们走到末尾,添加一个分号,然后粘贴bin文件夹的路径。这意味着我们正在将Path变量设置为bin文件夹。我们还需要在开始使用 Java 之前设置这两个变量。一旦我们设置了这两个变量并点击确定,我们就成功设置了环境变量。

如果我们想要交叉检查环境变量是否配置正确,我们使用命令提示符。在命令提示符中,我们输入java -version并按Enter。如果我们得到以下截图所示的输出,这意味着 Java 已经成功配置到我们的系统上:

图片

如果我们在添加变量之前运行命令,我们会看到 Java 没有被识别。只有设置好系统环境变量后,我们才能成功配置 Java。

之前的说明负责从我们这边安装和配置系统。接下来,我们将尝试下载 Eclipse,这是一个 Java 编辑器工具,我们在这里编写、运行和调试我们的代码。在下载 Eclipse 之前,我们必须确保 Java 在我们的机器上配置正确。如果安装或配置步骤中有任何错误,Eclipse 将无法正确安装。

使用 Java 编辑器工具

在这里,我们将查看我们将使用来编写 Java 代码的编辑器工具。市场上有很多工具可以作为新的 Java 编辑器,但我个人更喜欢使用 Eclipse。它带有许多内置功能和语法添加。随着我们的进展,我们将看到 Eclipse 的其他优点。其中一些优点不能从理论上讨论,所以一旦我们开始实际编码,我们就会理解它是如何提示我们编写正确语法的。因此,在整个书籍过程中,我们将使用 Eclipse IDE 编辑器编写所有的 Java 代码。

首先,我们下载 Eclipse IDE 编辑器,看看它提供的界面。以下链接将带我们到 Eclipse 的官方网站:www.eclipse.org/downloads/。网站看起来就像以下截图所示:

图片

当我们点击“下载 64 位”按钮下的“下载包”时,它会带我们到以下页面:

图片

我们将使用 Eclipse IDE for Java EE Developers。我们可以根据我们正在工作的系统选择 32 位或 64 位。我们已经知道如何通过访问控制面板并遵循安装阶段的说明来检查我们的系统是 32 位还是 64 位。

我们需要确保的一个重要事项是,我们的 Java 版本与我们要下载的 IDE 兼容。如果我们的系统是 32 位的,而我们下载了 64 位的 Java,那么 Eclipse 将无法打开。所以请确保我们的系统、Java 和 Eclipse 版本都在同一条线上。

文件将以 ZIP 文件夹的形式下载,我们可以将其解压。以下屏幕截图显示了eclipse文件夹中将会出现的文件夹:

图片

如果我们双击eclipse.exe文件,Eclipse 用户界面将打开。

如果我们要编写 Java 代码,我们需要创建一个 Java 项目。在左侧的空白窗格上右键点击,然后点击“新建”|“项目”。这在上面的屏幕截图中显示:

图片

我们会收到一个提示,告诉 Eclipse 我们正在做什么类型的项目,如下面的屏幕截图所示:

图片

如我们所见,有很多不同的框架可供选择,例如 Java 项目、C/C++和 Android,但我们只对 Java 项目感兴趣,所以我们选择 Java 项目,然后点击“下一步”。我们将得到一个“新建 Java 项目”窗口,我们将在这里填写我们新项目所需的所有信息,如以下屏幕截图所示:

图片

我们为将要创建的 Java 项目选择一个项目名称。我们将第一个项目命名为coreJavaTraining。点击“下一步”,然后点击“完成”。系统会提示我们是否要打开关联的视角?选择“否”:

图片

这样就可以成功创建coreJavaTraining项目了。在项目内部,有一个自动创建的源文件夹。这意味着我们需要在这个源文件夹内编写我们的类。这些类究竟是什么呢?基本上,所有的 Java 代码都是在一个类内部编写的。当我们用记事本编写 Java 时,我们打开记事本,编写 Java 代码,并将该记事本文件保存为.java扩展名。但在 Eclipse 中,所有这些工作都是由这个工具本身完成的。所以我们需要做的就是创建一个类,这将给我们一个合适的模板。我们右键点击源文件(src),然后点击“新建”|“类”。我们将得到一个 Java 类提示,我们将在这里输入类名。我们将这个类命名为Firstclass,并确保选中“public static void main (String[] args)”复选框;我们稍后会讨论这个选项的重要性。最后,我们点击“完成”。这在上面的屏幕截图中显示:

图片

我们可以看到,内置的层次结构已经为我们创建好了,因为 Eclipse 创建了一个外部模板。在编辑器中我们可以看到,有一个类和 public static void main。所有这些都是由 Eclipse 工具创建的。如果我们不使用任何工具在记事本中正常编写,我们需要创建模板。但在 Eclipse 中,我们只需要给出类名。我们将输入的代码将被封装在类中;也就是说,在类的括号内。我们创建文件时使用的任何名称都将作为类名。

所有代码的执行都将放置在 public static void main 中,因为每次我们运行此文件时,Java 控制将直接进入此块。它不会触及 public static void main 外部编写的任何代码。简而言之,我们在 public static void main 块外编写代码,但最终我们需要在块内调用该代码。这是因为只有 main 块负责执行我们的 Java 代码。这就是为什么我们写 public static void main。随着我们在本书中的进一步学习,我们将了解 publicvoid 关键字,因为现在过早地深入了解这些内容。我们可以在以下截图中看到模板:

图片

由 Eclipse 工具创建的类

编写您的第一个可执行 Java 程序

让我们从本节的基本编码开始。如果我们想在输出中打印某些内容,Java 中有一个名为 System.out.println() 的命令。此命令将在控制台打印输出。假设我们想打印 hello world,当我们运行以下代码时,hello world 将在我们的输出控制台中打印出来:

Firstclass.java

因此,让我们运行代码。有两种方法可以运行代码:

  • 右键单击项目资源管理器中的文件名,点击“运行方式”,然后选择“Java 应用程序”。

  • 或者,我们可以点击工具栏中的运行图标,然后在“保存并启动”窗口中点击“确定”。图标看起来像这样:

图片

这将运行我们的代码并打印我们的输出。以下截图显示了编辑器中的 hello world 消息:

图片

根据代码显示的输出“hello world”

简而言之,System.out.println() 用于在我们的控制台打印。我们将在几乎所有示例中使用这个命令来演示实际例子。如果我们从语句中移除 ln,则输出不会在新的一行打印。

让我们尝试打印一个语句,该语句将在同一行上显示两个打印命令的输出。在这里,我们在 hello world 语句之前添加一个 System.out.println("hi") 语句。如果我们运行代码,输出将如下所示:

图片

输出显示在两行上

观察到hi在一行上显示,然后hello world在下一行显示。在这里,ln将输出显示在下一行。如果我们从两个语句中删除ln并运行代码,消息将显示如下:

截图

输出显示在同一行

我们看到hihello world在同一行打印。

如果我们编写代码,然后我们想部分检查输出,我们不需要删除代码行;我们只需要简单地注释掉它。我们可以通过在开头放置双斜杠(//)来注释掉它,这样 Java 就不会选择该行。这如下面的截图所示:

截图

使用双斜杠进行注释

如果我们删除斜杠,并且语句只是一些随机单词,那么它将抛出错误。我们将看到一个带有交叉标记的红线下的代码。这意味着该行有错误。这如下面的截图所示:

截图

错误会在行号旁边用交叉标记标记

再次添加反斜杠以注释掉错误。

记住,在这里我们只在main块中编写我们的实际代码。如果我们想打印一个整数呢?

假设我们想打印数字4。要打印它,我们首先需要将其存储在变量中,然后我们将打印变量。所以当我们打印变量时,将自动打印表示该变量的值。对于这个例子,我们选择数字4,并将其赋值给名为a的变量。问题在于a不知道被分配了什么数据类型。因此,我们必须明确指出a是整数。如果我们没有指出a是整数,它将抛出错误。

简而言之,我们首先创建一个名为a的变量,它只作为整数使用,然后将整数值4放入其中。以下截图展示了我们正在讨论的例子:

截图

将值 4 赋给变量 a

因此,使用这种类型的代码,我们可以在外部输入,但如果我们想打印它,我们将在主块中输入。在这个例子中,我们想打印变量a的值,所以我们添加另一个System.out.println(a)语句。编辑器会在打印语句中的变量a上抛出错误。要了解错误是什么,我们将鼠标悬停在错误上,会显示一个弹出窗口,显示错误及其可能的修复方法,如下面的截图所示:

截图

当鼠标悬停在其上时,会显示错误详情

错误详情中会有一个可点击的选项。这将自动通过添加所需内容来解决错误。这是编辑器的一个非常棒的功能,它在处理更复杂的例子时非常有帮助。

在我们的示例中,当我们点击错误详情弹出窗口中的将 'a' 改为 'static'时,static被添加到变量a中,我们能够运行代码。运行代码后,控制台将看起来像这样:

图片

按照代码显示的 a 的值

我们将在后面的章节中详细探讨static究竟是什么。

概述

在本章中,我们对 Java 进行了简要介绍。然后,我们安装并配置了与 Java 一起工作的各种工具。继续前进,我们查看了我们将要用来编写自己的 Java 代码的编辑器。

最后,我们执行了第一个示例,看到了编辑器是如何工作的,以及它是如何处理错误的。

在下一章中,我们将学习一些基本概念,例如字符串、变量和方法,以及它们之间是如何不同的,我们将通过代码来了解。

第二章:理解 Java 中的类、对象及其用法

在上一章中,我们简要介绍了 Java 以及我们将要输入代码的编辑器的安装方法。我们还编写并执行了在编辑器上的第一个代码。

在本章中,我们将深入探讨一些基本概念,例如字符串和变量,以及它们之间的不同。我们还将了解方法是什么,以及它们如何与不同的代码一起使用。我们将讨论对象在我们的代码中的重要性以及如何实现它们。

在本章中,我们将涵盖以下主题:

  • 字符串和变量的区别

  • 使用方法

  • Java 中类和对象的重要性

字符串和变量的区别

在第一章,“Java 中的第一步编程”,我们打印了一个字符串和变量。如果我们仔细观察,当我们打印一个变量时,我们并没有使用双引号,但是当我们打印一个字符串时,我们使用了它们。这是因为值已经存在于变量中,所以我们不需要使用任何双引号。如果我们使用它们,Java 会将其视为字符串,并且输出将像以下示例中的字母a一样打印。如果我们运行这个程序并观察输出,字母a将按以下截图所示打印:

输出显示根据代码的 a 的值

如果我们不使用双引号,Java 将检查是否有任何变量被定义为这个字母。如果有,它将打印该变量中的值。如果没有定义任何变量,那么它将给出一个错误。如果我们注释掉变量声明,我们会看到一个错误。将鼠标悬停在变量上,我们会得到一个提示说创建一个局部变量a,或者我们可以通过添加双引号来使用它:

提供代码错误纠正建议的快速修复下拉菜单

简而言之,如果我们简单地使用双引号,变量将被视为字符串,但如果我们不使用双引号,我们必须在某个地方声明变量。这就是打印字符串和打印变量之间的区别。

使用方法

基本上,方法是我们 Java 类中的代码块。让我们在这里写一个代码块作为例子,并观察开闭括号放置的位置。以下示例显示了一个完整的代码块:

public void getData()
{
    static int a=4;
}

在这段代码中,我们给代码块命名为getData(),而void是这个方法的返回类型。

如果我们期望从方法返回一个数字,并且这个数字是一个整数,那么我们必须在void的位置写上integer。同样的规则也适用于字符串;如果我们计划从getData()方法返回一个字符串,那么我们必须将其声明为string。如果我们不返回任何内容,也就是说,如果我们只是写了几行代码,那么我们将其保留为void

看看以下截图:

对于getData(),返回类型被指定为void

在这里,我们没有返回任何内容,所以我们将其保持为void

让我们在System.out.println(" I am in method");下面添加一行return 2;。在这里,我们返回的是一个整数。这就是为什么我们会在这里收到错误。如果我们将鼠标悬停在return 2;上显示的错误上,你会看到一个建议,将方法返回类型更改为'int':

快速修复下拉菜单会显示建议以纠正代码错误

点击建议后,我们的 IDE 会自动将返回类型修改为整数,错误消失。字符串数据类型的情况也是如此。

我们将在第十章“关键字 final 的重要性、包和修饰符”中讨论public访问修饰符。由于 Java 中有不同的访问修饰符,如publicprivateprotecteddefault,所以有很多要讨论的内容。我们将通过适当的示例查看每个访问修饰符,以便详细解释。现在,我们只需将所有访问修饰符视为public

现在你可能想知道为什么这些方法存在于 Java 中。它们有什么用?

假设我们正在执行一段 10 行的代码块,例如,在页面上添加两个整数。现在每次我们到达需要添加两个整数的页面时,我们必须再次编写这 10 行代码。也许复制这 10 行代码对于单个实例来说可能无关紧要,但如果在整个项目中需要这个代码块 10 次呢?所以 10 页和 10 行代码在单个 Java 程序中就变成了 100 行代码,这是我们在复制。为了避免这种情况,我们将所有 10 行代码写入一个代码块中,例如命名为getData或其他任何名称。此后,每次我们需要输入这 10 行代码时,我们只需简单地调用getData方法。所有 10 行代码都会落入这个特定的代码块中,并会被执行。在这种情况下,我们避免了 10 次编写代码;我们只在方法中编写一次,并在需要时调用该方法。

让我们用一个例子来解释这一点:

package coreJavaTraining;

public class Firstclass {

    public void getData()
    {
        System.out.println(" I am in method")
    }
    public static void main(String[] args) {
        System.out.println(a);
        System.out.println("hi");
        System.out.println("hello world");
    }
}

在前面的类中,我们将“我在方法中”视为我们之前提到的 10 行代码。我们想要调用这个方法,但在这里getData()块在main方法块之外,这意味着代码无法执行。要执行它,我们必须将其移动到main方法块内部。在大多数情况下,人们只是将代码复制到main方法块中,然后收到错误,因为不允许在main方法块中存在方法。方法应该写在main方法块之外,但类内部。如果我们把东西写在类外部,那就没有意义,因为 Java 不会捕获它。但是,如果我们把方法写在main方法块之外,我们如何将其放入main方法块中呢?为此,我们需要为定义方法的类创建一个对象。在这里,我们的方法是在Firstclass类中定义的,所以我们为这个类创建一个对象,然后我们可以通过这个对象访问类中存在的方法和变量。

在下一节中,我们将了解对象是什么,在哪里使用它们,以及如何使用对象调用方法和变量。

Java 中类和对象的重要性

对象是类的实例或引用。因此,我们可以通过它们的对象来调用类中存在的方法和变量。我们不能直接调用方法和对象,我们只能通过它们的对象来使用它们。因此,首先,我们需要为类创建对象,然后我们才能在main类中调用方法。

让我们看看前面的例子来解释这一点:

package coreJavaTraining;

public class Firstclass {

    public void getData()
    {
        System.out.println(" I am in method");
    }
    public static void main(String[] args) 
    {
        System.out.println("hi");
        System.out.println("hello world");
    }
}

既然main方法块已经在类中,为什么我们还需要为这个类创建一个对象并调用它呢?

答案是,除非我们创建一个对象来调用方法,否则main方法块将无法知道其外部的方法。有一个例外,那就是static变量,表示该方法为静态。因此,通常情况下,只有通过对象才能访问其他方法。

在 Java 中创建对象

首先,我们需要在类中为对象分配一些内存。内存可以通过在类名后跟new操作符来分配。然后我们为它定义一个对象名称。返回类型始终应该是类名。这是为类创建内存分配的语法。因此,前一个示例的内存分配代码将类似于以下内容:

Firstclass fn=new Firstclass();

在这里,我们说fnFirstclass类的对象。现在我们已经创建了一个对象,让我们看看我们如何访问它。

在 Java 中访问对象

要访问类的成员方法,我们写入对象名称,然后 . (点)。所有符合该类的成员方法都会在下拉列表中显示——这是 Eclipse 的另一个优秀特性。我们只需在下拉列表中查找方法,而不是通过代码搜索它。

在示例中,我们使用的是getData()方法。其余显示的方法都是 Java 的内置方法。观察方法是如何显示的:

图片

下拉菜单显示编辑器可用的所有类方法

在点击getData()时,getData()块将被转移到调用对象所在的行,当我们运行程序时,代码将作为main块的一部分执行。访问代码最终将如下所示:

fn.getData();

让我们看看这个示例的最终代码将是什么样子:

package coreJavaTraining;

public class Firstclass {

    public void getData()
    {
        System.out.println(" I am in method")
    }
    public static void main(String[] args) 
    {
        Firstclass fn=new Firstclass();
        fn.getData();
        System.out.println("hi");
        System.out.println("hello world");
    }
}

因此,如果我们运行示例中给出的类,我们的结果将如下所示:

图片

根据代码显示的“I am in method”

输出中我们看到的是I am in method;这是因为控制从内存分配行开始,创建一个对象,然后使用该对象调用该类的的方法。控制返回到getData()块并完成该特定块中存在的代码行;它执行打印语句,我们看到它被打印出来。这就是为什么对象在调用方法时是强大的。

同样的技术也可以用于调用整数。假设我们在a类中声明一个变量并给它赋值。我们可以在main方法中添加以下行来打印变量的值:

System.out.println(fn.a);

这是在 Java 中使用类、对象和方法的一种方式;基本上我们是在封装。

在不同类中访问方法

假设我们面临一个情况,我们正在处理一个类,我们需要访问另一个类中的对象;在 Java 中可以这样做。让我们用一个例子来帮助解释这一点。让我们使用两个类,Firstclass()(来自Java 中访问对象部分),然后我们创建一个新的类,称为secondclass()。在创建新类时,编辑器会创建默认代码,我们可以在其中添加代码。我们添加一个随机方法,public void setData(),在其中我们打印I am in second class method语句。

现在,我们想在Firstclass()类中实现setData()方法。基本上我们想在Firstclass()中执行setData()方法。并且只能通过该特定类的对象来调用方法。为此,我们在调用另一个类中方法的方法中创建一个对象。我们使用与上一个示例中相同的代码来为对象分配内存。以下代码被添加到Firstclass()main方法中:

secondclass sn= new secondclass();
sn.setData();

main类中编写代码时,当我们输入sn.来调用方法时,我们又将得到 Java 中所有方法的选项。由于我们想调用setData(),我们从与我们共享的多个选项中选择它。这将通过为该类创建一个对象,成功地将setData()带入Firstclass()main方法中。

如果我们运行代码,我们将得到以下输出:

图片

输出显示“根据代码,我在第二个类方法中”

摘要

我们首先讨论了字符串和变量之间的区别,以及它们在代码中的表现形式。然后,我们了解了方法是什么,以及如何使用它们来编写我们的代码。接着,我们讨论了类和对象的重要性,以及它们是如何被用来调用执行类的方法的。我们学习了如何为对象分配内存,并在执行代码时调用该对象的方法。最后,我们学习了如何通过对象访问另一个类中存在的方法。

在下一章中,我们将学习更多关于字符串的知识,并查看String类。

第三章:在 Java 中处理字符串及其功能

在本章中,我们将讨论字符串,并查看String类。我们还将学习如何定义字符串,并查看我们可以用哪些不同的方式定义字符串。然后,我们将讨论String类中的不同方法。最后,我们将编写一些简单的代码来反转字符串的内容,并检查反转后的字符串是否是回文。

在本章中,我们将涵盖以下主题:

  • 字符串介绍

  • String 类及其方法

  • 反转字符串的逻辑

字符串介绍

字符串是 Java 编程中最重要的概念之一。String是 Java 中预定义的类之一。因此,如果你想操作字符串,那么你可以简单地创建这个String类的一个对象,然后通过这个对象,你可以按照你的意愿操作字符串。你可以根据substring概念将字符串分成两部分。我们还可以连接两个字符串。所有这些都可以通过这个String类来完成。

让我们尝试自己操作一个字符串。创建一个新的 Java 类,并将其命名为stringclassdemo

在几乎所有与 Java 相关的面试中,最常见的问题之一是程序员如何定义字符串。答案是你可以使用以下两种方式中的任何一种:

  • 通过定义字符串字面量

  • 通过创建 String 对象

现在,让我们逐个查看每种方法,以便了解声明字符串的不同方式。

定义字符串字面量

定义字符串字面量可以简单地这样做:

        String a= "hello";

我们创建了一个名为hello的字符串,并将其存储在名为a的变量中。这就是我们定义String的方式,与定义字符串字面量相同。

假设你定义了另一个字符串,如下所示:

        String a= "hello";
        String b= "hello";

不幸的是,即使b变量也有一个hello字符串,a变量也定义了相同的字符串。当 Java 程序编译这个时,它创建了一个名为aString对象,并赋值为hello

现在,在为这个hello字符串创建对象之前,b变量首先检查String池中是否已经定义了任何hello字符串实例。如果已经定义,它将简单地让a变量引用b对象,而不是单独创建另一个对象。

创建 String 类的对象

我们在以下代码行中创建了一个String类的对象:

        String ab=new String();

现在,要创建一个hello字符串,你可以简单地传递一个参数给String类,如下所示:

        String ab=new String("hello");

ab对象现在可以对这个hello字符串执行所有的字符串操作。

让我们再创建一个名为b的字符串,它也等于hello,如下所示:

        String a=new String("hello");
        String b=new String("hello");

然而,这里已经使用a对象创建了一个hello字符串,当 Java 编译器到达b对象时,它还会创建一个额外的重复的hello字符串并将其分配给b,因为在这里我们明确地强制它为这个类创建一个对象。尽管已经存在一个重复的对象,但它仍然会为这个字符串创建一个对象;然而,在定义一个String字面量时,如果对象已经在String池中存在,它将不会创建它——相反,它直接引用已经创建的对象。

所以,这是使用String字面量对象创建字符串和单独使用String类创建对象之间的基本区别。最终,两者都支持String方法,但在定义字符串时,两种方法之间有一些区别。

我们刚刚学到的这两种方法有什么区别?这两个字符串都可以访问hello字符串,但你可以看到它们之间有一些区别。如果你在后台以字面形式声明字符串,那么 Java 会将hello分配给a变量。所以这是一种更直接创建字符串的方法,而不是使用对象创建方法。

在我们大多数常规 Java 工作经验中,我们更愿意使用String字面量。我们只需声明a等于hello,然后就这样。这就像你定义整数一样。但String是一个类,在后台,它为这个hello字符串创建一个单独的对象,而整数只是一个引用数据类型,所以后台不会发生任何事情。

让我们看看我们可以用我们创建的对象对这个hello字符串进行哪些操作。

String类及其方法

我们有a变量,这个变量也充当一个对象。当我们输入a.到编辑器中,它会显示在该String类中存在的所有方法,如下面的截图所示:

图片

它将字符串中的第一个字符读取为索引零,第二个字符为索引一,依此类推。当你在程序上工作时,如果你想获取索引二上的字符,你可以简单地使用以下语句:

        Systme.out.println(a.charAt(2));

你将其打印到输出中,这样你就能看到那个字符。你可能想知道为什么我们需要从字符串中获取单个字符,但charAt方法经常被使用。在下一节中,我们将查看一个可以完全反转字符串的程序。

现在,我们只简要地概述一下这些方法。我们看到了如何获取特定索引位置上存在的字符。现在让我们尝试反转这个字符串。假设我们有存在的字符,我们需要找到该字符在字符串中存在的索引值。我们通过使用以下所示的indexOf方法来完成这个操作:

        Systme.out.println(a.indexOf"e"));

运行这个程序。你可以看到字符 l2H0e 在索引 1l 在索引 2。这就是如何借助 String 方法提取字符和索引。

但是,如果我只想从第一个字符开始提取到第三个字符的字符串呢?让我们看看下面的例子:

        String a= "javatraining";
        a.substring(3, 6);

我们输入 a.,你可以看到有一个 子字符串。如果你想提取从索引 3 开始到索引 6 结束的字符串,这意味着 j 将在 0a1,以此类推。它从 2 开始,然后移动到 345,并打印出类似 vatra 的内容。

如果你想要从整个字符串中提取 子字符串,那么给出第一个字母的索引和最后一个字母的索引,这样我们的整个字符串就会在第一个和最后一个字母之间打印出来。记住,还有一个 substring 方法,使用这个方法,如果你不传递最后一个索引,只传递第一个索引,那么它将从索引 5 打印到字符串的最后一个索引,如下所示:

        a.substring(5);

让我们打印输出并看看 substring 是如何提取的。这些结果如下面的截图所示:

截图

在这里,e 的索引是 -1,因为在这个字符串中没有名为 e 的字母字符。每当没有内容时,它就会打印 -1

这样就总结了 substring。如果我想将这个字符串与另一个名为 rahul teaches 的字符串连接起来,那么我这样做:

        String a= "javatraining";
        System.out.priontln(a.concat("rahul teaches"));

存在于 a 变量中的 javatraining 字符串将与 rahul teaches 连接,并打印出 javatrainingrahul teaches 的输出。我们也可以使用 a.length(),这将给出从零开始的字符串的最大长度。还有一个叫做 trim 的类型。假设你的字符串中有一些空白字符,如下所示:

        String a= " javatraining";
        System.out.println(a.trim());

在这里,字符串的第一个字符是一个空格,然后是其余的字符。如果你想删除这个空格,你可以简单地使用 a.trim。当你打印输出时,这个空格就会被删除。

如果你想将所有字母打印为大写,我们可以使用 a.toUpperCase。我们也可以通过使用 a.toLowerCase 来将它们转换为小写。

有一个更有趣的方法可以看看,那就是 split。基本上,我们可以根据我们的分隔符来分割整个字符串。为此,我们使用 a.split()。在这种情况下,我们想要根据代码中的斜杠来分割,如下所示:

        String a= "java/training";
        System.out.println(a.split(/));

这意味着在 / 字符之前的整个字符串应该作为一个字符串分开,剩余的部分应该作为另一个字符串分开。这种方法不仅可以用来在斜杠处分割,还可以根据我们的需求分割,如下面的代码所示:

        String a= "javatraining";
        System.out.println(a.split(t));

如果我们想要从t中分割我们的字符串,那么这意味着java将是一个字符串,而raining将是另一个字符串。因为我们会有两个字符串,所以我们的输出将存储这两个字符串在一个数组中,而这个数组的返回类型当然是String,因为它是在String中编写的,如下面的代码所示:

        String arr[]=a.split("t");
        System.out.println(arr[0]);
        System.out.println(arr[1]);

如果你想要打印字符串的前一部分,那么它将被存储在数组系统的0索引中,而如果你想要打印字符串的第二部分,那么它将在数组的1索引中呈现。

我们在这里将要讨论的最后一种方法是replace方法,如下面的代码所示:

        String a= "javatraining";
        System.out.println(a.replace("t", "s"));

在这里,我们想要将字符串中的t替换为一个随机的s。为此,我们使用a.replace("t", "s"),就是这样。打印出来后, wherever a t is present in the string, it will be changed to an s, and it will be printed in your output.

对于String方法来说,这基本上就结束了。你仍然可以通过使用a.并逐步遍历不同的方法来玩转它们,但这些都是我们在 Java 编程中使用的核心方法。

让我们尝试根据在本节中学到的方法解决一个例子。

反转字符串的逻辑

在本节中,让我们看看我们如何以相反的顺序打印一个字符串。这是雅虎面试中的一个问题。让我们为我们的例子创建一个reversedemo类。

我们有一个名为Rahul的字符串,我们想要输出为luhaR。还有一个概念我们需要注意:回文。如果你输入一个字符串,比如madam,并且我们反转这个字符串,它只会给出madam作为输出。这种类型的字符串被称为回文。以下代码中展示了一个回文的实例:

package demopack;

public class reversedemo {

    public static void main(String[] args) {

        String s = "madam";
        String t= "";
        for(int i=s.length()-1; i>=0; i--)
        {
            t= t+ s.charAt(i);
        }
        System.out.println(t);
    }
}    

我们首先创建一个名为s的字符串和一个空字符串,名为t。我们创建这个空字符串是为了在for循环之后连接每个元素,以便在控制台以字符串的形式输出结果;否则,我们可能会得到如下所示的结果:

m
a
d
a
m

使用连接逻辑,我们可以显示输出如下:

madam

这是一个简单的逻辑,用于反转我们的字符串,并使用空字符串逻辑以字符串的形式显示它。我们使用了charAt方法并实现了我们的反转字符串。一旦我们有了反转的字符串,我们就可以很容易地将其与原始字符串进行比较——在我们的例子中,这涉及到将t字符串与s字符串进行比较,如果它们都匹配,那么我们可以打印出给定的字符串是一个回文。

忘记回文。这是字符串反转的概念。

概述

在本章中,我们介绍了字符串,这是 Java 中较为重要的类之一。我们探讨了定义字符串的不同方法。然后,我们研究了String类下的不同方法。我们查看了一些String类中最常用的方法,在最后一节中,我们通过一个反转字符串的示例来更好地理解String类。

在下一章中,我们将通过示例了解重要的循环和条件。

第四章:Java 程序的基础块——循环和条件

循环和条件是 Java 程序的基础。本章将通过示例帮助我们理解重要的循环和条件。在 Java 中学习这些循环和条件将使编写代码变得更加容易。

在本章中,我们将涵盖以下主题:

  • for 循环

  • if...else 条件

  • 当前的 while 循环

  • 嵌套循环

当前的 for 循环

让我们看看for循环是如何工作的。for循环是 Java 程序中最常用的循环之一,了解它是如何内部工作的非常重要。所以,假设我们想要使用for循环打印从 1 到 100 的数字。为了在for循环中按顺序执行数字 1 到 100 并写入它,我们将简单地写下:

// 1 to 100

/*  for(initialization;condition;increment)
       {
       } */
    for (int i=0;i<100;i++)
    {
        system.out.println(i);
        }
}

由于我们想要打印0123,我们使用i++。这意味着对于每个循环,它只增加1。在循环过程中,每次它也会检查前面的条件是否满足。所以,如果1小于100,它会进入循环;如果2小于100,它会进入循环。直到这个条件满足,它将一直循环。当i的值达到100时,100小于100,这是假的。那时,它将终止循环并退出。这里我们将使用一个基本示例:

for (int i=0;i<5;i++)
    {
         system.out.println(i);
    }

要在 IDE 中以调试模式运行测试用例,请双击以下屏幕截图所示的位置:

图片

调试开始的行

当你看到蓝色图标时,通过点击类似昆虫的符号在调试模式下运行它。它将要求你在调试模式下启动。只需点击保存即可:

图片

编辑器顶部的调试图标

你将在这里看到所有的变量值。一步一步地,我们将进入循环,并执行程序的下一步:

图片

调试时的变量值

最后,当它达到值4,并且再次增加1后,它变成了5。注意,它在值变成5后没有进入循环,就退出了。这意味着条件不再满足,循环将运行五次。输出显示在下面的屏幕截图中:

图片

根据代码的最终输出

所以,这就是for循环的工作方式。

现在,如果我们把条件设置为以下内容,它将不会进入for循环,即使是第一次,因为条件是假的:

for (int i=5;i<3;i++)

在调试模式下运行前面的条件时,整个循环将被跳过,输出中不会看到任何内容。

让我们看看另一个例子:

for (int i=0;i<10;i+2 )

输出将是:

0
2
4
6
8

这就是for循环在内部是如何工作的。

在下一节中,我们将学习if...elsedo...while循环。

if...else 条件

在我们学习whiledo...while循环之前,我们将在本节中讨论if条件。在 Java 程序中,当使用if条件语句时,只有当条件满足时,if块中的语句才会执行。否则,将运行else块中的语句。此外,这种执行只发生一次。在for循环中,一个变量被初始化,循环一直运行,直到条件满足。

然而,在if的情况下,它不会一直循环。一旦满足if条件,它将进入循环一次;否则,它将进入else块。因此,控制将执行此else块中的语句,如下面的截图所示:

根据代码显示的 if...else 条件输出

但所有这些只发生一次,与for循环不同,在for循环中,条件满足直到它返回并执行。

让我们看看以下示例:

    if(5>2)
    {
        System.out.println("success");
    }
    else
    {
        System.out.println("fail");
    }

下面的截图显示了这些错误:

快速修复下拉菜单提供修正代码错误的建议

第一个错误是删除包含条件,这可以忽略。运行前面的程序,你会看到输出为success,因为进入的是条件5大于2为真:

输出显示成功,如代码所示

如果我们更改条件并使5小于2,使条件为假,它将跳转到else块并执行else块中的语句。

代码以输出失败

这次输出应该是fail,如下面的截图所示:

输出显示成功,如代码所示

这就是if条件的工作方式。

注意,如果你的块中只有一行,那么你可以去掉这些括号,因为最终它假设如果条件为真,则将执行下一行。这意味着如果你在你的块中只有一行,那么你可以去掉括号。但如果你想要有多个语句,如果你的条件为真,那么确保你在括号中写出这些语句以避免冲突。如果你没有指定括号,它仍然会打印为success,如下面的截图所示:

修改代码后输出显示成功

这里,5大于2。运行这个程序,程序将不使用括号运行。

现在,在添加一个额外的语句,比如"second step",它会抛出一个错误,如下面的截图所示:

错误会在行号旁边的交叉标记中标记,显示语法错误

注意前一个截图中的语法错误。要么你应该保留一个括号,要么你应该避免这个步骤。为了消除这个错误,我们将整个块保留在括号中。这样,错误就会消失。

for循环中引入if...else条件

现在,让我们将if...else条件引入for循环。让我们在我们的代码中添加以下内容:

for (int i=0;i<10;i=i+2)
{
     if(i==8)
     system.out.println("print 8 is displayed");
     else 
        system.out.println("I did not find");
}

由于这里只有一个语句,我们不会在括号中写它。现在,让我们分析一下。值将从零开始进入for循环,直到值小于10

进入for循环时,它会检查第一个值0是否等于8。由于它不相等,它会显示"I didnot find"。现在,第二次,将2加到0上(按照我们设定的条件)。请注意,这个新值仍然不等于8;因此,对于0246这些值,输出将保持不变。接下来,当8进入for循环时,条件得到满足,并显示输出" 8 is displayed"

输出显示为"8 is displayed""I didnot find"

现在,如果我们说i=9,它将永远不会被打印,因为我们设定的条件是i+2,这将是一个递增的偶数。这意味着条件没有得到满足,if条件之后的下一个步骤不会被执行。因此,我们可以这样说,如果条件为真,那么它才会被执行;如果不为真,则执行else块中的条件或语句。当你运行它时,你总是得到输出"I did not find"

然而,如果我们写下以下语法,我们将得到输出为"9 is displayed"

for(int i=0;i<10;i=i+3)

这就是if...else条件在for循环中工作的方式。在下一节中,我们将详细了解for循环。

while循环

在本节中,我们将详细了解while循环。首先,创建一个新的类。现在让我们看看我们如何在编写代码时利用这个while循环。假设我们想要按顺序打印从 1 到 10 的数字。我们如何使用while循环来打印这些数字?while循环的基本语法是:

// While loop

while(boolean)
{

}

而在这里,如果布尔表达式返回true,则控制才会进入这个循环,而如果表达式返回false,则控制将不会进入循环。这就是你与while循环的基本简单概念。现在让我们假设我们想要从 1 到 10 引入数字。为此,我们将编写以下代码:

//While loop 

//1 to 10

int i=0;
while(i<10)
{
      System.out.println(i);
}

如您所见,在前面的代码示例中,我们可以看到给定的条件是真实的。因此,它进入循环并打印i的值。这个循环会一直执行,直到表达式评估为false。根据我们的例子,条件始终为真;因此,它会进入无限循环并打印零。

这就是 while 循环的工作方式。除非这个参数中的条件变为假,否则这个循环永远不会停止执行。现在,如果我们打印变量后递增会发生什么?让我们看看我们这样做会发生什么:

//While loop 

//1 to 10

int i=0;
while(i<10)
{
      System.out.println(i);
      i++;
}

输出将如以下截图所示:

根据代码的 while 条件输出

如果我们使用以下条件:

while(i<=10)

新的输出将是:

修改代码后的 while 条件输出

同样,你也可以反转条件,如下所示:

//While loop 

//1 to 10

int i=10;
while(i>0)
{
      System.out.println(i);
      i++;//i=2
}

输出将无限循环,因为数字一直在增加,因为 10 大于 0

如果我们使用递减条件,它将一直递减,直到条件变为假。之后,它将退出循环,如下面的代码示例所示:

//While loop 

//1 to 10

int i=10;
while(i>0)
{
      System.out.println(i);
      i--;//i=2
}

上一段代码示例的输出将是:

5
4
3
2
1

因此,这就是我们如何在 Java 程序中使用 while 循环语法。在下一节中,我们将看到如何处理 do...while 循环。

do...while 循环

do...while 循环的语法是:

do
{
}while();

让我们考虑以下示例,其中我们想要打印从 20 到 30 的数字:

    int j=20;
do
{
    j++;
}while(j<30); // 1 loop of execution is guaranteed 

上述代码将输出 202122 直到 29。因此,首先它执行,然后比较。

while 循环和 do...while 循环的基本区别在于,while 循环在没有评估布尔表达式的情况下不会执行,而 do...while 循环首先执行一个循环,然后评估是否运行更多循环。

让我们考虑以下示例,其中变量的值大于 30

int j=20;
do
{
    j++;
}while(j>30); // 1 loop of execution is guaranteed 

在这里,输出将是 20,而随后的脚本将终止,因为,如本节前面所述,在 do...while 循环中,保证执行一个循环。如果你在这个 while 循环中运行相同的逻辑,即使是第一次,它也不会执行。

因此,在下一节中,我们将尝试基于 for 循环、while 循环、do...while 循环和 if 条件的练习。这些程序将是非常好的动手学习,有助于理解循环。

在下一节中,我们将学习嵌套循环是如何工作的。

嵌套循环

这是一个最重要的概念之一。所有的编程逻辑都来自嵌套循环。如果你能掌握其背后的概念,那么你将很容易解决 Java 中的编程示例。所以,首先,我将写一个语法:

for(int i=1;i<=4;i++)  // this block will loop for 4 times
{
}

上述语法表示循环将运行四次。如果我们再在上述块中写一个 for 循环会怎样?在循环中实现循环的概念称为 嵌套循环

     for(int i=1;i<=4;i++)  
     // (outer for loop) it will loop for 4 times
     {
         System.out.println("outer loop started");
         for(int j=1;j<=4;j++) //(inner for loop)
         {
             System.out.println("inner loop");
         }
         System.out.println("outer loop finished");
     }

因此,当我们完成前一个迭代一次时,一个循环系统就完成了。为了完成一个外层循环,我们必须完成所有四个内层循环。这意味着我们将不得不运行这个内层循环 16 次(四次乘以四次)才能完成这个外层循环四次。

输出结果如下所示:

图片

根据代码输出的嵌套循环

进一步学习,for循环的概念将被更频繁地使用。为了理解for循环的概念,让我们尝试解决几个示例。

示例 1

编写以下输出的代码:

1 2 3 4
5 6 7
8 9
10

如我们从输出中观察到的,对于每一行,一个数字在递减。在这里,我们将探讨外循环和内循环的概念。代码如下:

int k=1;
for(int i=0;i<4;i++)  
// (outer for loop) it will loop for 4 times
     {
         //System.out.println("outer loop started");
         for(int j=1;j<=4;j++) //(inner for loop)
         {
             System.out.print("k");
             System.out.print("\t");
         }
         System.out.println(" ");
    }

示例 2

编写以下输出的代码:

1
2 3
4 5 6 
7 8 9 10

如您所见,本例中使用的输出与第一个示例的输出相反:

int k=1;
for(int i=1;i<5;i++)  
// (outer for loop) it will loop for 4 times
     {
         //System.out.println("outer loop started");
         for(int j=1;j<=i;j++) //(inner for loop)
         {
             System.out.print("k");
             System.out.print("\t");
             k++;
         }
        System.out.println(" ");
     }

示例 3

以类似的方式,还有一个名为排序数字的程序

编写以下输出的代码:

1
1 2 
1 2 3
1 2 3 4

上述输出的代码如下:

    for(int i=1;i<5;i++)  
    // (outer for loop) it will loop for 4 times
         {
              for(int j=1;j<=i;j++) //(inner for loop)
              {
                  System.out.print("j");
                  System.out.print("\t");
              }
              System.out.println(" ");
         }

概述

通过使用简单的示例,我们学习了如何在 Java 中使用if...else条件语句。我们还看到了如何使用for循环和while循环来获取所需的输出。进一步学习,我们学习了如何使用嵌套for循环以特定模式获取输出。

在下一章中,我们将介绍一些重要概念,例如接口、它们的工作原理以及在 Java 中的使用。我们还将通过实际示例讨论继承。

第五章:关于接口和继承你需要知道的一切

在本章中,我们将探讨一些重要概念,例如接口、它们的工作原理以及在 Java 中的用法。我们将通过一个实际例子来讨论继承。本章还将探讨函数重载和函数重写的概念以及它们之间的区别。

我们将在本章中介绍以下内容:

  • 接口

  • 继承简介

  • 函数重载

  • 函数重写

接口

接口是 Java 面向对象编程中使用的核心概念之一,因此我们有必要熟悉接口及其用法。

接口与类相似。接口与类之间的唯一区别是接口将包含方法但没有方法体。困惑了吗?在一个类中,我们通常定义一个方法然后开始向其中编写代码。例如,在一个类中,如果我们想编写任何代码,我们只需通过使用public void声明该类,然后在该类中继续编写其余的代码,如下所示:

public void getData()
{
}

在接口中,我们只能定义方法的签名;我们无法在方法内部编写任何代码。但为什么?在接口内部编写方法签名有什么用?这个面向对象的概念在 Java 中有什么用?你可能会有这些疑问,所以让我们尝试通过一个现实生活中的场景来理解接口的概念。

使用接口的交通信号灯系统

考虑典型的交通信号灯系统,它被全世界用来维护交通规则。每个国家都有自己的交通规则,例如在道路的左侧或右侧驾驶。尽管各国交通规则不同,但有一些规则是全球通用的,并且每个国家都需要遵守。其中一条规则是使用交通信号灯来控制交通流量,红灯表示停车,琥珀/黄色灯表示准备引擎,绿灯表示移动车辆。假设这些全球规则是由一个中央交通当局制定的,我们想要实现,例如,澳大利亚的交通系统。这个系统将有自己的规则,但我们需要确保它遵循中央交通当局规定的全球规则。

通过这个例子,我们将尝试理解接口的概念。在这里,中央交通当局充当接口,澳大利亚交通规则充当实现接口的类;也就是说,澳大利亚交通系统将必须遵循中央交通当局接口中提到的规则/方法。任何接口中定义的方法只是签名,因此类将定义并实现接口中存在的方法。让我们看看我们的 Java 代码中的这个例子。

我们定义接口的方式与定义类的方式相同。在这个交通信号灯示例中,让我们将类命名为CentralTraffic。我们现在有一个现成的接口,如下所示:

package demopack;

public interface CentralTraffic {

    public void greenGo();
    public void redStop();
    public void FlashYellow();

}

我们可以在语法中看到,我们写的是interface而不是class。我们使用与在类中定义方法相同的方法在接口中定义一个方法,但请记住,我们不能有定义方法的主体,因为这是一个接口,这样做将引发错误。创建另一个类来实现这个接口,并将其命名为AustralianTraffic。一旦我们有了 Java 类,我们需要将CentralTraffic接口实现到它上面,我们使用implements关键字这样做,如下所示:

public class AustralianTraffic implements CentralTraffic {

在使用前面的句子后,我们的集成开发环境(IDE)将显示一个错误,当你将鼠标悬停在错误上时,你会看到一些与错误相关的建议。其中一个建议是导入CentralTraffic,另一个建议是添加未实现的方法。点击这些建议以解决错误,你应该得到以下代码:

package coreJava;
import demopack.CentralTraffic;
public class AustralianTraffic implements CentralTraffic {

    public static void main(String[] args) {

    }
    @Override
    public void greenGo() {
        // TODO Auto-generated method stub
        System.out.println(" greengo implementation")
    }
    @Override
    public void redStop() {
        // TODO Auto-generated method stub
        System.out.println(" redstop implementation")
    }    
    @Override
    public void FlashingYellow() {
        // TODO Auto-generated method stub
        System.out.println(" flash yellow implementation")
    }

}

CentralTraffic接口中定义的所有方法都可以在AustralianTraffic类中看到,我们也可以按自己的意愿实现这些方法。现在,如果我们从我们的 Java 类中移除greenGo方法,它将给出一个错误。因为这个方法是接口中定义的,所以我们必须实现接口中定义的所有方法。

接口方法是在public static void main外部定义的,要执行这些方法,我们应该在main方法中为它们创建一个类对象,如下所示:

        CentralTraffic a= new AustralianTraffic();

这行代码表示我们为AustralianTraffic类创建了一个对象来实现CentralTraffic接口中的方法。主类应该如下所示:

public class AustralianTraffic implements CentralTraffic {

    public static void main(String[] args) {
    CentralTraffic a= new AustralianTraffic();
    a.redStop();
    a.FlashYellow();
    a.greenGo();    
    }

现在,在实现了接口中的方法之后,我们可以在我们的 Java 类中定义我们自己的特定国家的方法(规则),如下所示:

public void walkonsymbol()
{
    System.out.println("walking");
} 

在我们的main方法中,如果我们尝试使用a.调用我们的特定国家的方法,就像我们在main类中的其他方法那样做,那么我们会发现我们无法这样做,因为walkonsymbol方法特定于某个国家(即AustralianTraffic类)并且没有在CentralTraffic中实现。对于walkonsymbol方法,我们需要在main类中为AustralianTraffic类创建另一个对象,如下所示:

        AustralianTraffic at=new AustralianTraffic();
        at.walkonsymbol();

与接口相关的一条信息是,一个类可以实现多个接口。假设我们创建另一个接口,例如ContinentalTraffic,并定义另一个与交通信号灯相关的规则,例如一个火车符号来表示火车正在通过。我们可以在我们的AustralianTraffic类中简单地通过添加逗号来实现这个接口,如下所示:

public class AustralianTraffic implements CentralTraffic, ContinentalTraffic {

对于这个接口,我们需要遵循与 CentralTraffic 接口相同的步骤,例如将 ContinentalTraffic 导入到 AustralianTraffic 中,添加未实现的方法,在主类中创建特定的 ContinentalTraffic 对象,等等。

现在你对接口和类之间的区别有了相当的了解。我们学习了如何定义接口,如何在另一个类中实现它们,以及如何使用对象调用它们。

继承

继承是 Java 中另一个重要的面向对象编程(OOP)概念。让我们以一个车辆为例来理解继承的概念,就像我们使用交通信号系统示例来理解接口一样。车辆的基本属性包括其颜色、档位、后视镜、刹车等。假设我们正在制造一种新的车辆,它对某些属性进行了改进,例如具有更高 CC 的引擎,也许与旧款的设计不同。现在,要创建具有这些新功能的新的车辆,我们仍然需要旧车辆的基本功能,例如后视镜和刹车,这些功能在车辆中默认存在。

让我们以先前的例子为例,使用 Java 来反映这些关系,以便理解继承的概念。在我们的例子中,如果我们有一个车辆类,并将车辆的基本特征作为存在于该类中的方法,那么当我们创建一个新的车辆类时,它可以继承为车辆创建的类的特征,我们不需要为这些特征编写代码,因为它们通过继承对我们可用。

让我们从代码开始。创建一个 parentClassdemo 类,这将是我们的父类。在这个类中,我们将定义我们的方法,如下所示:

package coreJava;
public class parentClassdemo {

    String color = "red";

    public void Gear()
    {
        System.out.println("gear code is implemented");
    }
    public void Brakes()
    {
        System.out.println("brakes code is implemented");
    }
    public void audiosystem()
    {
        System.out.println("audiosystem code is implemented");
    }
}

我们现在将在子类中继承这些方法。创建一个 Java 中的 childClassDemo。我们使用 extends 关键字继承父类,如下所示:

package coreJava;
public class childClassDemo extends parentClassdemo {

    public void engine()
    {
        System.out.println("new engine");
    }
    public void color
    {
        System.out.println(color);
    }

    public static void main(String[] args) {
        childClassDemo cd=new childClassDemo();
        cd.color();
    }

在这里,我们使用 extends 关键字在 childClassDemo 类中继承了 parentClassdemo 类。在这个 childClassDemo 类中,我们定义了自己的 engine 方法,并使用了从 parentClassdemo 类继承来的 color 方法。然后我们创建了一个 cd 对象,并使用它来调用继承类中的方法。

更多关于继承

让我们讨论一些关于 Java 继承中臭名昭著的棘手问题和误解。

让我们开始讨论一些关于继承的更常见问题。看一下以下代码块:

class X
{
    //Class X members
}

class Y
{
    //Class Y members
}

class Z extends X, Y
{
    //Class Z members
}
X and Y class and some data fields or methods inside it. The Z class inherits the X and Y classes. Is this allowed? The answer is no. Java does not allows multiple inheritances, whereas it is allowed in C++. So here, we can conclude that the preceding code snippet is not right and will throw an error.

这也是继承与接口之间区别之一,因为接口允许我们同时使用多个接口。

看一下以下示例:

class A
{
    int i = 10;
}

class B extends A
{
    int i = 20;
}

public class MainClass
{
    public static void main(String[] args)
    {
        A a = new B();
        System.out.println(a.i);
    }
}

在这里,我们有一个A类,它有一个i变量。还有一个扩展了A类的B类,并且我们也将它的局部i变量设置为20。现在,在MainClass中,我们为B类创建了一个对象。这一步实际上意味着什么?在这里,我们正在创建一个对象,并说明这个B类的对象应该引用A类的属性。尽管我们有权限通过这个a对象访问B类,但我们只能访问A类的属性或方法,因为B类有权限在这里访问A类,因为我们正在扩展它。

这里的问题是a.i将打印什么——20还是10?答案是,它将打印变量值10,因为A a = new B();明确告诉a它是一个B类的对象,但我们需要访问A类中的方法。如果我们想得到20的输出,我们将语法改为B a = new B();

如果你参加 Java 测验或复杂的面试,可能会遇到这样的问题。这些都是你必须知道的关于继承的重要信息,你可以据此进行规划。

函数重载

当一个类有多个同名方法时,就会发生函数重载。如果我们在我们类中定义两次getData方法,我们可以说getData函数被重载了,如下面的代码所示:

package coreJava;
//function overloading
public class childlevel extends childClassDemo {

    public void getData(int a)
    {

    }
    public void getData(String a)
    {

    }

    public static void main(String[] args) {
        childlevel cl=new childlevel();
        cl.getData(2);
        cl.getData("hello")
    }
}

在使用具有相同名称的多个函数实例时,我们需要记住一些规则。第一条规则是函数重载方法中参数的数量应该不同,第二条规则是参数的数据类型应该不同。如果我们保留两个具有int a参数的getData方法,它将引发错误,因此我们需要为每个方法有不同的参数数量。现在,当你打印这些时,你会得到2hello的输出。我们可以看到打印了两个不同的参数,但具有相同的名称。让我们再添加一个具有两个参数的getData实例,如下所示:

    public void getData(int a, int b)
    {

    }

现在我们有两个getData实例,它们的数据类型相同,但参数的数量不同。

你在现实生活中也可能遇到函数重载,例如,当你在电子商务网站上被要求选择支付方式时。网站可能使用不同的getPayment方法来确认支付——一个getPayment方法接受借记卡作为参数,另一个getPayment方法接受信用卡作为参数,另一个getPayment可能接受礼品卡作为参数。所以我们将不同类型的参数传递给同一个getPayment方法。在这种情况下,我们坚持使用getPayment作为方法名,并传递不同的参数,将函数重载的概念应用到这个特定的场景中。

函数重写

在本节中,让我们再讨论 Java 中的一个重要特性——函数重写。让我们继续使用我们在学习继承时看到的相同示例。

在那个示例中,我们有一个名为parentClassdemo的父类和一个名为childClassDemo的子类,子类继承了父类,如下所示:

package coreJava;
public class childClassDemo extends parentClassdemo {

    public void engine()
    {
        System.out.println("new engine");
    }

    public static void main(String[] args) {
        childClassDemo cd=new childClassDemo();
        cd.color();
    }

在这里,我们在子类中定义了engine方法,它打印一个新的引擎,我们还有一个名为color的方法,它在父类中定义,我们通过一个对象来调用它。如果我们打印这个,我们将得到color方法的输出,因为它是在父类中定义的。现在,我们在子类中创建一个新的方法,并将其命名为color,定义如下:

    public void color()
    {
        System.out.println("update color");
    }

我们有两个color方法的实例——一个在父类中定义,另一个在子类中定义。这就是函数重写概念发挥作用的地方。如果你运行子类,你将得到update color的输出。这是因为子类中定义的新color方法覆盖了父类中的color方法。

这总结了函数重写的整个概念,其中两个方法具有相同的名称、签名和参数。在函数重载中,我们有具有相同名称但不同参数的方法。这是函数重载和函数重写之间的一项主要区别。

概述

在本章中,我们介绍了几个重要的 Java 面向对象概念,例如接口、继承、函数重载和函数重写。我们通过示例查看每个概念,这有助于我们更好地理解这些概念。

在下一章中,我们将探讨 Java 代码中最重要概念之一:数组。我们将看到不同数组的形态,以及如何初始化和显示它们。

第六章:了解有关数组的一切

在本章中,我们将探讨 Java 代码中最重要概念之一:数组。我们将看到不同数组的样式,以及如何初始化和显示它们。我们还将查看一些练习,以帮助我们更好地理解数组的工作原理。

在本章中,我们将涵盖以下主题:

  • 数组及其在 Java 程序中的应用

  • 初始化数组和分配对象的方法

  • 多维数组的逻辑编程

  • 练习

数组及其在 Java 程序中的应用

我们可能以前遇到过数组的术语,所以让我们通过解释和示例来了解数组是什么。

数组是一个存储多个相同数据类型值的容器。

在以下示例中,我们将了解什么是容器,如何定义该容器,以及我们如何在其中存储值。

如果我们要使用数组,我们通过以下代码为它们分配一些空间来声明它们:

int a[] = new int[];

new关键字基本上为这个数组中的值分配内存。方括号表示我们将多个值添加到方括号中,[]表示数组的术语。为了定义一个数组,我们必须为将要存储在其中的多个值创建空间。在这个例子中,我们有五个整数值,我们计划将它们存储在数组中,这就是为什么我们指定数组数据类型为整数,并且要添加的变量数量在方括号中给出:

int a[] = new int[5];

如我们在第三章中观察到的,在Java 中处理字符串及其函数,如果值是字符串,我们将指定数组数据类型为String

我们已经声明了一个数组并为值分配了内存,现在我们需要传递这些值。第一个值将放在索引0,第二个放在索引1,以此类推,直到所有五个值。索引命名从0开始,这意味着我们实际上在数组中初始化了值。现在a数组包含了我们分配给它的所有值。在我们的例子中,我们为该数组声明了任何随机的值。

现在让我们从数组中检索值。为此,我们在声明数组的值之后,在main类中输入以下代码来创建一个for循环,并在其后留下一个打印语句:

for(int i=0; i<a.length;i++);
{
    System.out.println(a[i]);
}

我们将起点设置在索引0,并将限制设置为数组的长度。看看i<a.length代码,length是一个实际上返回数组大小的方法。

当我们运行代码时,我们会看到分配给数组的所有值依次打印出来。在下一节中,我们将看到一种更简单的方式来声明和初始化所有数组值。

初始化数组和分配对象的方法

在上一节中,我们看到了如何声明一个数组;最简单的方式是使用数组字面量形式。让我们用一个例子来解释这一点。

我们通过在先前的例子中输入以下代码行来声明另一个数组:

int b[] = {1,4,3,5,7,8};

前一个例子中的声明与我们在本例中进行的声明有什么区别?

在先前的例子中,我们是在分配内存然后赋值。在本例中,我们不是分配内存,而是直接将值传递给数组。在这里,内存是动态分配的,如果我们向数组声明中添加一个值,将自动分配内存并将值传递给它。在大多数情况下,程序员使用这种方法来声明数组值,而不是声明分配然后赋值。

与先前的例子类似,第一个值被分配到索引0。如果我们写一个与先前的例子类似的打印语句并运行代码,我们将看到b数组的值被显示出来。

这样我们就结束了单维数组的讨论;让我们来谈谈多维数组。

多维数组

x轴和y轴上传递对象,其实就是一个多维数组。其中x轴是行,y轴是矩阵中数组值的列。这里的“多”意味着我们从多角度来观察数组;这被称为多维数组。以下是我们创建的一个多维数组,用于解释这个概念:

2  4  5
3  4  7
5  2  1

这是一个矩阵,它有三行三列。2位于零行零列,它旁边的4位于零行第一列,其余的值以此类推。所以每个参数都有一个x轴和一个y轴。

让我们举一个例子来解释这一点。我们将创建另一个类,命名为Multidimensional.java,并在其中声明一个多维数组a

int a[][] = new int[2][3];

第一个括号代表x轴或行,第二个代表y轴或列。所以x轴有三个值,意味着有三行,而y轴有三个列。然后我们为创建的多维数组中的每个元素分配值。以下代码显示了如何为矩阵分配值:

a[0][0]=2;
a[0][1]=4;
a[0][2]=5;
a[1][0]=3;
a[1][1]=4;
a[1][2]=7;

这样我们就可以将所有值输入到一个多维数组中。如果我们想显示第二行第一列的值,我们写一个打印语句并给出我们希望显示值的元素位置。在这种情况下,我们想显示第二行第一列,所以打印语句将写成:

System.out.println(a[1][0]);

打印语句将显示3,这是该位置元素的值。在下一节中,我们将举一个例子,帮助解释我们如何使用所有这些概念来解决编码问题。

我们如何打印出在本例中声明的 a 数组的所有值?在先前的例子中,我们通过简单地创建一个for循环,从0迭代到数组的长度,然后显示数组。

如果我们想以最简单的格式声明一个多维数组,就像前一个例子中描述的数组b一样,我们可以用以下方式编写:

int b[][]= {{2,4,5},{3,4,7},{5,2,1}};

数组将假设第一个括号中的值在零索引,第二个在第一个索引,第三个在第二个索引。这是声明多维数组的最简单方式。

多维数组的逻辑编程

现在,我们将看看如何打印之前章节中使用的整个多维数组的所有值,即数组a

如果我们分析数组的声明,我们会看到需要两个for循环来打印整个数组,一个用于行,一个用于列。

我们希望控制器扫描完整的第一行,然后是第二行,最后是第三行。因此,我们添加一个外部的for循环来处理行,并将长度限制设置为数组中的行数,在这种情况下是两行。行的外部for循环将如下所示:

for(int i=0;i<2;i++)

这个for循环实际上将循环两次,因为我们为行设置了2的限制。第一个循环将扫描第一行,第二个循环将扫描第二行。现在,对于每个循环,我们需要扫描该特定行中存在的三个列。为此,我们添加一个内部for循环来扫描每一列,并将限制设置为数组中的列数,在这个例子中是3。列的内部for循环将如下代码所示:

for(int j=0;j<3;j++)

最后,为了打印数组,我们在内部for循环中添加一个打印语句来显示所有值。最终的代码将如下所示:

for(int i=0;i<2;i++) //row
{
    for(int j=0;j<3;j++) //coloumn
    {
        System.out.println(a[i][j]);
    }
}

让我们尝试理解我们在这里写的内容。控制将从外部for循环开始;这个外部for循环执行两次,因为它被设置为小于2。第一次进入外部for循环后,它进入内部for循环;这个循环执行三次,因为j被设置为小于3

让我们调试它并查看代码中的几个步骤来更好地理解这些循环。以下是在调试代码时将执行的步骤:

  1. 控制器第一次执行外部循环,i的值已经被初始化为0,这意味着x轴的值被设置为0。控制器将查看第一行,因为0表示正在访问第一行。

  2. 它移动到内部for循环并执行它,j的初始值已经被初始化为0;这意味着Y轴的值被设置为0。控制器将查看第一行和第一列,因为它已经在第一行,这是由于外部循环。内部循环将控制器发送到查看第一列。

  3. a将取第一行和第一列的值,因为ij的初始值都是0,即a[0][0]。因此,这次执行的输出将是第一行和第一列,在这个例子中是2

  4. 由于j被迭代到1,小于3,因此循环的条件仍然满足,控制器再次进入内for循环。这意味着y轴的值被设置为1,它将访问第二列。由于外循环和内循环已经将控制器置于第一行,控制器将查看第一行和第二列。

  5. a将取第一行和第二列的值,因为ij的值被设置为01,即a[0][1]。因此,这次执行的输出将是第一行和第二列,在这个例子中是4

  6. 由于j被迭代到2,小于3,因此循环的条件仍然满足。这意味着y轴的值被设置为2,它将访问第三列。由于外循环和内循环已经将控制器置于第一行,控制器将查看第一行和第三列。

  7. a将取第一行和第三列的值,因为ij的值被设置为02,即a[0][2]。因此,这次执行的输出将是第一行和第三列,在这个例子中是5

  8. 当控制器现在进入内循环时,它将无法执行它,因为j再次迭代后值将变为3,这并不小于我们为循环设置的极限。因此,控制器退出内for循环并返回外循环,迭代i的值为1;这意味着x轴的值被设置为1。控制器将查看第二行,因为1表示正在访问第二行。

  9. 步骤 2、3、4、5、6 和 7 将再次重复,但这次i的值,即x轴,被设置为1;这意味着将访问第二行。根据之前指定的步骤显示第二行中的所有值,直到我们达到矩阵的第三列。

  10. 控制器在访问第三列后退出内循环,因为j将被迭代到3,小于我们为循环设置的极限。因此,控制器再次退出内for循环并开始执行外循环。

  11. 在外for循环中,i的值将被迭代到2,并且循环将不会执行,因为它不小于我们为其设置的极限2

这就是如何使用两个for循环来获取多维数组的值,其中外循环处理行,内循环处理列。

练习

让我们尝试一些练习,这些练习将帮助我们理解和处理数组。这些练习在面试时也会解释概念。

打印 3 x 3 矩阵中的最小数

让我们为这个练习创建另一个类,命名为InterviewMinnumber,并在主块中定义数组。定义代码如下:

int abc[][]={{2,4,5},{3,2,7},{1,2,9}};

这段代码声明了一个名为abc的 3 x 3 矩阵。现在我们需要遍历矩阵中的每个数字,并寻找其中的最小数。要遍历多维数组中的每个数字,我们需要使用我们在多维数组上的逻辑编程部分中使用过的相同概念。

我们在这里使用两个for循环:一个外部的for循环用于遍历行,一个内部的for循环用于遍历列。这两个for循环的代码如下:

for(int i=0;i<3;i++)
    {
    for(int j=0;j<3;j++)
    {
    }
}

要找到最小的数,我们声明一个变量min,并将其赋值为abc数组的第一项。我们假设abc矩阵中的第一个值是最低的值。

我们在内部for循环中添加了一个if循环。在这个if循环中,我们写的任何内容都会去扫描我们声明的整个矩阵中的每个元素。在if循环中,我们添加了一个条件,检查从矩阵中取出的值是否小于min值。在if循环内部,我们交换minabc的值。最终的代码如下:

public class InterviewMinnumber 
{
    public static void main(String[] args) 
    {
        int abc[][]={{2,4,5},{3,2,10},{1,2,9}};
        int min=abc[0][0];
        for(int i=0;i<3;i++)
        {
            for(int j=0;j<3;j++)
            {
                if(abc[i][j]<min)
                {
                    min=abc[i][j];
                }
            }
        }
        System.out.println(min)
    }
}

让我们运行代码,看看它是如何找到矩阵中的最小数的。

当循环第一次执行时,矩阵的第一个元素的值与min变量的值进行比较,但我们把min变量的值设置为第一个元素,即2。我们在if循环中检查条件,该条件比较矩阵中元素的值和min的值。在这里,2不小于2,所以它不会进入循环,然后它再次回到代码的开始。在循环的下一轮中,元素的值发生变化,因为我们移动到了矩阵中的下一个元素。现在正在比较的元素是4,我们再次检查if条件,它不会为真,因为4不小于2,而2是当前min的值。最后,当它到达第三行第一列的元素时,1,那么if条件为真,控制器移动到循环内部,并将1赋给min值。这个过程一直持续到数组矩阵的最后一个元素,其中每个abc矩阵的值都与min变量进行比较。

如果我们调试代码并观察每一步,我们将更好地理解代码的逻辑和工作原理。

显示具有最小数的列中的最大数

在之前的示例中,我们观察了如何从数组矩阵中打印出最小数值。在这个例子中,我们将寻找矩阵中的最小数值,然后是同一列中的最大数值。背后的逻辑是:我们首先找到最小数值,记住它所属的行号,然后提取同一列中的最大数值。

让我们使用之前示例中使用的相同矩阵。在这个矩阵中进行的这个练习的输出将是4。以下步骤将用于执行此练习:

  1. 在我们声明的矩阵中找到最小值

  2. 确定最小数值所在的列

  3. 在确定的列中找到最大数值

在之前的示例中,我们已经执行了第 1 步,即找到矩阵中的最小数值,因此我们将使用相同的代码,只需稍作变量更改:

int abc[][]={{2, 4, 5}, {3, 0, 7}, {1, 2, 9}}

让我们进入第 2 步。如果我们观察代码,我们会看到i代表行号,而j代表列号。因此,j将取最小数值所在的列的值,我们将这个值赋给一个变量,该变量将调用mincolumn。因此,我们在交换命令下编写代码,将j的值赋给mincolumn。代码将类似于以下内容:

mincoloumn=j;

因此,当我们找到矩阵中的最小数值时,我们将它的值赋给j,即列号,赋给mincloumn。在这种情况下,mincolumn的值将是1。这完成了第 2 步。

在第 3 步中,我们从包含最小数值的列中寻找最大数值。我们创建一个while循环,位于我们为寻找矩阵中最低数值所创建的外部for循环之外。我们将条件变量k初始化为0,并在满足while循环条件时迭代它。while循环的条件设置为k小于3;这是因为我们需要遍历三行以寻找其中的最大值。while循环的代码将如下所示:

while(k<3)
{
    k++;
}

我们声明一个名为max的变量,并给它一个初始值行0和列mincolumn。这使得变量max的初始值为4,因为4是包含矩阵中最小数值的行的第一个元素。声明代码将如下所示:

int max=abc[0][mincoloumn];

while循环内,我们添加一个if循环,并设置一个条件,比较列中具有最小数值的变量是否大于我们声明的变量max。如果条件成立,该数值的值将被分配给max变量,控制器在通过1迭代k后退出if循环,并返回到while循环。迭代将控制器带到下一行,因为k用来表示正在遍历以寻找最大数值的行。

if循环的代码将如下所示:

if(abc[k][mincoloumn]>max)
{
    max=abc[k][mincoloumn];
}

因此,对于k的第一个值,即0,我们进入第一行第二列并将值赋给max;在这个例子中,值是4。在if条件中,我们比较第一行第二列的值与max的值。在这个例子中,两个值都是相同的,所以if循环没有执行,我们迭代k并再次进入while循环。接下来,我们比较第二行第二列的值与max的值;我们移动到第二行,因为k的值迭代了1,当前k的值是1。所以,在比较时,我们看到o小于4,其中4max变量的值。条件再次不满足,if循环再次被跳过。这也适用于第三行,最终max的值是4,这是该列中的最大数。最后,我们留下一个打印语句,在最后打印max的值。

使用/不使用临时变量交换变量

在这个练习中,我们将交换简单数组中元素的位置,并将它们按升序排列。

要做到这一点,我们首先需要理解其工作逻辑。让我们通过一个例子来解释这一点。

我们初始化a数组并在其中声明值,如下面的代码所示:

int a[]= {2,6,1,4,9};

我们可以使用冒泡排序机制来比较变量彼此,然后按照我们想要的顺序排列它们。对于前面的例子,逻辑的工作方式如下;我们将比较262124,以及29。比较之后的最小数是1,我们将它的位置与第一个索引交换,即2。所以交换后,1将成为新的第一个索引。这意味着1是数组中给出的值中的最小数。现在我们移动到第二个索引,我们保留第一个索引不变,因为我们已经比较并宣布1为固定的第一个索引,因为它在数组中是最小的数。现在我们取第二个索引的值6,并将其与其他数组中的值进行比较。首先我们比较62,由于2小于6,我们交换它们的位置,所以2成为新的第一个索引,6成为第二个索引。然后我们比较23;基本上我们是在比较第一个索引与数组中的所有其他值。然后我们比较2324,以及29;在这里2是最小的数。所以2成为数组中的固定第二个索引。现在我们剩下四个需要排序的值。我们再次比较6与其他值。6小于3,所以我们交换63的位置。这使得3成为数组中的第三个索引,我们比较3与其他数字,3是给定值中的最小数。所以3成为数组中的固定第三个索引。然后我们对最后三个值执行相同的事情,并得出最终排列将是123469。现在我们需要将这个逻辑应用到 Java 程序中并打印它。

我们将决定我们逻辑的算法,并根据该算法,我们将逐步设计我们的代码。我们将编写一个外层for循环,该循环移动一个索引并与其余部分进行比较。

我们编写一个外层for循环,并将条件设置为不超出数组的长度;这里数组的大小是5,所以条件设置为i小于5。如果i0,变量值将比较它和第一个、第二个、第三个和第四个变量。如果i2,变量将比较它和第三个和第四个变量。所以无论i索引是什么,它都应该从i的值开始比较其下一个索引。为此,我们将创建一个内层for循环,并将j初始化为总是比i多一个数字,即i1,因为我们将比较它和下一个索引。所以如果i等于0j将是1。所以零索引将从第一个索引开始比较。我们将其与数组的末尾进行比较,所以我们将内层for循环的限制设置为j,因为它小于数组的长度,在这个例子中是5

我们然后在内部for循环中添加一个if循环。这个循环将在条件满足时比较索引并交换值。一旦完成第一轮比较,控制器就会退出内部for循环,回到外部for循环,这时在比较后选择最小的数字,将其推到角落,索引移动到下一个值。

现在,我们回到if循环内部,编写代码在比较条件为真时交换值。为了交换变量值,我们需要声明一个temp变量并将a[i]的数字赋值给temp。我们添加以下代码以成功交换变量:

temp=a[i];
 a[i]=a[j];
 a[j]=temp;

最后,我们在比较和重新排列值后添加一个打印语句来显示最终的数组。

最终输出将如下所示:

1
2
4
6
9

摘要

在本章中,我们介绍了数组中的各种概念。我们查看了几种不同类型的数组,以及它们如何初始化和显示。然后我们进行了不同的练习,以了解我们如何在不同的实例中使用数组。

在下一章中,我们将讨论为什么Date类和构造函数是 Java 的重要组成部分

第七章:理解 Java 11 中的日期类和构造函数

Date类和构造函数是 Java 的重要组成部分。在本章中,我们将通过一些示例详细讨论这些内容。

在本章中,我们将涵盖:

  • Date

  • Calendar

  • 构造函数

  • 参数化构造函数

Date

为了理解Date类的概念,我们将首先为我们的dateDemo类创建源代码。假设我们想打印当前日期或当前时间。我们如何打印它?

有时,我们被要求将日期输入到当前日期字段中,我们需要从 Java 中获取它。在这种情况下,我们将使用Date类,它将给我们当前的日期和时间,以及以秒为单位的时间。因此,关于一天、一周、一个月、一年或小时的每个细节都可以通过 Java 类读取。Java 已经开发了一个名为Date的类,我们可以从中获取所有这些细节。以下截图显示了源代码:

图片

显示使用日期类的源代码

基本上,我们需要使用那个特定类中的方法。为了使用那个类中的方法,我们需要创建那个特定类的对象。为此,让我们考虑以下代码语法:

Date d= new Date();

这个Date类来自util包,d是包含日期和时间的Date类的对象。在前一章中,我们看到 Java 有一些包,如java.lang包,它捕获所有基本的 Java 内容,以及java.util包,这是我们拥有集合框架和Date类的地方。

前面的代码语法表明我们不知道Date类在哪里。为了使这个类在我们的 Java 文件中可用,我们需要导入util Java 包,因为Date类被封装在这个特定的包中。如果我们用它在前面类中导入包,你就可以成功使用那个日期。将鼠标移到这里,它会显示import 'Date' (java.util),如下面的截图所示:

图片

快速修复下拉菜单,提供纠正代码错误的建议

一旦点击它,你会看到:

import java.util.Date

其中util是包,Date是一个类。

正如我们所见,d是包含日期和时间的对象,但我们如何打印它?因为它是一个对象格式,我们不能简单地使用以下:

System.out.println(d)

要将其转换为可读文本,请参考以下截图:

图片

将代码转换为可读文本格式

在这里,我们将Date转换为字符串,这样我们就可以在我们的输出中直观地看到它。如截图所示运行前面的代码,它打印出以下内容:

Fri Apr 15 17:37:27 EDT 2016

这就是我们如何从当前系统的 Java 日期中打印整个日期、时间和月份。前面输出中的格式不是我们通常得到的,但它可能具有特定的格式,例如:

mm//dd//yyyy

如果我们想要以前面的格式提取我们的日期,我们该如何做?

d对象提供了所有详细信息。但我们如何将这些详细信息转换为前面的格式呢?为此,我们将使用以下内容:

       Date d= new Date();

        SimpleDateFormat sdf=new SimpleDateFormat("M/d/yyyy");
        System.out.println(sdf.format(d));
        System.out.println(d.toString());

前面代码语法的输出将是:

按照代码显示日期和时间

请参考以下 URL 以获取SimpleDateFormat格式代码:

现在,在修改对象和SimpleDateFormat代码后,我们看到以下内容:

 Date d= new Date();

        SimpleDateFormat sdf=new SimpleDateFormat("M/d/yyyy");
        SimpleDateFormat sdf=new SimpleDateFormat("M/d/yyyy hh:mm:ss");
        System.out.println(sdf.format(d));
        System.out.println(sd.toString());
        System.out.println(d.toString());

输出将如下所示:

以新格式显示日期和时间

因此,我们实际上可以按照我们的要求格式化日期,并将其传递给SimpleDateFormat方法。我们可以将d对象放入一个参数中,这样它将以特定方式格式化。这就是 Java 中检索日期的方式。

在下一节中,我们将看到如何使用Calendar类。

日历类

在上一节中,我们探讨了Date类,我们学习了Date方法以及如何使用简单的日期格式标准来操作它们。在本节中,我们将学习Calendar类,它与Date类类似,但有一些额外功能。让我们看看它们是什么,以及我们如何使用它们通过Calendar类提取我们的日期格式。

首先,我们将创建一个具有不同名称的类以避免冲突。要创建Calendar实例,请运行以下代码:

Calendar cal=Calendar.getInstance();
Date d=new Date();

步骤与Date类类似。然而,Calendar对象有一些Date不支持的独特功能。让我们来探索它们。

使用以下代码片段:

        Calendar cal=Calendar.getInstance();
        SimpleDateFormat sd=new SimpleDateFormat("M/d/yyyy hh:mm:ss");
        System.out.println(sd.format(cal.getTime()));

前面代码的输出将是:

使用日历类显示日期和时间

现在,假设我们想要打印月份和星期几。我们将在前面的代码片段中添加以下行:

System.out.println(cal.get(Calendar.DAY_OF_MONTH));
System.out.println(cal.get(Calendar.DAY_OF_WEEK_IN_MONTH));

输出将如下所示:

使用日历类显示日期、时间、月份中的天数和星期几

同样,我们可以从以下屏幕截图看到有多个属性可供选择:

显示日历类多个属性的下拉菜单

因此,在这里我们使用了Calendar实例来获取系统日期和时间,但在前面的类中我们使用了Date实例;这就是唯一的区别。在这个Calendar实例中有很多方法,你不会在Date类中找到。

这就是根据我们的要求检索系统日期的方式。

构造函数

构造函数是 Java 编程语言中最重要概念之一。因此,在我们看到示例之前,让我们先了解什么是构造函数。

构造函数在创建对象时执行一段代码块。这意味着,每当我们为该类创建一个对象时,都会自动执行一个代码块。换句话说,每当创建一个对象时,都会调用构造函数。

所以构造函数在哪里使用,我们如何定义它?构造函数应该像方法一样编写,但方法和构造函数之间的唯一区别是构造函数不会返回任何值,并且构造函数的名称应该始终是类名。

要为这个类创建一个构造函数,我们将编写以下代码语法:

public class constructDemo()
{
//
}

从前面的代码语法中可以看出,无论谁创建对象并调用构造函数,都会执行这个构造函数中写的内容。如果我们为前面称为constructorDemo的类创建一个对象,自动会执行这个代码块中的所有行。这就是构造函数的主要目的:

package coreJava;

public class constructDemo {
    public constructDemo()
    {
        System.out.println("I am in the constructor");
    }
    public-void getdata()
    {
        System.out.println("I am the method");
    }
    // will not return value
    //name of constructor should be the class name
    public static void main(String[] args)  {
        // TODO Auto-generated method stub
        constructDemo cd= new constructDemo(); 

每当执行前面的行时,控制会自动检查是否存在显式定义的构造函数。如果已定义,它将执行特定的代码块。在 Java 中,每当创建一个对象时,都会调用构造函数。

前面代码的输出将是:

I am in the constructor

我们实际上并没有为每个类创建构造函数,而是现在特别引入了构造函数的概念,因为在之前,我们在定义构造函数时没有使用任何概念。现在如果我们使用这个命令,程序仍然会运行,但这次它不会执行那个代码块。如果我们没有定义任何构造函数,编译器将调用默认构造函数。我们可能称之为隐式构造函数。

我们主要依赖于构造函数在实时中初始化对象,或者为我们的程序定义变量。构造函数和普通方法看起来相似,因为它们在括号中定义了访问修饰符,但不会接受任何返回类型,但在这种情况下它接受。因此,如果我们编写:

public constructDemo()
{
    System.out.println("I am in the constructor");
    System.out.println("I am in the constructor lecture 1");

}

前面代码的输出将是:

I am in the constructor
I am in the constructor lecture 1

因此,一般来说,人们使用前面的代码块来定义变量或在实时中初始化属性,然后继续使用构造函数。

在下一节中,我们将查看 Java 中另一个构造函数。

参数化构造函数

我们在上一节中学到的构造函数是默认构造函数,因为它不接受任何值。在具有相同语法的参数化构造函数中,我们实际上提供了一些参数,如下面的截图所示:

使用给定代码的参数化构造函数的输出

之前构造函数和这个构造函数之间的唯一区别是,在这里我们传递了参数,而在默认的构造函数中则没有传递任何参数。当我们运行我们的代码时,每当创建一个对象,如果我们没有传递任何参数,编译器会自动选择默认构造函数,如下面的截图所示:

当传递默认参数时的输出

现在,让我们为同一个类创建一个带有参数的另一个对象:

constructDemo c=new constructDemo(4,5);

当我们按照前面提到的语法定义参数时,编译器在执行运行时检查是否存在具有两个整型参数的构造函数。如果找到了构造函数,它会执行以下代码语法:

public constructDemo(int a, int b)
{
    System.out.println("I am in the parameterized constructor");
}

在没有定义参数的情况下,编译器会执行默认构造函数。前面代码的输出将是:

 I am in the parameterized constructor

在运行时创建对象时,我们必须提供参数,因此在执行过程中,它会将参数与定义的构造函数进行比较。同样,我们可以为同一个类创建多个对象:

constructDemo cd=new constructDemo();
constructDemo c=new constructDemo(4,5);

当两个构造函数一起运行时,输出将是:

I am in the constructor
I am in the constructor lecture 1
I am in the parameterized constructor

现在,我们将创建一个类似类型的另一个构造函数,但这次只有一个参数:

public constructDemo(String str)
{
    System.out.println(str);
}
public static void main(String[] args) 
{
    constructDemo cd=new constructDemo("hello");
}

输出将是:

hello

因此,如果我们明确定义了某些内容,Java 编译器会优先选择显式构造函数,否则它会打印出隐式构造函数。这里需要注意的关键点是它不会返回任何值,并且构造函数必须只使用类名来定义。

摘要

在本章中,我们运行了一些代码示例,以了解Date类、Calendar类以及构造函数的工作原理。

在本章中,我们将探讨三个关键字:superthis,并讨论finally块。

第八章:Java 中 super 和 this 关键字以及异常的重要性

在本章中,我们将探讨两个关键字:superthis。我们将挑选示例并解释在编写 Java 代码时如何在各种情况下使用它们。我们还将探讨异常以及如何使用它们来处理由于某些错误而导致代码失败的情况。我们将以关于finally块的章节结束本章。

在本章中,我们将涵盖以下主题:

  • super 关键字

  • super 关键字的实际用法

  • this 关键字的重要性

  • 不同类型的异常

  • try...catch 机制用于处理异常

  • Java 中 finally 块的重要性

super 关键字

通常情况下,当人们从不同的类继承属性时,如果在父类和子类中都使用了相同的变量名,可能会出现冗余。为了区分父变量和子变量,我们使用super关键字。

让我们用一个例子来解释这一点。让我们创建两个类,分别命名为childDemoparentDemo。在parentDemo类中,我们定义一个名为name的字符串,并将其赋值为'rahul'字符串。

现在,在childDemo类中,我们继承了parentDemo类的属性。我们知道如何使用extends关键字继承父类的属性,这是我们在第五章“关于接口和继承你需要知道的一切”中学到的。继承属性的代码如下:

public class childDemo extend parentDemo{

在此代码中,childDemo正在继承parentDemo的属性。

childDemo类中添加一个字符串,命名为name,并将其赋值为QAClickAcademy字符串。然后我们在childDemo类内部定义一个名为public void getStringdata()的方法,并给出一个打印name值的输出语句。我们还在getStringdata()方法外部定义另一个方法,命名为public static void main(String[] args),并创建子类childDemo的对象,childDemo cd = new childDemo();。一旦创建了对象,我们就在其下方添加另一行代码:cd.getStringdata();。这调用了getrStringdata()方法,所以显然输出的是name的值,即QAClickAcademy。尽管我们继承了parentDemo类的属性,该类也包含一个同名的字符串,但打印语句调用的是childDemo中的字符串值。这是因为 Java 优先考虑局部变量。

当父类和子类的变量名发生冲突时,它优先考虑局部变量,在这种情况下是childDemo类。如果我们正在处理一个需要同时在parentDemo类中打印字符串name的项目,该怎么办?为此,我们使用super关键字来引用parentDemo类,从该类继承属性到childDemo类。因此,如果我们想从parentDemo类中调用name变量,我们添加一个打印语句,并在我们想要打印的变量前添加一个super关键字——这将获取parentDemo的值。当我们现在运行代码时,我们得到父对象和子对象作为输出,因为我们已经在两个类中都留下了打印字符串name的语句。parentDemo类的代码如下:

public class parentDemo{
    String name= "Rahul";
    public static viod main (String[] args){
    }
}

childDemo类的代码如下:

public class childDemo extends parentDemo{

    String name = "QAClickAcademy";
    public void getStringdata();
    {
        System.out.println(name);
        System.out.println(super.name);
    }

    public static void main(String[] args){
    childDemo cd = new childDemo();
    cd.getStringdata();
    }
}

最终输出将是:

QAClickAcademy
Rahul

super 关键字的实际用法

在本节中,我们将探讨在 Java 中使用super关键字的多种方式。

使用方法中的 super 关键字

我们看到了如何借助super关键字处理父变量。在本节中,我们将看到如何处理在parentDemo类和childDemo类中名称相同的两个方法。我们也将在本节中使用之前的示例。

parentDemo类中,添加一个名为getData()的方法,并在方法内部添加一个打印语句以显示"I am in parent class"信息。如果我们想在childDemo类中执行getData()方法,我们在childDemo类的main方法中写cd.getData()。我们可以像继承parentDemo类的属性一样访问getData()。如果我们运行childDemo类,我们将收到之前示例的输出以及我们在parentDemo类中添加的新句子,即I am in parent class

childDemo类中,我们将定义另一个与parentDemo类同名的方法,并添加一个打印语句以显示I am in child class信息。如果我们运行childDemo类,我们将得到之前示例的输出,然后显示I am in child class。这是因为优先考虑局部类,所以childDemo类中的getData()方法覆盖了parentDemo类中的getData()方法。

现在,我们想在childDemo类中使用parentDemo类的getData()方法。为此,我们只需像处理变量那样做:在childDemo类的getData()方法中添加super.getData()。当我们运行childDemo()类时,我们将得到之前示例的输出,然后是I am in parent class,然后是I am in child class

使用构造函数中的 super 关键字

让我们在本节中使用super关键字来为构造函数。我们也将使用之前的示例。

parentDemo 类中,我们定义了一个构造函数,parentDemo(),并添加了一个打印语句来打印:父类构造函数

childDemo 中,我们定义了一个构造函数 childDemo() 并添加了一个打印语句来打印:子类构造函数。如果我们想在 childDemo 类中使用 parentDemo 类的构造函数,我们在 childDemo() 构造函数中添加 super() 方法。这使得控制器调用 parentDemo 类中的构造函数。

在使用构造函数时,我们需要遵循的一个重要规则是:在子构造函数中,每次使用 super 构造函数时,它都应该始终是其第一行。

当我们运行 childDemo 类时,控制器首先执行 super() 方法。它进入 parentDemo() 构造函数并执行它,然后是 childDemo()。所以最终的输出将是:

Parent class constructor
Child class constructor
QAClickAcademy
Rahul
I am parent class
I am in child class

this 关键字的重要性

在 Java 中还有一个与 super 关键字类似的关键字:this。在本节中,我们将探讨 this 关键字。

让我们用一个例子来解释 this 关键字。创建一个名为 thisDemo 的类,并声明一个变量 a,将其值设置为 2。我们在其类中定义一个 getData() 方法,在其中声明 a 变量,并将其值设置为 3。我们还在其中添加了一个打印语句。代码将如下所示:

package coreJava;public class thisDemo
{
    int a= 2;
    public void getData()
    {
        int a= 3;
        System.out.println(a);
    }

如我们所见,a 的值在整个类中都是 2,但在一个特定的方法 getData() 中,我们希望变量的值是 3。在这个代码中,我们想要调用 a 的两个值,即 23。我们在主方法中创建了一个对象,并将 td 对象添加到其中。td 对象的代码如下:

thisDemo td=new thisDemo();
td.getData();

如果我们运行代码,我们得到的输出是 3。但我们也想在同一个块中打印 a 的值为 2。这就是 this 关键字发挥作用的时候。类对象的范围将在类级别,而不是方法级别。因此,我们说 getData() 方法指的是当前对象,对象的作用域位于类级别。因此,a=2 对整个类有效,而 a=3 只对 getData() 方法有效。这就是为什么我们在 getData() 方法中调用 a 变量时称其为局部变量,而在类中的 a 变量称为全局变量。

为了打印我们正在工作的示例的全局变量,我们需要在 getData() 方法中添加一个打印语句,并在打印语句中添加 this.a。打印语句将如下所示:

System.out.println(this.a);

当我们运行代码时,我们得到以下输出:

3
2

这就结束了我们对 this 变量的示例。现在让我们学习异常。

不同类型的异常

在本节中,我们将探讨如何在 Java 中处理异常。

通常,如果代码中存在错误,我们需要捕获它并打印一条消息而不失败;这可以通过使用try...catch机制来完成。所以通常,当我们尝试编写代码并且怀疑其中可能存在错误时,我们将使用该错误进行异常处理。

我们将通过一个练习来解释它。让我们创建一个新的类,exceptionDemo,并在main块内部声明变量abc,并分别将470的值赋给它们。我们在main块内部添加一个try块,并声明一个整数变量k,它等于b除以c。每次我们在try块中添加任何内容时,我们都在尝试查看代码是否工作。如果它失败,控制器将退出这个try块并进入包含异常的catch块。一个需要记住的重要点是catch块紧随try块之后。在catch块内部,我们写入一个打印消息来显示我捕获了错误/异常

当控制器进入k变量行时,脚本会失败,因为7/0是无穷大,这是一个算术异常,但脚本不会立即失败。如果我们不写try...catch块,我们会看到不同类型的错误。

让我们移除try...catch块,运行代码,并查看我们得到的错误。我们在输出部分看到一个错误,Java.lang.ArithmeticException;这是因为我们不能将7除以0,所以脚本会突然失败。

如果我们一开始觉得我们的代码会出现错误,我们可以简单地编写一个脚本来传递和捕获错误,通过放置一个可以由try...catch机制处理的适当调试信息。现在,让我们再次添加try...catch块并调试整个代码。输出将会是我捕获了错误/异常;这是因为7除以0是无穷大,所以这里的脚本应该失败,但我们没有在输出部分看到代码失败的任何错误。这是因为控制器简单地移动到catch块并执行它。最终的代码将如下所示:

public static void main(String[] args)
{
    int b=7; 
    int c=0;
    try
    {
        int k=b/c;
        System.out.println(k);
    }
    catch(Exception e)
    {
        System.out.println("I caught the error/exception")
    }
}

输出将如下所示:

I caught the error/exception

处理异常的try...catch机制

在本节中,我们将使用一个try后跟多个catch块。Java 中有不同类型的异常,并且对于每个异常,我们都可以添加单独的catch块。

让我们用之前的例子来解释这一点。为之前的代码编写的异常是一个通用异常,所以对于try块中的任何错误,都会执行通用异常。现在让我们尝试捕获一个特定的异常。我们可以在try块下面添加一个catch块,并添加一个特定的异常和一个打印语句来打印我捕获了 Arithmeticerror/异常。特定catch块的代码如下:

catch(arithmeticException et)
{
    System.out.println("I caught the Arithmeticerror/exception");
}

当我们运行代码时,我们得到以下输出:

I caught the Arithmeticerror/exception

我们看到,当我们运行代码时,控制器进入了catch块,因为catch块是专门为算术异常编写的,而抛出的错误也属于算术错误。所以一旦控制器收到一个错误,try块将看到哪个catch块与之相关,并运行它。

Java 中还有许多其他的异常:我们只需在 Google 上搜索并查看它们。

Java 中finally块的重要性

还有一个与try...catch块类似的块:就是finally块。无论是否抛出异常,finally块都将被执行。如果程序运行成功,该块将被执行,即使程序没有运行。

我们将使用我们在处理异常的 try...catch 机制部分使用的示例来解释这一点。我们只是在catch块之后添加一个finally块,并在其中给出一个打印语句,说“删除 cookies”。代码块将看起来像这样:

finally
{
    System.out.println("delete cookie")
}

当我们运行代码时,我们得到以下输出:

I caught the Arithmeticerror/exception
delete cookie

一个重要的点是,finally可以与或不与catch块一起工作;它只需要写在try块下面。

摘要

在本章中,我们探讨了superthis关键字。我们还通过示例来解释我们可以在哪些情况下使用这些关键字来克服某些障碍。我们学习了异常,并在代码因错误而失败的各种实例中实现了它们。我们还学习了finally块。

在下一章中,我们将深入探讨集合框架,它由接口和类组成。我们还将查看三个主要的集合:ListSetMap

第九章:理解集合框架

在本章中,我们将深入探讨集合框架,该框架由接口和类组成。我们将查看三个主要集合:ListSetMap。本章将讨论来自List集合的ArrayList、来自Set集合的HashSet以及来自Map集合的HashMapHashTable。我们将通过查看示例来逐一介绍每个概念。

本章我们将涵盖以下主题:

  • 集合框架

  • 列表集合

  • 集合集合

  • 映射集合

集合框架

Java 集合框架基本上是一组接口和类的集合。为了高效编程或使用 Java 方法的灵活性,Java 设计了一个框架,该框架由不同的类和接口组成。集合框架有助于高效地存储和处理数据。这个框架有几个非常有用的类,它们提供了大量的有用功能,使得程序员的任务变得非常简单。

我们已经看到了许多关于数组和多维数组的概念。例如,在一个数组中,如果我们想从一个新的数组集中删除一个索引,我们可以使用集合框架来完成。假设在一个数组中有 10 个值,我们想删除第五个值,或者在第 5 个和第 6 个值之间插入一个值——在集合框架中,你将获得一些灵活的方法。

在接下来的章节中,我们将讨论这个集合框架中可用的方法类型,以及如何有效地使用它们。所以,为了给你一个概念,请记住,集合是一组类和接口。

我们将查看这个框架提供的集合。

列表集合

第一个集合是List集合/接口。列表是有序集合,有时我们也称其为序列。列表可以包含重复元素,就像数组一样,但数组与ArrayList之间有很多区别。你可以向这个List容器中插入多个值,它也可能包含重复元素。实际上,你可以从任何索引添加或删除任何值。比如说,你按顺序向列表中添加了 15 个元素,现在你想删除第 6 个元素,或者你想在第 10 个和第 11 个元素之间插入一个元素,或者你想知道一个元素在 15 个元素中的哪个索引。列表容器中有许多有用的 API 可以检索元素,而这些在数组中是得不到的。数组只能初始化;除此之外,你无法对数组执行任何方法,而使用ArrayList,你有很多灵活的方法可以操作。

List接口是一个集合,ArrayListLinkedListvector是实现了这个接口的三个类。这个接口提供了一组方法。它公开了一些方法,而这三个类在其类中使用这些方法。

在这三个中,让我们讨论一下ArrayList。这是最著名的一个,被大多数 Java 程序员使用。一旦你理解了ArrayList,你就可以轻松地了解LinkedListsvector。在下一节中,我们将创建一个ArrayList类并实现List接口中的方法,以查看这些方法在检索或组织数据时的灵活性。当你有一组数据在容器中时,你可以通过List接口轻松地组织这些数据。

ArrayList

让我们从ArrayList类开始,它实现了List接口。创建一个新的类,命名为arrayListexample。我们将首先查看ArrayList中存在的方法,然后我们将讨论数组和ArrayList之间的区别。

我们首先声明ArrayList如下。如果你在你的 IDE 中悬停在ArrayList上,你会看到一个建议告诉你导入java.util以使用ArrayList

package coreJava;

public class arrayListexample {

    public static void main(String[] args) {

        ArrayList a=new ArrayList();

    }
}

一旦你这样做,它仍然会显示关于ArrayList的建议,并且如果你悬停在它上面,它会建议添加参数类型。为了移除这个建议,你可以向ArrayList传递一个参数类型,例如IntegerString

        ArrayList<String> a=new ArrayList<String>();
        a.add("rahul");
        a.add("java");

在传递参数类型后,你可以通过使用a.轻松地添加一些字符串实例,它将显示ArrayList支持的不同类型列表。对于ArrayList,我们没有定义特定的数组大小,而当你看到数组时,我们明确地定义了大小。在数组中,一旦我们定义了大小,就不能增加或减少大小。但在ArrayList中,你可以随时从列表中添加或删除元素,它是一个动态大小的数组。这是数组和ArrayList之间最基本的区别之一。

如果我们想要打印这个ArrayList,我们可以简单地通过添加以下代码行来实现:

        System.out.println(a);

运行时,它将打印出[rahul, java]。但如果你想以数组的形式打印这个,我们需要写一个for循环。我们添加另一个对象,这次我们指定了字符串要放置的索引:

        a.add("rahul");
        a.add("java");
        System.out.println(a);
        a.add(0, "student");
        System.out.println(a);

当我们打印这个时,它会给出以下输出:

[rahul, java]
[student, rahul, java]

你可以看到,在第二行中,我们在列表中rahul之前添加了student,因为我们已经指定了它的索引为0

如果我们想要从列表中删除一个条目,我们可以通过添加以下几行代码来实现:

        a.remove(1);
        a.remove("java");

第一行代码将从列表的第一个索引处删除条目,而第二行将找到列表中的字符串并删除它。如果你想获取特定索引的条目,你可以使用get方法来实现:

       a.get(2);

上述代码行将打印出java作为输出,因为它是在索引2处的元素。

假设你有一个包含 50 个元素的列表,你需要找出特定的字符串/整数是否存在于该列表中。如果你使用数组,你必须创建一个for循环来找出元素是否存在,但在ArrayList中,我们有一个contains方法会为我们检查整个列表,并以truefalse的形式给出输出:

        System.out.println(a.contains("java"));

这将输出true,因为元素存在于我们的列表中;如果你将其更改为,例如testing,它将返回false,因为它不在我们的列表中。

ArrayList中另一个有用的方法是indexOf方法。如果我们想从列表中找到特定元素的索引值,我们可以通过使用indexOf来知道:

        System.out.println(a.indexOf("rahul"))

这将返回这个字符串的索引号。

现在,如果我们想检查数组是否为空,我们可以使用ArrayList中的isEmpty方法来做,它将返回truefalse

        System.out.println(a.isEmpty());

这将返回false,因为我们的列表不是空的。

ArrayList中最后一个且最重要的方法是size方法,它返回列表的长度:

        System.out.println(a.size());

关于ArrayList的另一件事是你需要知道的是,实现List接口的所有类都可以接受重复的值。我们知道在集合接口中扩展List的类:ArrayListLinkedListvector。并且所有这些类都可以接受重复的值。

ArrayList 的示例

假设我们有一个包含重复数字的数组,例如 {4, 5, 5, 5, 4, 6, 6, 9, 4},我们想要从这个数组中打印出唯一的数字,以及这个数字在这个数组中重复了多少次。我们的输出应该是“四个数字重复了三次,五个数字重复了三次,六个数字重复了两次,九个数字重复了一次。”

让我们把ArrayList的概念引入这里来解决这个谜题:

package demopack;
import java.util.ArrayList;
public class collectiondemo {
    public static void main(String[] args) { 
        int a[] ={ 4,5,5,5,4,6,6,9,4}; 
        ArrayList<Integer>ab =new ArrayList<Integer>(); 
        for(int i=0;i<a.length;i++) 
        { 
            int k=0; 
            if(!ab.contains(a[i])) 
            { 
                ab.add(a[i]); 
                k++; 
                for(int j=i+1;j<a.length;j++) 
                { 
                    if(a[i]==a[j]) 
                    { 
                       k++; 
                    } 
                } 
                System.out.println(a[i]); 
                System.out.println(k); 
                if(k==1) 
                    System.out.println(a[i]+"is unique number"); 
            } 
        } 
    }
}
ArrayList with the ab object type. Then we create a for loop, and within it we use an if loop with !ab.contains to check whether the element is present within the loop. We need another for loop within this if loop to iterate through the remaining part of the array. The if loop within this for loop will work as a counter for us to increment the number of times a number is repeated in the array.

我们已经完成了forif循环。我们打印出数组中的每个元素以及每个元素在数组中出现的次数。要打印唯一的数字,即不在数组中重复的数字,我们使用if循环并打印它。

这个例子就到这里了;你可以尝试用你自己的逻辑来编写这个例子。

集合的 Set

Java 中另一个重要的集合是Set集合/接口。HashSetTreeSetLinkedHashSet是三个实现Set接口的类。SetList之间的主要区别是Set不接受重复的值。SetList接口之间的另一个区别是,没有保证元素按顺序存储。

在本节中,我们将主要讨论HashSet。我们将举一个示例类来尝试理解这个概念。为这个部分创建一个类,命名为hashSetexample,并在类中创建一个对象以使用HashSet;它将建议你添加参数类型,在我们的例子中是String

package coreJava;

import java.util.HashSet;

public class hashSetexample {

    public static void main(String[] args) {

       HashSet<String> hs= new HashSet<String>();

    }
}

在你的集成开发环境(IDE)中,当你输入 hs. 时,它会显示 HashSet 提供的所有方法:

图片

首先添加一些重复条目的字符串实例:

        HashSet<String hs= new HashSet<String>();
        hs.add("USA");
        hs.add("UK");
        hs.add("INDIA");
        hs.add("INDIA");
        System.out.println(hs);

当你打印这个时,输出将如下所示:

[USA, UK, INDIA]

我们可以看到,对于 INDIA 的重复条目,HashSet 会拒绝并只显示一个实例。

如果我们希望删除任何对象,我们可以使用 remove 方法,要获取列表的大小,则使用 size 方法:

        System.out.println(hs.remove("UK"));
        System.out.println(hs.isEmpty());
        System.out.println(hs.size());

isEmpty 方法告诉我们列表是否为空——如果为空,它将返回 true,否则返回 false

使用迭代器

要遍历列表中存在的每个元素,我们使用 iterator 方法。我们需要为这个 Iterator 类创建另一个对象,以及 String 参数类型:

        Iterator<String> i=hs.iterator();

想象一下,我们有一组元素,并且它们从零开始按顺序排列,一、二、三等等。iterator 从零开始遍历每个元素,并打印出每个值对应的元素。我们为 iterator 创建了一个对象,并按以下方式打印值:

        System.out.println(i.next());
        System.out.println(i.next());

第一次调用 i.next() 将打印零索引处的值,下一次 i.next() 实例将打印一索引处的值。如果我们有一个包含大约 100 个值的集合,我们将不得不使用 while 循环:

        while(i.hasNext())
        {
            System.out.println(i.next());
        }

在这里,我们使用了 hasNext 方法,该方法检查集合中是否有下一个值。如果有下一个索引的值,它将返回 true,如果没有,则返回 false。在我们的例子中,它将返回 true 100 个值,然后返回 false,并退出 while 循环。

这就是如何使用 iterator 迭代 Set 接口中存在的对象。如果你在做自动化测试,比如 Selenium,你将频繁地使用这个 while 循环。

Map 集合

我们还有一个名为 Map 的集合。我们将举一个例子,并在编写代码的过程中讨论 Map。此接口以键值对的形式接受值。

我们创建一个类,hashMapexample,并在其中定义 HashMapHashMap 需要两种类型的参数,例如 IntegerString

package coreJava;

import java.util.HashMap;

public class hashMapexample {

    public static void main(String[] args) {

       HashMap<Integer, String> hm= new HashSet<Integer, String>();

    }
}

这里,Integer 是键,String 是值。现在,如果你在 IDE 中输入 hm.,你会看到 HashMap 中的一些方法;让我们使用 put 方法:

        hm.put(0, "hello");
        hm.put(1, "goodbye");
        hm.put(2, "morning");
        hm.put(3, "evening");

put 方法以键和值的形式接收输入。此外,键的值需要是整数,也可以是字符串。键只是我们为值定义的东西。我们可以使用 remove 方法删除值:

        hm.remove(2);

HashMap 中的 entrySet 方法以集合索引的形式存储每个键和值:

        Set sn= hm.entrySet();

我们现在已将这个 HashMap 转换为集合。要遍历这个集合的每个索引,我们使用 iterator,就像在前一个部分中一样,我们使用 while 循环:

        Iterator it= sn.iterator();

        while(it.hasNext())
        {
            Map.Entry mp=(Map.Entry)it.next();
            System.out.println(mp.getKey());
            System.out.println(mp.getValues());
        }

我们在这里需要使用 Map.Entry,因为每个索引中的元素都包含一个键和一个值,Map.Entry 帮助我们分离出键和值。当你打印这个 while 循环时,你应该得到以下输出:

0
hello
1
goodbye
2
morning
3
evening

不使用 Map.Entry,将会抛出错误。这就是 HashMap 的工作方式。

HashTable

还有一个名为 HashTable 的集合,但它与 HashMap 的操作方式相同。你只需要将 HashMap 改为 HashTable——就是这样。不过,HashMapHashTable 之间还是有一点细微的差别。

HashMapHashTable 之间的差异如下:

  • 同步或线程安全

  • 空键和空值

  • 迭代值

同步或线程安全

这是两者之间最重要的差异。HashMap 是非同步的,也不是线程安全的。那么非同步是什么意思呢?这意味着如果有多个程序同时访问 HashMap,它会持续更新。现在假设有五个线程在 HashMap 上工作。这意味着五个不同的程序或线程可以同时访问 HashMap,这意味着没有同步。但在 HashTable 中,如果一个程序正在访问 HashTable,其他程序需要等待第一个程序释放 HashTable 资源。这是主要差异。另一方面,HashTable 是线程安全的,也是同步的。你应该在什么时候使用 HashMap?如果你的应用程序不需要多线程任务——换句话说,HashMap 更适合非线程应用程序。HashTable 应用于多线程应用程序。

空键和空值

HashMap 允许一个空键和任意数量的空值,而 HashTable 不允许在 HashTable 对象中存在空键和空值。假设你正在将员工记录输入到数据库中,当你在数据库中上传员工详细信息时,也许你不知道他们的电话号码,但你可以现在在键值和索引值中输入一个名为电话号码的字段;你现在可以将其留为空;你可以在以后更新它。这在 HashMap 中是可行的,但当你在使用 HashTable 时,它将不允许任何空键和空值。如果你觉得你想让你的程序非常安全,并且你想阻止多个线程同时访问它,那么你应该选择 HashTableHashTable 是线程安全的,并且它不会在另一个程序完成对 HashTable 的操作之前释放其对象。

迭代值

HashMap 对象的值通过使用 iterator 进行迭代。除了 vector 类之外,HashTable 是唯一一个使用枚举器来迭代 HashTable 对象值的类。

HashMapHashTable 之间,操作是相同的,除了我们刚刚描述的三个差异。

摘要

在本章中,我们探讨了集合框架和三种类型的集合:ListSetMap。我们在List集合中探讨了ArrayList,并且还探讨了ArrayList的一个示例。Set集合与ArrayList不同——主要区别在于Set不接受重复的值。在最后一个集合,即Map集合中,我们看到了两种类型,HashMapHashTable,以及两者之间的区别。

第十章:final 关键字、包和修饰符的重要性

这是本书的最后一章。在这里,我们将处理一些更重要的概念,这将帮助我们编写和执行更好的代码。

在本章中,我们将探讨以下概念:

  • final 关键字

  • Java 中的修饰符

final 关键字

首先,我们将创建一个新的类。如果我们声明任何变量为 final,这意味着该值不能再更改。让我们考虑以下代码:

package coreJava;

public class finaldemo {

    public static void main(String[] args) {
        //TODO Auto-generated method stub
        final int i=4; //constant variables
    }
}

如您所见,我们已将整数值声明为 4。这意味着我们无法将此值更改为另一个数字。如果我们尝试这样做,它将抛出一个错误,表示 移除 'final' 修饰符的 'i'。如果我们想使一个值保持不变,这个关键字很有用。

如果我们将一个类标记为 final,它将抛出一个错误,因为当我们更改访问模式为 final 时,我们无法将其用作父类。换句话说,我们将无法从它继承属性。如果我们想继承属性,我们需要将其改回 publicfinal 关键字的逻辑是,一旦写入,我们就不能重写 final 方法。因此,这些是唯一的,不能再次使用相同的名称。

final 关键字可以在方法级别使用,以确保该方法不会被重写。在变量级别使用,以确保我们不会更改它,并且它也可以在类级别使用,以确保我们不会继承那个父类。

但请记住不要混淆 finalfinallyfinallytry...catch 异常有关。一旦执行了 trycatch 块,并前置任何错误,无论脚本是否通过,控制器都会来到这个日志并执行代码。finally 是关于限制访问的,例如我们无法使用它,继承它,甚至更改其值。我们已经探讨了包,以及如何将包导入其他类。我们已经探讨了接口的继承、运行时多态、字符串等等。这一切都是关于关键字。

在下一节,我们将学习关于包的内容。

当为每个 Java 类编写脚本时,会自动出现一个预填充的行。它是 package coreJava。由于我们在 Java 中创建了一个包,并将所有 Java 类放入该 coreJava 包中,所以我们将其视为 package coreJava

包不过是类和接口的集合。例如,Java 自带一些内置包,如 java.lang;如果我们导入此包,只有在这种情况下,我们才能访问基本的基本方法,如 public static void main、整数或数组。所有这些类都来自这个 java.lang 包。定义包名很重要,因为没有它,我们无法访问包内存在的类。这是因为 java.lang 是默认包,并且它包含在 Java 编译器本身中。

我们还有一个包,java.util。我们在处理集合时使用了这个包;我们导入了java.util包。为了工作在ArrayList上,这个类位于java.util包中。因此,如果我们移除import java.util.ArrayList,它会抛出一个错误,因为它不属于java.lang。所有集合接口都来自util包。

但我们如何知道使用什么关键字?以下截图显示了如果我们悬停鼠标,Eclipse 会显示什么:

快速修复下拉菜单显示建议以纠正代码错误

我们正在导入java.util包。并且从那个包中,我们正在导入ArrayList类。它的语法将是:

import package.classname

在这里,我们在这个 Java 类中使用ArrayList的原因是因为我们知道ArrayList位于java.util包中。但在使用 Eclipse 时我们不需要记住它。当你只是将鼠标悬停时,它会建议我们导入包,我们只需点击它。它将自动导入那个特定的包。

HashSet从相同的util包中导入HashSet类。如果我们去HashMap,它会带来HashMap。因此,每当我们想要工作在某个测试上时,我们需要导入那个包或类。System.out.println()也只来自一个包,但它们来自java.lang,这是一个内置的编译器。这些都是在 Java 包内建。

同时,我们也可以定义一个用户定义的 Java 包。在这种情况下,所有我们的测试用例都在一个名为coreJava的不同包中。如果有人想使用我们的类,他们只需要运行import coreJava.classname

在下一节中,我们将查看public修饰符。

Java 中的修饰符

有四种类型的访问修饰符:

  • public

  • private

  • protected

  • default

我们在这里不会讨论理论,因为您可以在 Google 上找到它。我们需要一个实际的方法,即这些访问修饰符的确切使用位置,或者包的确切导入位置。每当我们在整本书中创建方法时,我们每次只是使用public并编写方法。其他三个访问修饰符的工作方式类似。

现在我们来尝试理解每个这些访问修饰符如何帮助我们。

default

如果我们没有提到任何访问修饰符,我们的 Java 类会自动认为它有一个default访问修饰符。如果是default,这意味着你可以在你的包中的任何地方访问这个方法。但如果你走出这个包,那么你将无法访问这个方法。即使我们将package.classname导入我们的新包中,如果我们没有将其指定为public,我们也将无法访问这个方法。如果你不指定它,那么默认情况下它认为它是一个default访问修饰符。default访问修饰符可以在包内任何地方访问,但不能在包外。

Packages部分,我们导入了这个包并尝试使用它。正如你在以下截图中所看到的,第 15 行出现了一个错误:

图片

快速修复下拉菜单,建议纠正代码中的默认错误

如果我们没有指定任何内容,我们就无法访问它,因此它与默认功能相同。这也适用于变量:

public class arrayListexample {
    // can accept duplicate values
    //ArrayList, LinkedList, vector- Implementing List interface
    //array has fixed size where arraylist can grow dynamically
    //you can access and insert any value in any index
    int i=5;

如我们所见,在前面的代码中我们声明了一个整数。然而,它不会是public的;它是default。因此,我们无法在包外访问这个变量。如果我们导入它,我们将能够访问类但不是方法。如果我们想要访问,我们必须将其写为public。那么public访问修饰符做什么呢?

public

在将方法或变量设置为public后,我们将能够在所有包中访问它。这意味着基本上是任何地方。对这个类这个包没有限制。前一个截图观察到的错误也会在我们将方法/变量设置为public时出现。

以下截图显示了我们将int值设置为public后的情况:

图片

快速修复下拉菜单,建议纠正代码中的公共错误

在下一个类中,我们将探讨privateprotected访问修饰符是什么。在这个之后还有两个更多的访问修饰符,让我们看看它们的作用。

private

如果我们将我们的方法或变量标记为private,那么我们无法在类外访问它们。它们不能在包外或同一类外被访问。如果我们想在我们的ArraysDemo示例中访问这个,我们无法做到。即使我们尝试这样做,也会抛出一个错误,如下一个截图所示:

图片

快速修复下拉菜单,建议纠正代码中的私有错误

这是因为,如果我们将任何方法或变量标记为private,我们就无法在特定类外访问它。除非我们将其更改为其他内容,否则它会抛出一个错误。这也适用于变量。

如果你想看到一个实时场景,比如说你正在支付并购买一个产品;所有的信用卡详情都会被当作private,因为它们不会在购买类之外被访问。如果它们可以被访问,那就是一个安全漏洞,对吧?所以为了使信用卡详情仅限于那个特定的类,开发者会将private变量赋予所有卡详情,这样其他类就不能使用它。即使他们使用了继承或导入了一个包,他们也无法访问那些敏感详情。还有很多实时场景;如果你正在开发测试框架,可能会有一些变量你不应该更改,并且始终将其保持为私有。

protected

如果我们将变量或方法定义为 private,我们只能在子类中访问它们。这意味着如果我们将其定义为 protected,那么无论哪个类继承父类,只有那些子类才能访问该方法,其他类则不能。这一点可以通过以下代码片段来理解:

protected void abc() {
    //TODO Auto-generated method stub
    System.out.println("Hello");
    }

defaultprotected 的区别在于,在 default 情况下,我们只能在同一个类包内访问一个类。即使是 protected,也能访问同一个包内的所有类,但它有一个额外的特性。这个额外的特性是指,如果我们想在其他包中访问它,只有继承父类属性的子类才能访问它。

同样的概念也适用于变量。

摘要

在本章中,我们学习了有助于我们理解包、修饰符和 Java 中的 final 关键字重要性的概念。

现在你已经阅读了所有章节,我希望你对这些概念有了更好的理解。

posted @ 2025-09-10 15:11  绝不原创的飞龙  阅读(15)  评论(0)    收藏  举报