理解Java中的数据类型

作为“写作换捐”计划的一部分,作者选择了自由开源基金会作为受赠方。

介绍

Java是一种静态类型的编程语言。这意味着当你创建一个变量时,你必须同时指定它的数据类型,也就是它所存储的信息的类型。这与动态类型的语言(例如PHP)形成了对比。使用动态类型的语言,你不需要指定变量的数据类型,这可能会让人感到轻松一些。

然而,了解数据类型并适当地使用它们可以让开发人员优化他们的代码,因为每种数据类型都有特定的资源需求。另外,如果你指定了一个数据类型并尝试存储一个不同类型的数据,例如出错时,你将无法编译代码。因此,在静态类型语言中,您甚至可以在任何测试之前就能够检测到错误。

Java拥有两种数据类型:原始类型和引用类型(也称为非原始类型)。在本教程中,您将使用变量来存储和使用Java程序中的信息,以了解Java中常用的一些数据类型。这并不是对所有数据类型的详尽概述,但本指南将帮助您熟悉Java中可用的选项。

先决条件

请参照本教程,您需要准备以下物品:

  • An environment in which you can execute Java programs to follow along with the examples. To set this up on your local machine, you will need the following:Java (version 11 or above) installed on your machine, with the compiler provided by the Java Development Kit (JDK). For Ubuntu and Debian, follow the steps for Option 1 in our tutorial, How To Install Java with Apt on Ubuntu 22.04. For other operating systems, including Mac and Windows, see the download options for Java installation.
    To compile and run the code examples, this tutorial uses Java Shell, a Read-Evaluate-Print Loop (REPL) run from the command line. To get started with JShell, check out the Introduction to JShell guide.
  • Familiarity with Java and object-oriented programming, which you can find in our tutorial, How To Write Your First Program in Java.

原始类型

Java的基本类型是Java中最简单和最基本的数据类型。它们代表原始值,如数字和字符。最常用的基本数据类型包括int(整数)、boolean(布尔值)和char(字符)。您可以在官方的Java数据类型文档中找到其他类型。

整数

整数既可以是负数也可以是正数的整数。在Java中,你将使用int来存储它们。int可以容纳足够大的数字来满足大多数目的:从-2,147,483,648到2,147,483,647。

让我们来看一个使用int的例子:

int theAnswer = 42;

原始类型总是以小写字母开头(int)。Java 语法规定您首先要指定数据类型(int),然后是变量名称(theAnswer)。此后,您使用等号(=)将值42赋给该变量。

无论其数据类型如何,您都可以直接通过指定变量名来使用变量,而不需要在前面添加任何特殊字符。这是因为Java可以将其识别为变量。

Note

注意:变量theAnswer的名称以及本教程中的所有其他变量都采用驼峰命名法。尽管没有严格要求使用它,但这是Java中被广泛接受的命名规范。

一旦你声明了变量,你可以在方法中通过引用来使用它。

int theAnswer = 42;
System.out.println("The answer to all questions is " + theAnswer);

在第二行中,你可以使用内置的方法println来将theAnswer打印到console控制台中,该方法来自于System.out这个包。这是测试一个变量是否按预期声明的最简单的方法。

要查看此代码的运行情况,请使用Java Shell工具。安装Java后,在本地计算机上打开一个终端或命令提示符,然后键入jshell。

  1. jshell

 

您的输出将与以下内容相似:

Output

| Welcome to JShell — Version 11.0.16 | For an introduction type: /help intro jshell>

你可以将这个教程中的代码示例粘贴到控制台中。完成后,你可以通过输入/exit命令退出jshell。

要声明和使用 int,在 jshell 控制台中粘贴下面的代码行:

  1. int theAnswer = 42;
  2. System.out.println(“The answer to all questions is “ + theAnswer);

 

您将会看到以下的输出结果:

Output

theAnswer ==> 42 The answer to all questions is 42

这个输出证实你正确地将int类型的变量theAnswer设置为42(theAnswer ==> 42)。你还成功地通过将theAnswer传递给一个方法来使用它,而该方法输出了预期的变量值。

布尔值

布尔值可以是真或者假。在Java中,你可以使用布尔类型来存储它们。例如,让我们创建一个布尔变量来判断Java是否有趣:

boolean isJavaFun = true;

你将变量isJavaFun定义为true。另一个布尔值的选择是false。

