三、Java 语法基础

1 标识符

1.1 什么是标识符

标识符就是变量名、常量名、方法名、类名等由程序员自己决定的名字

让我们回顾一下我们写过的第一个 Java 程序。

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

在这段程序中, Hello 是类名, main 是方法名,都是标识符。

1.2 标识符命名规则

标识符命名是由程序员自己决定的,但需要遵守一定的规则。

  1. 构成标识符的字符只能是字母、数字、下划线(_)、美元符($),不限长度。

    中文等 Unicode 字符也可以,但不推荐

    美元符($)在某些情况下,自动生成的代码中会出现,自己确定标识符时,应尽量避免使用。

  2. 首字符不可以是数字。

  3. 标识符区分大小写。MyNamemyName 不是同一个标识符。

  4. 关键字和保留字不能直接做标识符。

1.3 关键字和保留字

关键字是 Java 语言中,有特定语法含义的词

如果程序员自己命名的标识符,与关键字相同,那么,Java 解释器就不能判断究竟应该把这个词作为有意义的关键字解释,还是仅仅将它作为一个名字(标识符)来解释。因此,关键字不能直接作为标识符(标识符可以包含关键字)。

其中,constgoto 并没有语法含义,但觉得它们可能会有用,因此保留在了关键字中。因此,它们被称为 “保留字” 。

abstract

continue

for

new

switch

assert

default

goto

package

synchronized

boolean

do

if

private

this

break

double

implements

protected

throw

byte

else

import

public

throws

case

enum

instanceof

return

transient

catch

extends

int

short

try

char

final

interface

static

void

class

finally

long

strictfp

volatile

const

float

native

super

while

truefalsenull看起来像是关键字,但它们实际上是字面量。我们不能将它们用作程序中的标识符。

不需要专门区记忆关键字。大部分关键字我们都会在之后的课程中学到,而且如果你输入的自定义标识符是关键字,编辑器会直接报错。

1.4 标识符命名规范

上面,我们提到了标识符的命名规则,但这仅仅是变量命名时的最低标准,仅仅可以让我们的代码,可以通过编译器的编译,可以正常运行。

但在真实情境中,我们一般不会是一个人完成一个程序的开发,我们需要与团队进行合作,那么代码可以轻松被其他人读懂,也就是代码具有可读性,是非常重要的

即使我们真的在进行一个人的程序开发,如果我们的代码不具有可读性,那么,就连我们自己,也将很难再次看懂自己的代码。

要使代码具有良好的可读性,就要做到标识符 “见名知意” ,同时遵守一定的命名规范

2 变量

我们的第一个程序,仅仅是在屏幕上显示了一段文字,而这样的程序是没有什么意义的,如果我们想在屏幕上显示文字,为什么我们不直接打开记事本呢?

程序出现的意义,就在于要利用计算机强大的计算能力来处理数据

要让计算机对数据进行处理,就必须把需要处理的数据先存放在计算机的内存当中。因而每一个数据在计算机中都会有一个存放空间,在计算机编程中,我们把这些存放数据的空间称为变量(Variable)。

我们可以把计算机内存想象成为一幢拥有很多很多单人小房间的大楼,每一个数据都存放在一个房间中,而且一个房间内只能存放一个数据。这些房间可以分为两类:

  • 有一些房间内只要存放一个数据以后,从开始到结束(程序运行过程)一直存放着的都是这一个特定的数据,这些存放的数据不会改变的房间就是常量,即:不变的变量

  • 更多房间内存放的数据会经常改变,开始时(程序运行之初)存放的是一个数据,过一段时间(程序运行中)又换成了另一个数据,结束时(程序运行结束时)存放的也许又换了一个数据,这些存放的数据经常会变化的房间就是变量

往变量中存放数据(值)的操作我们称之为赋值(或代入),程序中首次向变量中代入数据(值)称为变量初始化,变量可以在定义的同时进行初始化。在 Java 中,我们使用 = 来完成赋值操作, = 被称为 “赋值符号” ,作用是将右侧的值赋值给左侧变量

在 Java 语言中,我们可以使用如下代码来创建变量:

// 数据类型 变量名 = 数据值;
char score = 'A';
// 也可以把声明变量和为变量赋值的操作分开
int num;
num = 5;
// 在数据类型前加上 final ,就变成了创建常量,为了和变量区分,常量名往往使用区别大写字母。常量只能被赋值一次。
final int AGE = 18;

这两行代码的作用,如图所示:

变量就是存放数据(值)的小房子.gif一个变量中只能存放一个数据(值)。如果变量中已经放入了一个数据(值),当把一个新的数据(值)再次放入这个变量中时,新数据(值)就会替代原先存放在该变量中的数据(值),原先存放的数据(值)就会消失。

当我们运行如下代码:

int num = 5;
num = 7;

代码的效果,如下图所示:

赋值操作.gif如上所述,变量就是存放数据(值)的小房子。为了区分这些存放不同数据(值)的小房子,我们需要给每个小房子安排一个唯一的房间名,这个唯一的房间名就是变量名。变量通过变量名区分,不同的变量有不同的名称。知道了变量名,就可以知道变量中存放着的数据(值)是什么。

3 数据类型

我们已经知道,变量是用于存放数据的单人房间,而这个房间还有一个特点,就是这是一个单一功能的房间,它里面只能入住在定义时允许入住的那一种数据(值),其他类型的数据(值)是不能入住的

大家可能注意到了,我们在变量的讲解中,使用到了 intchat 两个关键字,这两个关键字就是用来声明数据类型的。

// 数据类型 变量名 = 数据值;
int num = 5;
char score = 'A';

变量中只能赋值与其数据类型一样的数据值.gif在 Java 语言中,数据类型分为两大类:

  • 基本数据类型

    指的是在变量这个小房间里,存放的数据,是这个数据本身。

  • 引用数据类型

    有时候,我们需要的数据,并不是单一的数据值,而是几个数据值组合成的复杂数据。

    比如每一名 “学生” 的数据,其中包含 “姓名” 、“性别”、“身高”、“体重” 等数据。

    像这样由若干(可以仅仅是 1)数据组成的复合数据,就不能直接放在基本数据类型那样的小房间中,这时候就需要 引用数据类型 登场了。

    在引用数据类型的变量这个小房间中,存放的是一个地址,计算机可以在这个地址找到若干其他小房间,这些小房间中存放着组成引用数据类型变量的每一项数据。(如果组成部分也是引用数据类型,那么小房间中可以是另一个地址。例如:“学生” 变量中包含 “成绩” 变量,“成绩” 变量又包含 “数学成绩” 、“语文成绩” 等)

3.1 基本数据类型

Java 编程语言支持的八种基本数据类型是:

  • bytebyte 数据类型是 8 位有符号二进制整数。它的最小值为 -128,最大值为 127(含)。字节数据类型可用于在大型数组中节省内存,因为节省内存实际上很重要。

  • Shortshort 数据类型是 16 位有符号二进制整数。它的最小值为 -32,768,最大值为 32,767(含)。与 byte 字节数据类型一样,short 数据类型的使用准则也是相同的:在节省内存的情况下,可以使用 short 数据类型来节省大型数组的内存

  • int:默认情况下,int 数据类型是 32 位有符号二进制整数,其最小值为 -231,最大值为 231-1。在 Java SE 8 及更高版本中,您可以使用 int 数据类型表示无符号 32 位整数,其最小值为 0,最大值为 232-1。使用 Integer 类将 int 数据类型用作无符号整数。

  • longlong 数据类型是 64 位二进制整数。有符号 long 的最小值为 -263,最大值为 263-1。在 Java SE 8 及更高版本中,可以使用 long 数据类型表示无符号 64 位 long,其最小值为 0,最大值为 264-1。当您需要的数值范围大于 int 所提供的范围时,请使用该数据类型。

  • floatfloat 数据类型是单精度 32 位 IEEE 754 浮点。它的取值范围超出了本文的讨论范围。与对字节和 short 的建议一样,如果需要在大型浮点数数组中节省内存,请使用 float(而不是 double)。这种数据类型绝对不能用于精确数值,如货币。如果要记录精确小数,需要使用 java.math.BigDecimal 类。

  • doubledouble 数据类型是双精度 64 位 IEEE 754 浮点。它的取值范围超出了本文的讨论范围。对于十进制值,该数据类型通常是默认选择。和 float 相同,这种数据类型也不能用于精确值,如货币。

  • boolean:布尔数据类型只有两个可能的值:真和假。这种数据类型适用于只用两种取值的数据,例如普通电灯的开关。这种数据类型代表的数据,只需要 1 位二进制数即可表示,但其真实大小并没有精确定义。

  • charchar数据类型是单个 16 位 Unicode 字符。它的最小值为'\u0000'(或 0),最大值为'\uffff'(或 65,535,含)。

除了上面列出的八种基本数据类型之外,Java 编程语言还通过 java.lang.String 类提供对字符串的特殊支持。将字符串括在双引号内将自动创建一个新String对象;例如,String s = "this is a string";. String对象是不可变的,这意味着一旦创建,它们的值就不能更改。从技术上讲,该类String不是基本数据类型,但考虑到该语言给予它的特殊支持,您可能倾向于将其视为基本数据类型。

3.2 引用数据类型

现阶段,我们最常用的引用数据类型是String ,我们之后会遇到其他引用数据类型。

4 数据类型的默认值

在声明变量时,并不一定需要赋值。已声明但未初始化的字段将被编译器设置为合理的默认值。一般来说,基本数据类型的默认值为 0 ,引用数据类型的默认值为 null 。不过,依赖默认值通常被认为是不好的编程风格。

下图总结了上述数据类型的默认值。

数据类型

默认值

byte

0

short

0

int

0

long

0L

float

0.0f

double

0.0d

char

'\u0000'