使用上述变量,你可以通过以下方式打印出句子“Java很有趣:真”。

  1. boolean isJavaFun = true;
  2. System.out.println(“Java is fun: “ + isJavaFun);

 

在jshell中运行这些代码将产生以下输出:

Output

isJavaFun ==> true Java is fun: true

与int示例类似,println方法会打印括号中提供的参数。加号(+)将字符串”Java很有趣:”与变量isJavaFun连接起来,实际上只是一个参数 – 字符串”Java很有趣:true”。

为了存储一个单个的字母数字字符,你可以使用char。例如:

char firstLetter = 'a';

注意到字母a被单引号包围。单引号只能用于字符值。而双引号则用于字符串,这将在后面学到。

char这种类型似乎不是特别有用,因为你不太可能需要将变量分配给一个单个字符。然而,char被用作字符串类(例如String)的构建块,而这些类基本上是char值的集合。

正如你在本节中所看到的,原始类型变量的声明和使用是直观的,因为它们表示简单的值,如整数。这些值可以直接使用,无需进行额外的操作,比如创建对象、调用方法等等。

参考类型

在这个系列的第一个教程中,你学到了Java代码是以类为组织单位的,这些类被用作创建对象的模板。当这些对象被分配给变量时,你是在指向或引用这些对象。在这些情况下,这些变量被称为引用类型。这些变量也被称为非基本类型,因为基本类型变量不能指向对象。

物体是强大的,因为它们具有先进的属性并且能够在触发它们的方法时进行操作。然而,如果没有指向这些物体的变量,这些物体就无法访问且几乎无法使用。这就是为什么引用类型变量对于Java和面向对象编程来说是至关重要的。

Note

注意:引用类型指的是从类创建的对象。为了避免混淆,以下示例中的引用类型和创建的对象将是相同的类。
然而,在复杂的程序中,这种情况很少发生。在Java中,接口是对特定行为的要求组,这些要求可以由一个或多个类来满足。满足接口要求的类被称为实现了该接口。因此,在复杂的程序中,常常使用接口的引用类型来声明变量。这样,您可以指定变量应该展示的行为,而无需将其与具体的行为实现绑定在一起。这使您能够轻松更改变量指向的实现方式,而无需更改变量的使用方式。这个复杂的概念是继承和多态性更高级话题的一部分,将在我们的Java系列中进行单独的教程。

虽然原始类型只有几种,但引用类型几乎没有限制,因为类(和接口)的数量没有限制,每个类代表一个引用类型。Java中有许多内置类提供基本功能。最常用的类可以在核心java.lang包中找到。在本节中,您将会对其中一些进行复习。

字符串类

字符串类表示由字符组成的字符串的组合。要声明一个字符串或任何其他引用类型变量,首先要指定其类型,然后是变量名称。在此之后,您可以使用等号为其赋值。到目前为止,它与使用基本类型类似。然而,引用类型指向对象,所以如果尚未创建对象,则必须创建对象。以下是一个例子:

String hello = new String("Hello");

你好是一个具有引用类型String的变量名。你将它分配给一个新的String对象。新的String对象是使用new关键字和类名String创建的。String类以大写字母开头。按照约定,所有类和因此引用类型都以大写字母开头。

每个类都有一个特殊的方法叫做构造函数,用于创建新的对象。可以通过在类名后面加上括号()来调用该构造函数。构造函数可以接受参数,就像上面的示例中,参数”Hello”被应用于String类的构造函数。

为了确认hello变量的行为是否如预期一样,可以将它再次传递给println方法,像这样操作:

  1. String hello = new String(“Hello”);
  2. System.out.println(hello);

 

在jshell中运行这些代码将产生以下输出:

Output

hello ==> “Hello” Hello

这次输出确认变量hello被设置为“你好”。之后,同一个“你好”被打印在新的一行上,确认了println()方法已处理它。

封装类

在上一节中,你使用了频繁使用的String引用类型。其他常见的引用类型是所谓的原始类型包装器。包装器类包装或包含原始数据,因此得名。所有原始类型都有包装器对应类,以下是一些例子:

  • Integer: To wrap int values.
  • Character: To wrap char values.
  • Boolean: To wrap boolean values.

这些包装器的存在是为了将简单的原始值升级为功能强大的对象。每个包装器都有与其设计用于存储的值相关的现成方法可供使用。

举个例子,你将要探索整数。在前面一节中,你使用new关键字创建了一个字符串对象。然而,有些类提供甚至鼓励使用特殊方法来获取对象,而Integer就是其中之一。在整数的情况下,使用特殊方法主要是为了资源优化,但在其他情况下,可能是为了简化复杂对象的构造。