String (或其他引用数据类型)  

null

boolean

false


需要注意的是,我们现在接触到的变量一般都是局部变量(本概念之后介绍)。编辑器不会为局部变量设置默认值,直接使用未初始化的局部变量,会导致报错编译错误。

5 字面量

我们把直接出现在代码中的数据值,成为 “字面量”(Literals) 。

我们之前在创建和初始化变量时,= 右侧放的就是字面量。那么这些字面量的类型是什么?是与左侧数据类型相同吗?

我们可以尝试在 IDEA 中输入以下代码:

float f1 = 0.1;

此时,IDEA 会提示本行代码存在错误:需要的类型为 float ,但提供的类型是 double

由此我们可知,字面量的数据类型,并不是根据左侧变量数据类型决定的

5.1 整数字面量

byteshortintlong 整数类型的值可以由 int 字面量创建。超过 int 范围的 long 类型值可以由 long 字面量创建。

如果一个整数字面量以字母 Ll 结尾,它就是 long 类型;否则就是 int 类型。建议使用大写字母 L,因为小写字母 l 与数字 1 很难区分。

一般情况下,我们只会用到十进制数。不过,如果需要使用其他数字系统,下面的示例显示了正确的语法。前缀 0x 表示十六进制,0b 表示二进制:

// 十进制 26
int decVal = 26;
// 十六进制 26
int hexVal = 0x1a;
// 二进制 26
int binVal = 0b11010;

5.2 小数字面量

如果浮点字面量以字母 Ff 结尾,则其类型为 float;否则,其类型为 double,并可选择以字母 Dd 结尾。

浮点类型(float 和 double)也可以用 Ee 来表示需要使用科学计数法。

double d1 = 123.4;
// 值与 d1 相同,但使用了科学计数法。
double d2 = 1.234e2;
// 使用字面量给 float 变量赋值时,必须使用 f 结尾。
float f1  = 123.4f;

5.3 数字字面量中的下划线

在 Java SE 7 及更高版本中,数字字面量中的数字之间可以出现任意数量的下划线字符 (_)。例如,利用这一功能,您可以分隔数字文字中的数字组,从而提高代码的可读性。

long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi =  3.14_15F;

5.4 字符和字符串字面量

charString 类型的字面量可以包含任何 Unicode (UTF-16) 字符。如果编辑器和文件系统允许,可以直接在代码中使用这些字符。如果不允许,可以使用 "Unicode 转义符",如 "\u0108"(大写 C,带圆括号)或 "S\u00ED Se\u00F1or" (西班牙语中的 Sí Señor)。对于字符字面量,始终使用 "单引号",对于字符串字面量,始终使用 "双引号"。

Java 编程语言还支持一些用于 charString 字面量的特殊转义序列:\b(退格)、\t(制表符)、\n(换行)、\f(换页)、\r(回车)、\"(双引号)、\'(单引号)和\\(反斜杠)。

对于 String 类型来说,存在一个特殊字面量 nullnull 可以被赋值给任何引用数据类型,代表着这个房间里没有任何住户。

5.5 布尔类型字面量

对于 boolean 类型来说,只存在两种字面量,true(真)和 false(假)。

6 变量赋值操作

我们之前使用赋值操作时,= 的右侧,放的都是字面量,但实际上,只要 = 右侧可以得到一个与左侧变量类型相同的值,那么赋值操作就可以实现。

当我们执行如下代码:

public class Hello {
    public static void main(String[] args) {
        int A = 10;
        System.out.println(A);
        A = 10 + 8;
        System.out.println(A);
        int X = A;
        System.out.println(X);
        int Y = A + 2;
        System.out.println(Y);
    }
}

计算机实际执行效果如下:

通过赋值语句向变量赋值.gif

7 交换两个变量的值

本课的最后,让我们用一个经典题目——“交换两个变量的值” 来检验一下,我们对变量的理解是否正确。

public class Hello {
    public static void main(String[] args) {
        int A = 18;
        int B = 10;
        // 编写代码,使输出结果顺序为 10、18
        
        System.out.println(A);
        System.out.println(B);
    }
}

此时,大家想到的做法是怎样的呢?像下面这样吗?

public class Hello {
    public static void main(String[] args) {
        int A = 18;
        int B = 10;
        // 编写代码,使输出结果顺序为 10、18
        A = B;
        B = A;

        System.out.println(A);
        System.out.println(B);
    }
}

很可惜,我们得到的结果为 10、10 。让我们看看发生了什么。

无法正确交换变量的值的算法描述.gif正确代码如下:

public class Hello {
    public static void main(String[] args) {
        int A = 18;
        int B = 10;
        // 编写代码,使输出结果顺序为 10、18
        int C = A;
        A = B;
        B = C;

        System.out.println(A);
        System.out.println(B);
    }
}

流程如下:

利用临时变量正确交换变量的值.gif

本文部分素材来源:

  1. www.54benniao.com

  2. https://docs.oracle.com/javase/tutorial/java/TOC.html