在下面的示例中,您可以使用valueOf方法创建一个名为theAnswer的整数变量,并将其值设置为42。

  1. Integer theAnswer = Integer.valueOf(42);
  2. System.out.println(theAnswer);

 

在jshell中,你将获得以下输出:

Output

theAnswer ==> 42 42

通过调用Integer的valueOf(42)方法,你指示Java给你一个具有这个值的对象。在幕后,Java会检查它的缓存中是否已经有一个具有这个值的对象。如果有,那么这个对象将与theAnswer变量关联起来。如果没有,将为theAnswer变量创建一个新的对象。

出于性能考虑,许多内置类提供了这些方法,并且如果不是强制要求,也建议使用它们。在Integer的情况下,您仍然可以使用new关键字创建对象,但是会收到一个弃用警告。

除了String和包装类之外,还有其他一些有用的内置引用类型可以在java.lang包概述中找到。要完全理解这些更高级的引用类型,需要额外的解释或先前的知识。这就是为什么我们将在我们的下一个Java系列教程中介绍其中一些的原因。

字面的

字面值代表可以直接在代码中使用的固定值,因此可以分配给原始类型和引用类型。有几种类型的字面值,可以按以下方式进行分类。

原始类型字面量

你已经在原始类型的部分中使用了一些字面值。对于每种原始类型,都有相应的字面值,例如我们的例子中的42,’a’和true。像42这样的整数被称为整数字面值。同样,像’a’这样的字符被称为字符字面值,而true和false被称为布尔字面值。

原始类型字面量也可以用来创建引用类型的值。使用int字面量创建了一个Integer对象,并且使用代码Integer.valueOf(42)。还有一种简化的方法,可以直接赋值给变量,如下所示:

Integer theAnswer = 42;

42 是一个整型字面值,就像任何其他整数一样,你可以将其直接赋值给theAnswer变量,无需任何其他语句。这种声明整数的方式很常见,因为它很方便。

这种速记方法对于其他基本类型字面值以及它们对应的引用类型(例如布尔值)也同样适用。

Boolean isFun = true;

true 是字面量,直接赋值给了类型为 Boolean 的 isFun 变量。也有一个 false 字面量,可以以同样的方式赋值。

字符串字面量

还有一个特殊的字面值可以用于字符串引用类型,通过双引号括住其值来识别。在这个例子中,它的值是“你好,世界!”

String helloWorld = "Hello, World!";

使用字面量更简单和更短,这就是许多程序员的首选。然而,在引用类型的部分中,您仍然可以声明一个新的String对象的String变量,就像您已经做过的那样。

“空值字面量”

还有一个重要的文字,就是null,它代表了值的缺失或对象的不存在。null允许您创建一个引用类型并将其指向null,而不是指向一个对象。null可以用于所有引用类型,但不能用于任何基本类型。

在使用空字面值时有一个注意事项:你可以用它来声明变量,但是在重新赋值一个适当的、非空的值之前,你不能使用这些变量。如果你尝试使用一个具有空值的引用类型变量,你会遇到错误。这里有一个例子:

  1. String initiallyNullString = null;
  2. System.out.println(“The class name is: “ + initiallyNullString.getClass());

 

当您尝试在jshell中运行此代码时,您将看到类似于以下错误的错误提示:

Output

initiallyNullString ==> null | Exception java.lang.NullPointerException | at (#4:1)

根据您的操作系统和Java版本,您的输出可能会有所不同。

因为您试图在最初为空的对象 initiallyNullString 上调用返回类名的 String 方法 getClass(),所以抛出了 java.lang.NullPointerException 错误。

Note

请注意:为了简化,我们将java.lang.NullPointerException称为错误,尽管从技术上讲它是一个异常。要了解更多关于异常和错误的内容,请查看Java教程中的异常处理部分。

要解决这个错误,你需要像这样重新赋值initiallyNullString的值。

  1. String initiallyNullString = null;
  2. initiallyNullString = “not null any longer”;
  3. System.out.println(“The class name is: “ + initiallyNullString.getClass());

 

新的修复过的代码将打印出以下输出:

Output

initiallyNullString ==> null initiallyNullString ==> “not null any longer” The class name is: class java.lang.String

以上输出显示了initiallyNullString最初为null,然后变成了一个包含”不再是null”的新字符串对象。接下来,当在实例化对象上调用方法getClass()时,你会得到java.lang.String,其中String是类名,java.lang是它的包名。最后,打印出一个完整而有意义的消息:”类名是:class java.lang.String”。

这种对空值的声明在旧代码中更常见。它们被用来先创建一个变量,然后在稍后分配它的真实值,通常通过一些确定后者的逻辑。然而,自从Java 8版本之后,引入了一种名为Optional的新的引用类型,对于之前使用null的情况更加合适。

局部变量类型推断

到目前为止,您一直在使用Java中的一些常见数据类型来定义变量。然而,Java 10引入了一项名为本地变量类型推断的新功能,允许您在新变量前使用关键字var。通过这个功能,Java将从本地上下文中推断(也就是自动猜测)数据类型。类型推断存在争议,因为它与先前解释的变量定义的冗长形成对比。这种功能的优缺点是有争议的,但事实是,其他静态类型语言,如C ++,支持类型推断。

无论如何,类型推断无法完全取代数据类型的使用,因为它仅适用于局部变量,即方法内的变量。让我们以一个var的示例来看一下。

  1. var hello = “Hello”;
  2. System.out.println(hello);

 

你使用var关键字声明变量hello,以便指示Java检测其数据类型。之后,你以通常的方式将其打印到控制台中,以确认它按预期工作。

Ouput

hello ==> “Hello” Hello

只要你的Java安装(更具体地说,是JDK)在10版本以上,这个示例就会运行。旧版本不支持var关键字。

类型推断发生在编译过程中,也就是在你编译代码之时。编译过程将纯文本源代码转换为机器代码,并应用各种优化,包括类型推断。这确保了有足够的系统内存供类型推断的变量使用。因此,编译后运行的机器代码是完全优化的,就像你手动指定了所有的数据类型一样。

在这个例子中,var关键字能够工作是因为变量是局部的,并且var数据类型仅适用于局部变量。局部变量是在方法内定义的,只能在方法内部访问,这就是为什么它们被称为“局部”的原因。

为了展示var只能用于局部变量,试着将其放在main方法外面,像这样:

  1. public class Hello {
  2. var hello = “Hello”;
  3. public static void main(String[] args) {
  4. // example code
  5. }
  6. }

 

当你将上述代码粘贴到jshell中时,你会得到以下错误信息:

Output

| Error: | ‘var’ is not allowed here | var hello = “Hello”; | ^-^

由于hello在方法之外,不再被视为局部变量,所以不允许使用var。因此,非局部变量不适用于类型推断,因为上下文无法可靠地用于检测数据类型。

虽然使用var可能具有挑战性且不是必须的,但你很可能会遇到它,所以了解它很有用。

保留关键词

在Java中声明变量时,还有一个重要的规则需要知道。有一些保留关键字是你不能用于变量名的。例如,你不能像这样声明类型为int的原始数据类型并将其命名为new。

  1. int new = 1;

 

如果你尝试这个例子,你会因为new是一个保留关键字而得到编译错误。

Output

| Error: | ‘.class’ expected | int new = 1; | ^ | Error: | <identifier> expected | int new = 1; | ^ | Error: | ‘(‘ or ‘[‘ expected | int new = 1; | ^ | Error: | unexpected type | required: value | found: class | int new = 1; | ^–^ | Error: | missing return statement | int new = 1; | ^———-^

关键字new用于创建新对象,而Java不希望它出现在这个位置。在先前输出的错误列表中,第一部分是最重要的。

Output

| Error: | ‘.class’ expected | int new = 1; | ^

错误“.class”表示,当你使用new关键字时,Java期望后面接一个类。在这一点上,Java无法解释该语句,随后出现了其他错误。

其余的保留关键字,如abstract、continue、default、for和break,在Java中也有特定的意义,不能用作变量名。完整的保留关键字列表可以在Java语言关键字页面找到。即使您不记得所有保留关键字,您可以通过编译错误来识别问题。

结论是

在本教程中,您学习了Java中的基本数据类型和引用数据类型,这是一个复杂但必要的话题。花点时间练习并多次查看示例。尝试更改一些数据类型和数值。注意错误何时被抛出以及何时不被抛出,以培养对成功代码执行的感知。

要了解更多关于Java的内容,请查看我们的《Java编码系列教程》。

发表回复 0

Your email address will not be published. Required fields are marked *


广告
将在 10 秒后关闭
bannerAds