暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

2、Java 基础语法

编码逻辑 2021-08-27
273

本小节我们将介绍 Java
语言的基础语法,包括我们在编写第一个 Java
程序时已接触过的类、主方法的概念,以及在编程中给源代码文件和类起名字的时候应该注意什么,什么样的名字是可以使用的,什么样的名字是不可以使用的,还有如何为代码添加注释等内容。

只有掌握了这些最基础的知识,才能减少后续学习中的困扰,避免踩坑。

 

1. 基本语法

我们在前面完成了第一个 Java
程序,我们现在来回顾一下:

实例演示


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

可查看在线运行效果

整个程序看似简单,但包含很多基础的知识点。下面我们将围绕这个程序来介绍几部分内容:

  1. 大小写敏感

  2. 主方法

  3. 源代码文件

 

1.1 大小写敏感

Java 语言是大小写敏感的,这个知识点很好理解:所有的命名都区分大小写 (文件名、类名、方法名等等)。

例如:HelloWorld
helloWorld
是不同的;Hello.java
HellO.java
也是不同的。

 

1.2 类

Java 是纯面向对象的编程语言,因此 (class) 是一个程序的基本单位。所有的 Java 程序想要运行,都离不开类。

我们可以来看看代码的第一行:


public class HelloWorld {
代码块1

其中,public
是一个关键字,它属于访问控制符,它表示这个类是公开的。关于什么是访问控制符,在初学阶段不必理解。

紧接着的 class
也是一个关键字用于声明类, HelloWorld
是类名,类名的首字母要大写。如果类名由多个单词组成,那么每个单词的首字母都要大写。例如,我们可以这样声明一个表示夜猫编程学生的类:


public class ImoocStudent {
  ...
}
代码块123

 

1.3 主方法

什么是主方法呢?请观察示例代码的 class
内部(指的是类名 HelloWorld
后面用大括号 {}
包含的内容),这个方法被称为主方法。每个类只能拥有一个主方法。

需要特别注意的是:所有的 Java 程序都从主方法开始执行。 以下的写法是固定的,所以你暂时无需深究:


public static void main(String[] args) {
    ...
}
代码块123

而在主方法内部(指的是 main()
后面一对大括号中间包含的内容)我们可以定义一些指令,例如:


System.out.println("Hello World!");
代码块1

我们称这个指令为输出语句,它的作用是向屏幕输出 Hello World!
。输出语句在后面会经常用到。

我们也可以在主方法内部多次调用输出语句,以输出多条内容:

实例演示


public class ImoocStudent {
  public static void main(String[] args) {
System.out.println("第一行输出:夜猫编程学生");
      System.out.println("第二行输出:快来夜猫编程");
    }
}
123456


另外补充一点,类的内部不仅可以包含一个主方法,也可以包含多个方法。在学习方法的概念之前,我们将主要在主方法中编写示例代码。

 

1.4 源代码文件

既然源代码需要提供给计算机执行,我们就要将源代码以文件的形式保存在计算机的磁盘上。

需要注意的是:源代码文件的命名必须与类名相同,且后缀名为.java
。例如:HelloWorld
类对应的源代码文件名应该为 HelloWorld.java
,而 ImmocStudent.java
源代码文件的对应类名为 ImmocStudent

 

2. Java 标识符

 

2.1 概念

在计算机编程语言中,标识符是开发者编程时使用的名字,用于给变量、常量、函数、语句块等命名,以建立起名称与使用之间的关系。标识符通常由字母和数字以及其它字符构成。

在 Java 中,标识符通常用来给类、对象、变量、方法、接口、自定义数据类型命名。

 

2.2 命名规范

标识符都以字母(A-Z 或者 a-z),美元符号($)或下划线(_)开始;首字母后可以是字母、数字、下划线的任意组合;正如我们前面所提到的,标识符是大小写敏感的;需要特别注意的是,Java 中的关键字(本节最后将会介绍)不能被用作标识符。

以下是合法的标识符命名实例:

  • $name

  • _World

  • Imooc

  • imooc1

以下不合法的标识符命名实例:

  • ¥color

  • 12name

  • *abc

  • final

 

3. Java 注释和空行

 

3.1 概念

3.1.1 注释

注释是一种便于给人阅读程序的文本,它不会被编译器解析。养成多些注释的习惯,不但有助于自己理解程序,也有助于别人更好地理解自己的程序。在团队协作的项目中,代码注释更加重要,代码的研发人员通过编写通俗易懂的注释,可以极大地降低协作成员之间沟通成本。

下图灰色部分为 Java 源码中的注释:

3.1.2 空行

空行就是空白行,与注释一样,同样不会被编译器解析。

适当地使用空行,可以让代码的结构看起来更好看,例如,下面程序中第 2 行、第 5 行和第 8 行都是空行:


1 class HelloImooc {
2    
3    public static void main(String[] args) {
4     System.out.println("你好夜猫编程");
5        
6        System.out.println("Hello, yemao!");
7   }
8    
9}
代码块123456789

 

3.2 注释的分类

Java 语言提供了三种类别的注释:

  1. 单行注释

  2. 多行注释

  3. 文档注释

3.2.1 单行注释

单行注释用于注释一行文本,它以双斜线开始,后面跟上要注释的内容,其写法为:


// 被注释的内容
代码块1

在 Java 代码中,它是这样的:

实例演示


public class HelloImooc {
  // 定义入口方法
  public static void main(String[] args) {
      // 打印输出:你好夜猫编程
      System.out.println("你好夜猫编程");
    }
}
1234567


3.2.2 多行注释

多行注释用于注释多行文本,它以 /*
开头,以 */
结尾,其写法为:


/*
被注释的第一行内容
被注释的第二行内容
被注释的第三行内容
*/
代码块12345

当我们在开发时为了方便调试,需要注释一段多行的逻辑代码,可以使用多行注释:

实例演示


public class Dog {
  private int age;
 private String name;
  
  /*
  多行注释,注释了这段代码
  public Dog (String name, int age) {
  this.name = name;
      this.age = age;
    }
    */
    public static void main(String[] args) {
    }
}
1234567891011121314


3.2.3 文档注释

Java 中还有一种特殊的多行注释 —— 文档注释,它以 /**
开头,以 */
结尾,如果有多行,则每行都以 *
开头,其在代码中的写法为:

实例演示


/**
 * HelloWorld 类
 * 它是我的第一个 Java 程序
 * @Author: Colorful
 * @Date: 2020/02/02
 */
public class HelloWorld {
    /**
     * 主方法,向屏幕打印 Hello World!
     * @param args 主方法的固定参数
     */
  public static void main(String[] args) {
      System.out.println("Hello World!");
    }
}
123456789101112131415


这种特殊的多行注释需要写在类和方法的定义处,可以使用 javadoc
这样的命令来自动创建文档。另外通常在程序开头加入作者,时间,版本,要实现的功能等内容注释,方便程序的维护以及程序员的交流。

 

4 关键字和保留字

 

4.1 概念

关键字 (Keyword
) 是 Java 语言中的特殊标记。它已经被语言本身预先使用,因此我们不能使用关键字作为我们标识符的命名。

例如 Java 基本类型的 int
boolean
,流程控制语句中的 if
for
,访问修饰符 public
,以及一些用于声明和定义 Java 类、包、接口的 class
package
interface

而保留字 (Reserved word
) 可能是未来的关键字,也就是说可能在未来的版本中,Java 语言作为特殊标记。

Tips:无论是关键字还是保留字,我们都要记住:不能使用它们作为我们的代码中的标识符。

 

4.2 Java 中有哪些关键字

关键字一律用小写字母标识,Java 语言中定义了如下表所示的关键字:

关键字说明
abstract表明类或者成员方法具有抽象属性
assert断言,常用于程序的调试
boolean基本数据类型:布尔类型
break提前跳出一个块
byte基本数据类型,字节类型
case用在 switch 语句之中,表示其中的一个分支
catch用在异常处理中,用来捕捉异常
char基本数据类型:字符类型
class用于声明一个类
const保留关键字
continue回到一个块的开始处
default默认,用在 switch 语句中,表明一个默认的分支;JDK1.8
 以后也作用于声明接口函数的默认实现
do用在 do-while 循环结构中
double基本数据类型:双精度浮点数类型
else用在条件语句中,表明当条件不成立时的分支
enum枚举
extends表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口
final用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量
finally用于处理异常情况,用来声明一个基本肯定会被执行到的语句块
float基本数据类型之一,单精度浮点数类型
for一种循环结构的引导词
goto保留关键字,没有具体含义
if条件语句的引导词
implements表明一个类实现了给定的接口
import表明要访问指定的类或包
instanceof用来测试一个对象是否是指定类型的实例对象
int基本数据类型之一,整数类型
interface接口
long基本数据类型之一,长整数类型
native用来声明一个方法是由与计算机相关的语言(如 C/C++/FORTRAN 语言)实现的
new用来创建新实例对象
package
private一种访问控制方式:私用模式
protected一种访问控制方式:保护模式
public一种访问控制方式:共用模式
return从成员方法中返回数据
short基本数据类型之一,短整数类型
static表明具有静态属性
strictfp用来声明 FP_strict(单精度或双精度浮点数)表达式遵循 IEEE 754 算术规范
super表明当前对象的父类型的引用或者父类型的构造方法
switch分支语句结构的引导词
synchronized表明一段代码需要同步执行
this指向当前实例对象的引用
throw抛出一个异常
throws声明在当前定义的成员方法中所有需要抛出的异常
transient声明不用序列化的成员域
try尝试一个可能抛出异常的程序块
void声明当前成员方法没有返回值
volatile表明两个或者多个变量必须同步地发生变化
while用在循环结构中

 

本小节我们将介绍 Java 语言中也是编程语言中的一个基本概念:变量。

通过本小节的学习,你将了解到变量是什么,如何创建变量,如何操作变量,变量的命名规范,这些是我们本小节学习的重点。我们也会介绍常量的概念和使用。

1. 什么是变量

在程序设计中,变量是指一个包含值的存储地址以及对应的符号名称

从定义上来看,变量大概可分为两部分:变量的名字和变量的值,可通过变量名来访问变量值。简单来说,变量就是存储数据的载体。

对于 Java 语言来讲,Java 是一种强类型的语言,因此变量都必须有一个类型。在 Java 代码中,变量是长这个样子的:


// =左侧的age是变量名,右侧的22是变量值
int age = 22;
代码块12

 

2. 创建变量

我们已经在上面看到了变量在代码中的样子,现在我们来动手创建变量。

Java
语言中,我们需要做两件事才能创建一个变量:

  1. 给变量起一个名字

  2. 定义变量的数据类型

创建变量的过程也叫声明变量,声明变量的语法如下:


DataType 变量名;
代码块1

Tips:关于数据类型,我们将在下一小节介绍。此处只需知道变量有类型之分即可。

声明一个变量,实例如下:


int a;
代码块1

上述代码,声明了一个名字为a
,类型为整型的变量。

我们可以再声明一个名字为b
,类型为字符型的变量,实例如下:


char b;
代码块1

再声明两个整型的变量age
number
,实例如下:


int age;
int number;
代码块12

 

3. 给变量赋值

变量声明操作已经告诉了编译器变量的数据类型。数据类型决定了变量中可以存放什么,不能存放什么,上述的变量a
int
类型(整型),因此只能存放整数。

一旦声明了一个变量,我们就可以使用赋值语句为其赋值,实例如下:


// 变量声明语句
int a;
// 赋值语句
a = 1;
代码块1234

为变量分配值的语句,就称为赋值语句。需要特别提醒的是,语句中=
的意义不同于数学中的等号,在 Java 中,=
是赋值符号。

对于变量的声明和赋值操作,我们也可以将这两条语句合并成一条语句,实例如下:


int a = 1;
代码块1

另外,如果要创建多个类型相同的变量,我们可以在一条语句中将多个变量的声明进行分组:


int a, b;
a = 1;
b = 2;
代码块123

为了精简语法,还可以将变量的声明和赋值同时分组:


int a = 1, b = 2;
代码块1

在作用域范围内,变量的值能够随时访问或重新赋值,比如:

实例演示


class PrintVariable {
    public static void main(String[] args) {
        int a = 20;
    System.out.println("修改前变量a=" + a);
    // 将变量a重新赋值为100
    a = 100;
    System.out.println("修改后变量a=" + a);
    }
}
123456789

可查看在线运行效果

运行结果:


修改前变量a=20
修改后变量a=100
代码块12

上述代码中,声明了一个整型变量a
,且初始化值为20
,可以使用a = 100;
这种赋值语句,对变量a
重新赋值。

注意,在 Java 中,对变量进行重新赋值,这样的写法是错误的:


int a = 20;
int a = 100;
代码块12

编译代码,将会抛出异常:


Test.java:5: 错误: 已在方法 main(String[])中定义了变量 a
int a = 2;
    ^
1 个错误
代码块1234

编译报错的原因很简单,第二行代码再次定义了变量a
,而变量a
已经在内存中存在了,不能再重复定义。这与对变量重新赋值不同。

 

4. 变量命名规范

对于变量的命名,每种编程语言都有自己的规则和约定,Java 语言也不例外。命名变量的规则和约定如下:

  • 变量的名称可以是任何合法的标识符,以字母,美元符号$
    或下划线_
    开头
    。但是,按照约定俗成,变量应始终以字母开头,不推荐使用美元符号和下划线开头;

  • 开头后续的字符可以是字母、数字、美元符号或下划线。为变量选择名称时,推荐使用完整的英文单词,不推荐使用单词缩写,更不要使用中文拼音。这样做有利于代码的阅读和理解。另外请牢记,选择的名称不能是关键字保留字

  • 变量命名区分大小写

  • 变量命名应采用小驼峰命名法。所谓小驼峰命名法,就是如果你选择的名称只包含一个单词,那么用全部小写字母拼写该单词;如果名称包含多个单词,请将第二个单词起的每个单词的第一个字母都大写;

  • 如果变量存储了一个常量值,要将每个字母大写并用下划线字符分隔每个单词。比如static final int MAX_NUM = 100
    。按照约定俗成,除了常量命名的情况,下划线字符永远不会在其他地方使用。

下面我们对照上述规则和约定来看几个实例。

实例1:


int $a;
int _b;
int age;
代码块123

上面3个变量的声明都是合法的,但是根据约定俗称,不推荐$a
这种以美元符号开头、_b
这种以下划线开头的命名方式。

实例2:


public class VariablesNameing2 {
    public static void main(String[] args) {
        String Name = "Colorful";
        String name = "Colorful1";
        System.out.println("Name=" + Name);
        System.out.println("name=" + name);
    }
}
代码块12345678

变量名区分大小写,因此上面的Name
name
是两个不同的变量。由于只有一个单词组成,应将单词使用全部小写拼写,不推荐第1行Name
这种命名方式。

实例3:


// 声明姓和名变量
String firstName;
String lastname;
代码块123

上面声明了两个变量 firstName
lastname
,由于它们都是由两个单词组成,按照小驼峰命名法的约定俗成:第2行lastname
变量名由两个英文单词组成,因此推荐改为lastName

 

5. 常量

所谓常量,就是恒常不变的量。我们可以将常量理解成一种特殊的变量。

与变量不同的是,一旦它被赋值后,在程序的运行过程中不允许被改变。常量使用final
关键字修饰:


final DataType 常量名 = 常量值;
代码块1

Tips:常量的命名规范与普通变量有所不同,要将每个字母大写并用下划线字符分隔每个单词。

如果我们尝试在代码中修改常量的值:


class ConstantTest {
    public static void main(String[] args) {
        // 声明并初始化常量 TOTAL_NUM
        final int TOTAL_NUM = 200;
        // 对 TOTAL_NUM 重新赋值
        TOTAL_NUM = 20;
    }
}
代码块12345678

编译执行代码,编译器将会报错:


ConstantTest.java:6: 错误: 无法为最终变量TOTAL_NUM分配值
        TOTAL_NUM = 20;
        ^
1 个错误
代码块1234

适当地使用常量可以提高代码的安全性和可维护性。例如,我们可以在程序中声明一个表示网站名称的常量:final String SITE_NAME = "夜猫编程";
,这样在所有需要用到网站名称的地方,都调用这个常量即可。这样既保证了其值不可修改,提高了代码的安全性,又统一了调用方的规范。

 

6. 变量的种类

学习变量的种类,需要你对 Java 的类和对象有一定的了解。目前不要求完全理解,等到后面学完面向对象相关知识后再回过头来回味。

Java 语言定义了以下4 种变量

  • 实例变量(见代码中instanceVariable

  • 类变量(见代码中classVariable

  • 局部变量(见代码中localVariable

  • 参数(见代码中parameter
    args


public class KindsOfVariables {
    // 1.实例变量
    public int instanceVariable = 1;
    // 2.类变量
    public static int classVariable;
    
    public void demoMethod(int parameter) { // 3.参数    
        // 4.局部变量
        int localVariable;
    }
    
    public static void main(String[] args) {
        // 入口方法
    }
}
代码块123456789101112131415

 

6.1 实例变量

实例变量在类范围内声明。声明时不使用static
关键字修饰,因此也称为非静态字段

实例变量用于存储对象的状态,它的值对于类的每个实例都是唯一的,每个对象都拥有自己的变量副本。只要相应的对象存在于内存中,它就占用着存储空间。

下面是一个实例变量的实例,当然,我们还没有介绍类和对象的概念,如果你了解类和对象,可以阅读源码帮助理解:

实例演示



public class Student {
    // 实例变量 name
    public String name;
    // 实例变量 age
    public int age;
    // 构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 打印学生基本信息的方法
    public void printInfo() {
        System.out.println("学生姓名为:" + name);
        System.out.println("学生年龄为:" + age);
    }
    public static void  main(String[] args) {
        // 实例化两个学生对象
        Student student1 = new Student("小虎", 20);
        Student student2 = new Student("小李", 18);
        // 分别调用打印学生基本信息方法,打印两个对象下的两个实例变量
        student1.printInfo();
        System.out.println("--------分割线--------");
        student2.printInfo();
    }
}
12345678910111213141516171819202122232425262728


运行结果:


学生姓名为:小虎
学生年龄为:20
--------分割线--------
学生姓名为:小李
学生年龄为:18
代码块12345

实例变量和实例对象相关,因此需要通过new
关键字实例化出对象,通过对象才能访问其实例变量(也称实例属性)。上述代码中,name
age
就是用于存储其对象的属性,我们实例化了两个学生对象,其实例变量name
age
,在每个对象实例中是唯一的。

 

6.2 类变量

类变量在类范围内使用static
关键字修饰,因此类变量又被称为静态字段、静态变量

static
修饰符告诉编译器,无论类被实例化多少次,类变量始终只有一个变量副本。只要类被加载到内存中,它就会存在。

另外,类变量可以被声明为常量,通过使用final
关键字以表示变量永远不会改变。例如:public static final NAME = "虎哥"
,这里的NAME
就是不会改变的常量。再次提醒,在常量的命名规范中,要将字母全部大写。

对于类变量,我们再来看一个实例:

实例演示


public class Course {
  
  // 类变量 courseType
  public static String courseType = "文字课程";
  // 常量 COURSE_NAME
  public static final String COURSE_NAME = "Java 基础教程";
public static void main(String[] args) {
      // 分别打印类变量和常量
      System.out.println(Course.courseType);
      System.out.println(Course.COURSE_NAME);
    }
}
12345678910111213


运行结果:


文字课程
Java 基础教程
代码块12

类变量和类相关,因此不需要使用new
关键字实例化对象后再调用,可以直接通过类名 + .
点运算符 + 类变量名
的方式调用。

上述代码中,courseType
COURSE_NAME
都使用static
关键字修饰,它们都可以直接通过Course.变量名
的方式调用。

 

6.3 局部变量

局部变量是在方法范围内被声明和使用的。它们没有任何关键字修饰,可以根据变量声明的位置来认定局部变量(即方法的左花括号和右花括号之间),因此,局部变量只可以对声明它们的方法可见。方法返回后,它们将被销毁。

main
方法中的局部变量实例:


public static void main(String[] args) {
  // 局部变量 name
  String name = "小斧";
  // 局部变量 age
  int age = 20;  
  System.out.println("姓名:" + name);
  System.out.println("年龄:" + age);
}
代码块12345678

我们再来看一个自定义方法中的局部变量实例:


public class PrintNumber {
  
  public void printer() {
      int num = 10;
      for(int i = 1; i <= num; i ++) {
      System.out.println(i);
        }
    }
  
}
代码块12345678910

局部变量和方法相关,因此只能在方法内部局部定义和使用,在第二个实例中没有代码注释,请思考printer
方法中有哪几个局部变量。

 

6.4 参数

参数是用于传递给方法签名的变量(例如入口方法main
中的args
),它们可以在方法中的任何位置被调用。在方法执行的期间位于内存中,方法返回后被销毁。

例如,上面实例变量的实例中,Student
类的构造方法就接收两个参数,如下为代码截取:


// Student 类构造方法
public Student(String name, int age) {  // name 和 age 就是传递给Student构造方法的参数
    this.name = name;
    this.age = age;
}
代码块12345

注意,方法体中的this.name
this.age
指代的是实例变量,而 name
age
是参数,它们被用于赋值给实例变量。

 

Java 基本数据类型

前面我们学习了变量,每个变量都是有数据类型的。在 Java 中,一共有两大数据类型:

  • 基本数据类型(内置数据类型)

  • 引用数据类型

本小节,我们将主要介绍基本数据类型,除了我们在示例中经常用到的 int
类型外,Java
语言还有其他 7
种基本数据类型。它们由语言预先定义,也称内置数据类型,顾名思义,它们是 Java
语言中最基本的数据类型。另外注意:引用数据类型并不属于基本数据类型的范畴,我们将在后面讲解。

Java 语言支持 8 种基本数据类型:byte
short
int
long
float
double
char
boolean

 

1. 分类和特点

 

1.1 分类

基本数据类型定义在 Java
类型系统中,在类型系统中,又可将基本类型分为三大类:

  • 数字型:包含 short
    int
    long
    float
    double
    ,只能存储数字数据;

  • 字符型byte
    char
    ,只能存储字符数据

  • 布尔类型boolean
    ,只能存储 true
    (真) 或 false
    (假)。

 

1.2 范围和默认值

基本类型都有固定的大小,因此,基本类型的值会被限制在一个范围内。

另外,在声明变量时,不一定总是需要分配值。编译器会将已声明但未初始化的字段设置合理的默认值。但是,建议为每个变量都赋初始值,这是很好的编程习惯。

具体的范围和默认值,请参考下表:

类型大小(位)最小值最大值默认值
byte8-128+1270
char160+655,35‘\u0000’
short16-32,768+32,7670
int32-2,147,483,648+2,147,483,6470
long64-9,223,372,036,854,775,808+9,223,372,036,854,775,8070L
float321.4 E-453.402,823,5 E+380.0f
double644.9 E-3241.797,693,134,862,315,7 E+3080.0d
booleanfalse

 

1.3 常见错误

在编码过程中,要特别注意变量不要超出其类型的范围,请查看如下示例:

实例演示


public class MemoryOverflow {
    public static void main(String[] args) {
      // Integer.MAX_VALUE 用来int类型能存储的最大值
        int maximumValue = Integer.MAX_VALUE;
      System.out.println("int类型能够存储的最大值为:" + maximumValue);
        System.out.println(maximumValue + 1);
    }
}
12345678

可查看在线运行效果

运行结果:


int 类型能够存储的最大值为2147483647
-2147483648
代码块12

我们发现 int
类型能存储的最大值加 1 之后,变成了一个负数,这个数其实就是 int
类型能够存放的最小值,这是因为加 1 之后变量超出了 int
类型能够存储的最大值,这就是我们常常说的内存溢出错误

还要特别注意一点,由于 Java 是强类型的,每个变量都有一个类型,只有给定种类的值能够存储到该变量中。例如,不能将浮点型的数字赋值给整型变量:


public class IncompatibleTypeError{
    public static void main(String[] args) {
        int age;
      age = 20.5f;
    }
}
代码块123456

源代码在编译阶段就会报错:


$ javac IncompatibleTypeError.java
IncompatibleTypeError.java:4: 错误: 不兼容的类型: 从float转换到int可能会有损失
      age = 20.5f;
            ^
1 个错误
代码块12345

 

2. 整型

整型就是整数类型,和数学中的整数意义相同,例如:


// 声明一个整型变量age
int age = 10;
// 声明一个整型变量 score
int score = 100;
代码块1234

整型除了 int
类型,还有 short
long
类型,也就是短整型和长整型,他们用于存放不同范围的整数值。需要注意的是,long
类型的值后面要以大写字母 L
或小写字母 l
结尾。请阅读以下代码:


// 声明一个短整型变量a
short a = 20;
// 声明一个长整型变量b
long b = 100l;
// 声明一个长整型变量c
long c = 100L;
代码块123456

Tips:对于长整型,推荐后面总以大写字母 L
结尾,因为小写字母 l
与数字 1
容易混淆。

和数学一样,计算机中的整型也有进制的概念,Java
可以通过以下几种进制系统表示:

  • 十进制:基数为 10,由 0 到 9 组成;这是我们日常生活中使用的数字系统;

  • 十六进制:基数为 16,由数字 0 到 9 和字母 A 到 F 组成;

  • 二进制:基数为 2,由数字 0 和 1 组成。

Java
中,十六进制和二进制需要以前缀区分,前缀 0x
表示十六进制,前缀 0b
表示二进制,我们来看一个示例:


// 十进制表示数字10
int decimalValue = 10;
// 十六进制表示数字10
int hexadecimalValue = 0xA;
// 二进制表示数字10
int binaryValue = 0b1010;
代码块123456

 

3. 浮点型

浮点类型就是数学中的小数,在 Java 中,浮点型又可分为单精度浮点型 (float
) 和双精度浮点型 (double
)。需要注意的是,float
类型的值必须要以大写字母 F
或小写字母 f
结尾,我们来看一个示例:


float f1 = 1.2f;
float f2 = 10.56F;
代码块12

double
类型的值可以以字母 D
d
结尾,但不做强制:


// 声明三个double类型变量,其值都为123.3
double d1 = 123.3;
double d2 = 123.3D;
double d3 = 123.3d;
代码块1234

另外浮点类型也可以使用字母 E
e
,后面跟上次方的数值,来表示数学中的科学计数法,我们来看一个示例:


// 科学计数法表示的 123.4
double d2 = 1.234e2;
float f1  = 1.234e2f;
// 科学计数法表示 200022.1
double d3 = 2.000221e5
代码块12345

 

4. 布尔类型

布尔类型 boolean
只有两个可能的值:true
false
,它是用于跟踪判断条件真假的标志。


boolean b1 = true;
boolean b2 = false;
代码块12

我们将在后面学习条件语句的时候经常使用。这时布尔类型才能发挥它真正的价值,这里不再赘述。

 

5. 字符类型

字符类型 char
表示一个字符。Java 中的 char
类型除了可表示标准的 ASCII
外,还可以表示一个 Unicode
字符:

实例演示


public class CharType {
    public static void main(String[] args) {
        // 存放一个 ASCII 码
        char a = 97;
        // 存放一个Unicode字符
        char zh = '斧';
        System.out.println(a);
        System.out.println(zh);
    }
}
12345678910

运行结果:


a
代码块12

Java 语言还为 char
String
类型(String 类型将在后面单独讲解),支持一些特殊的转义序列:

符号代表字符
\ n换行(0x0a)
\ r回车(0x0d)
\F换页(0x0c)
\ b退格(0x08)
\ s空格(0x20)
\ t制表符
"双引号
单引号
\反斜杠
\ddd八进制字符(ddd)
\ uxxxx十六进制 Unicode 字符(xxxx)

 

Java 运算符

我们已经学会了如何声明变量和赋值变量。那么你可能想知道如何对它们进行操作。本小节我们学习的运算符就可以对它们进行运算。

运算符是一些特殊的符号,它们对一个,两个或多个操作数执行特定的运算,然后返回一个结果。这里的操作数指的就是运算符操作的实体。

Java
提供了一组丰富的运算符来操作变量。我们可以将所有Java
运算符分为以下几类:

  • 算术运算符

  • 关系运算符

  • 位运算符

  • 逻辑运算符

  • 赋值运算符

  • 其他运算符

本小节我们将按照以上分类介绍 Java 中的运算符,并在最后介绍运算符的优先级。

 

1. 算术运算符

 

1.1 概述

Java 语言提供了执行加减乘除四则运算的运算符。算数运算符被用在数学表达式中,可以使用任意嵌套的小括号,其作用与数学中相同。下表列出了算术运算符:

(在例子中,初始化两个整型变量a、b:int a = 2;
int b = 4;

运算符描述例子
+
加法运算符 (也用于字符串连接)a + b 等于 6
-
减法运算符a - b 等于 -2
*
乘法运算符a * b 等于 8
/
除法运算符b / a 等于 2
%
取余运算符b % a 等于 0
++
自增运算符a ++ 等于 3
--
自减运算符b – 等于 3

 

1.2 实例

以下是算数运算符的实例程序。

加法运算符使用实例:

实例演示


public class ArithmeticOperators1 {
    public static void main(String[] args) {
        // 声明两个整型变量 num1,num2 分别赋值为 2, 3
        int num1 = 2, num2 = 3;
        // 使用加法运算符,对num1和num2执行相加操作,并将返回结果赋值给result
        int result = num1 + num2;
        System.out.println( num1 + " + " + num2 + " = " + result);
    }
}
123456789

可查看在线运行效果

运行结果:


2 + 3 = 5
代码块1

减法运算符使用实例:

实例演示


public class ArithmeticOperators2 {
    public static void main(String[] args) {
        // 声明两个整型变量 num1, num2 分别赋值为 5, 3
        int num1 = 5, num2 = 3;
        // 使用减法运算符,让 num1 加上 num2,并将返回结果赋值给result
        int result = num1 + num2;
        System.out.println( num1 + " + " + num2 + " = " + result);
        // 计算 num2 - num1 的结果
        int result1 = num2 - num1;
        System.out.println( num2 + " - " + num1 + " = " + result1);
    }
}
123456789101112

可查看在线运行效果

运行结果:


5 + 3 = 8
3 - 5 = -2
代码块12

乘法运算符使用实例:

实例演示


public class ArithmeticOperators3 {
    public static void main(String[] args) {
        // 声明两个整型变量 num1, num2 分别赋值为 2, 5
        int num1 = 2, num2 = 5;
        // 使用乘法运算符,让 num1 与 num2 相乘,并将返回结果赋值给result
        int result = num1 * num2;
        System.out.println( num1 + " * " + num2 + " = " + result);
    }
}
123456789

可查看在线运行效果

运行结果:


2 x 5 = 10
代码块1

除法运算符使用实例:

实例演示


public class ArithmeticOperators4 {
    public static void main(String[] args) {
        // 声明两个整型变量 num1, num2 分别赋值为 10, 2
        int num1 = 10, num2 = 2;
        // 使用除法运算符,让 num1 除以 num2,并将返回结果赋值给result
        int result = num1 / num2;
        System.out.println( num1 + " / " + num2 + " = " + result);
    }
}
123456789

可查看在线运行效果

运行结果:


10 / 2 = 5
代码块1

取余运算符使用实例:

实例演示


public class ArithmeticOperators5 {
    public static void main(String[] args) {
        // 声明两个整型变量 num1, num2 分别赋值为 5, 2
        int num1 = 5, num2 = 2;
        // 使用取余运算符,让 num1 对 num2 取余,并将返回结果赋值给result
        int result = num1 % num2;
        System.out.println( num1 + " % " + num2 + " = " + result);
    }
}
123456789

可查看在线运行效果

编译执行代码,屏幕上将会打印:


5 % 2 = 1
代码块1

自增、自减运算符使用实例:

实例演示


public class ArithmeticOperators6 {
    public static void main(String[] args) {
        // 声明两个整型变量 num1, num2 分别赋值为 5, 2
        int num1 = 5, num2 = 2;
        // 打印 num1 和 num2
        System.out.println("num1=" + num1);
        System.out.println("num2=" + num2);
        num1 ++;
        num2 --;
        System.out.println("num1自增后:" + num1);
        System.out.println("num2自减后:" + num2);
    }
}
12345678910111213

可查看在线运行效果

运行结果:


num1=5
num2=2
num1自增后:6
num2自减后:1
代码块1234

另外,整型之间的除法运算是整除,这也就意味着2 / 4
的结果为0
,如果我们想像数学一样得到一个小数,可以使用浮点类型的操作数。例如:

实例演示


public class OperatorDemo1 {
    public static void main(String[] args) {
        // 分组初始化两个整型变量i1、i2,值分别为2、4
        int i1 = 2, i2 = 4;
        // 使i1除以i2,并将返回结果赋值给i3
        int i3 = i1 / i2;
        System.out.println("整型2除以整型4的结果为:" + i3);
        // 分组初始化两个浮点型变量f1、f2,值分别为2、4
        float f1 = 2f, f2 = 4f;
        // 使f1除以f2,并将返回结果赋值给f3
        float f3 = f1 / f2;
        System.out.println("浮点型2除以浮点型4的结果为:" + f3);
    }
}
1234567891011121314

可查看在线运行效果

运行结果:


整型2除以整型4的结果为:0
浮点型2除以浮点型4的结果为:0.5
代码块12

要特别注意,在 Java 语言中,算数运算符不能作用于不同类型的操作数。我们来看一个反例:


public class OperatorDemo1 {
    public static void main(String[] args) {
        // 初始化布尔类型的变量b,值为true
        boolean b = true;
        // 初始化整型变量i,值为20
        int i = 20;
        // 使用加法运算符,让i与b相加
        int result = i + b;
    }
}
代码块12345678910

编译代码,将会报错:


javac OperatorDemo1.java
OperatorDemo1.java:7: 错误: 二元运算符 '+' 的操作数类型错误
        int result = i + b;
                       ^
  第一个类型:  int
  第二个类型: boolean
1 个错误
代码块1234567

编译器给出明确提示:加法运算符的操作数类型错误。这是因为 Java 是强类型的语言,不同类型的操作数的算数运算是违规的,这个原理同样适用于其他算数运算符,此处不再一一列举。

还有一点,自增自减运算符是有前后之分的,++i
表示先加1再引用i
i++
表示先引用i
再加1。将在下一小节举例介绍。

 

2. 关系运算符

 

2.1 概述

关系运算符又称为比较运算符,比较的结果是一个布尔类型的值(true
false
)。

Java 语言有几个可用于比较变量的运算符,如下表所示:

(在例子中,初始化两个整型变量a、b:int a = 2;
int b = 4;

运算符描述例子
==
检查如果两个操作数的值是否相等,如果相等则条件为真。(a == b) 为假
!=
检查如果两个操作数的值是否相等,如果值不相等则条件为真。(a != b) 为真
>
检查左操作数的值是否大于右操作数的值,如果是那么条件为真。(a > b) 为假
<
检查左操作数的值是否小于右操作数的值,如果是那么条件为真。(a < b)为真
>=
检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。(a >= b)为假
<=
检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。(a <= b)为真

Tips:在比较两个操作数是否相等时,必须使用“==
”而不是“=
”。

 

3.2 实例

下面是一个比较运算符的实例程序:

实例演示


public class OperateDemo2 {
    public static void main(String[] args) {
        // 初始化一个双精度浮点型变量d1,值为10
        double d1 = 10;
        // 初始化一个整型变量i1,值也为10
        int i1 = 10;
        System.out.println("id == i1的结果为:" + (d1 == i1));
        System.out.println("id != i1的结果为:" + (d1 != i1));
        System.out.println("id > i1的结果为:" + (d1 > i1));
        System.out.println("id < i1的结果为:" + (d1 < i1));
        System.out.println("id >= i1的结果为:" + (d1 >= i1));
        System.out.println("id <= i1的结果为:" + (d1 <= i1));
    }
}
1234567891011121314

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


id == i1的结果为:true
id != i1的结果为:false
id > i1的结果为:false
id < i1的结果为:false
id >= i1的结果为:true
id <= i1的结果为:true
代码块123456

Tips>
<
>=
<=
这几个运算符左右两边的操作数必须是byte
short
int
long
double
float
char
这几种数据类型;而==
!=
运算符的操作数既可以是基本数据类型,又可以是引用数据类型。

 

3. 位运算符

Java 语言还提供了对整数类型执行按位和移位操作的运算符,称作位运算符

它在实际的编码中并不常用,这部分内容了解即可。

假设a = 60,b = 13
;它们的二进制格式表示将如下:


a = 0011 1100
b = 0000 1101
-----------------
a & b = 0000 1100
a | b = 0011 1101
a ^ b = 0011 0001
~a = 1100 0011
代码块1234567

下表列出了位运算符的基本运算,假设整数变量 a 的值为 60 和变量 b 的值为 13:

运算符                         描述例子
&(按位与)如果相对应位都是1,则结果为1,否则为0(a&b),得到12,即0000 1100
|(按位或)如果相对应位都是 0,则结果为 0,否则为 1(a | b)得到61,即 0011 1101
^(按位异或)如果相对应位值相同,则结果为0,否则为1(a ^ b)得到49,即 0011 0001
〜(按位取反)按位取反运算符翻转操作数的每一位,即0变成1,1变成0。(〜a)得到-61,即1100 0011
<< (左位移)按位左移运算符。左操作数按位左移右操作数指定的位数。a << 2得到240,即 1111 0000
>> (右位移)按位右移运算符。左操作数按位右移右操作数指定的位数。a >> 2得到15即 1111
>>> (零填充右移)按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。a>>>2得到15即0000 1111

 

4. 逻辑运算符

 

4.1 概述

逻辑运算符可以在表达式中生成组合条件,例如在执行特定语句块之前必须满足的两个或多个条件。使用逻辑运算符,可以描述这些组合条件。逻辑运算的返回结果只能为真或假。

Java 语言中的逻辑运算符,如下表所示:

(在例子中,初始化两个整型变量a、b:int a = 0;
int b = 1;

运算符                              描述例子
&&(逻辑与)当且仅当两个操作数都为真,条件才为真。(a && b)为假
|| (逻辑或)如果任何两个操作数任何一个为真,条件为真。(a || b)为真
!(逻辑非)用来反转操作数的逻辑状态。如果条件为真,则逻辑非运算符将得到假。!(a && b)为假

 

4.2 短路运算

&&
||
运算符存在短路行为。短路的意思是:只有在需要的时候才会判断第二个操作数的真假。例如:

实例演示


class LogicOperators {
    public static void main(String[] args){
        int a = 1, b = 2;
        if((a == 2) && (b == 2)) {
            System.out.println("a和b都等于2");
        }
        if((a == 1) || (b == 1)) {
            System.out.println("a等于1或b等于1");
        }
    }
}
1234567891011

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


a等于1或b等于1
代码块1

程序解析:有两个整型变量a
b
,值分别为1
2
。第一个if
语句的条件为逻辑与运算,其第一个操作数a == 2
为假,所以无论第二个操作数是真是假,都不去判断,条件直接被判定为假;第二个if
语句的条件为逻辑或运算, 其第一个操作数a == 1
为真,所以无论第二个操作数是真是假,都不会去判断,条件直接被判定为真。这就是所谓的短路。

 

5. 赋值运算符

 

5.1 概述

赋值运算符是为指定变量分配值的符号。下标列出了常用 Java 中常用的赋值运算符:

运算符                                                                  描述                例子
=简单的赋值运算符。将值从右侧操作数分配给左侧操作数。c = a + b将a + b的值赋给c
+=加和赋值运算符。它将右操作数添加到左操作数,并将结果分配给左操作数。c + = a等于c = c + a
-=减和赋值运算符。它从左侧操作数中减去右侧操作数,并将结果分配给左侧操作数。c -= a等效于c = c – a
*=乘和赋值运算符。它将右操作数与左操作数相乘,并将结果分配给左操作数。c *= a等效于c = c * a
/ =除和赋值运算符。它将左操作数除以右操作数,并将结果分配给左操作数。c /= a等于c = c / a

 

5.2 实例

我们来看一个赋值运算符的实例:

实例演示


public class OperateDemo5 {
    public static void main(String[] args) {
        // 分组初始化三个变量 num1、num2、result,值分别为 20、10、0
        int num1 = 20, num2 = 10,  result = 0;
        System.out.println("初始值:");
        System.out.print("num1=" + num1 + '\t');
        System.out.print("num2=" + num2 + '\t');
        System.out.print("result=" + result + "\t\n");
        System.out.println("开始赋值运算:");
        result += num1;
        System.out.println("result += num1 结果为:" + result);
        result -= num2;
        System.out.println("result -= num2 结果为:" + result);
        result *= num1;
        System.out.println("result *= num1 结果为:" + result);
        result /= num2;
        System.out.println("result /= num2 结果为:" + result);
        result %= 15;
        System.out.println("result %= 15 结果为:" + result);
    }
}
123456789101112131415161718192021


运行结果:


初始值:
num1=20num2=10result=0
开始赋值运算:
result += num1 结果为:20
result -= num2 结果为:10
result *= num1 结果为:200
result /= num2 结果为:20
result %= 15 结果为:5
代码块12345678

 

6. 其他运算符

 

6.1 条件运算符(? :)

条件运算符也称为三元运算符。我们会在条件语句小节中再次对其介绍。

该运算符由三个操作数组成,用于判断布尔表达式。它的目的是确定应将哪个值分配给变量。条件运算符的语法为:


变量 = (布尔表达式) ? 值1 : 值2
代码块1

如果布尔表达式为真,就将值1
分配变量,否则将值2
分配给变量。

下面是一个实例程序:

实例演示


public class ConditionalOperators {
    public static void main(String[] args) {
        int age = 15;
        System.out.println(age >= 18 ? "在中国你已经成年" :  "在中国你还未成年");
    }
}
123456


由于age
变量值为15,小于18,age >= 18
返回结果为假,因此编译执行后,屏幕将打印:


在中国你还未成年
代码块1

 

6.2 instanceof 运算符

Tips:了解 instanceof 运算符需要一些面向对象的前置知识。目前你可以选择性学习。

instanceof
运算符将对象与指定类型进行比较,检查对象是否是一个特定类型(类类型或接口类型)。

instanceof 运算符的语法为:


( Object reference variable ) instanceof  (class/interface type)
代码块1

如果instanceof
左侧的变量所指向的对象,是instanceof
右侧类或接口的一个对象,结果为真,否则结果为假。

实例演示


public class InstanceOfOperators1 {
    public static void main(String[] args) {
        String name = "imooc";
        boolean b = name instanceof String;
       System.out.println("结果为:" + b);
    }
}
1234567

运行案例点击 "运行案例" 可查看在线运行效果

由于字符串变量name
String
类型,所以执行代码,屏幕会打印:


结果为:true
代码块1

注意,instanceof
运算符不能用于操作基本数据类型,如果将字符串类型name
变量改为一个char
类型的变量,编译代码将会报错:


InstanceOfOperators1.java:4: 错误: 意外的类型
        boolean b = name instanceof String;
                    ^
  需要: 引用
  找到:    char
1 个错误
代码块123456

 

7. 运算符的优先级

当多种运算符在一同使用的时候,会有一个执行先后顺序的问题。

下表中的运算符按优先顺序排序。运算符越靠近表格顶部,其优先级越高。具有较高优先级的运算符将在具有相对较低优先级的运算符之前计算。同一行上的运算符具有相同的优先级。

          类别                       操作符关联性

后缀

() [] . (点操作符)

左到右

一元

+ + - !〜

从右到左

乘性

* /%

左到右

加性

+ -

左到右

移位

>> >>> <<

左到右

关系

>> = << =

左到右

相等

== !=

左到右

按位与

左到右

按位异或

^

左到右

按位或

|

左到右

逻辑与

&&

左到右

逻辑或

| |

左到右

条件

?:

从右到左

赋值

= + = - = * = / =%= >> = << =&= ^ = | =

从右到左

逗号

左到右

相同优先级的运算符出现在同一表达式中时,如何控制它们计算的先后呢。我们来看一个实例:

实例演示


public class OperateorsPriority {
    public static void main(String[] args) {
      int a = 2;
      int b = 4;
      int c = 6;
      int result = a + b - c + a;
     System.out.println("result = " + result);
    }
}
123456789

运行案例点击 "运行案例" 可查看在线运行效果

在计算result
的语句的右侧,+
-
两个运算符优先级相同,如果我们不加以控制,将按照从左到右顺序计算,打印结果为result = 2
;但是如果我们想先计算a + b
c + a
的值,再计算两者之差,我们可以使用括号()
将其顺序进行控制:(a + b) - (c + a)
,再执行代码将打印我们想要的结果:result = -2

我们在前面的小节中,已经学习了变量和运算符。有了这些前置知识,我们就可以学习表达式、语句和块了。

运算符可用于构建表达式,表达式可以进行值的计算,它是语句的核心组成部分;而语句是指令式编程语言中最小的独立元素;多条语句又可以组成语句块。本小节我们将学习表达式的概念和常用分类,也将了解到什么是语句和块

 

1. 表达式

 

1.1 概念

表达式,是由数字、运算符、数字分组符号(括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合。约束变量是在表达式中已被指定数值,而自由变量则可以在表达式之外另行指定数值。

Java
中,表达式是根据 Java 语法由变量运算符方法调用组成的结构,表达式的结算结果为单个值。表达式实例:

实例演示


public class Expression {
  public static void main(String[] args) {
      int a = 10, b = 20;
      // (a + b) * 2 就是一个算数表达式
      int c = (a + b) * 2;
      // c > b 就是一个布尔表达式
      if (c > b) { // if语句将在下一小节讲到,此处只需知道 c > b 是一个表达式即可
          System.out.println("c大于b");
        }
    }
}
1234567891011

上面代码中,(a + b) * 2
就是一个算数表达式,而 c > b
就是一个布尔表达式,代码中的 if
语句将在下一小节讲到,此处只需知道 c > b 是一个表达式即可。

下面我们将围绕算数表达式和布尔表达式来学习表达式。

 

1.2 分类

1.2.1 算数表达式

算数表达式是最常用的表达式,又称为数学表达式。它是通过算术运算符来进行运算的数学公式。

为了使用 Java
进行算数运算,首先必须至少声明一个变量。如下:


int num = 10;
代码块1

变量创建后,可以使用算数运算符+
-
*
/
%
++
--
)来操作变量的值。使用算数表达式的实例如下:

实例演示


public class ArithmeticExpression1 {
  public static void main(String[] args) {
      int num = 10;
      int result = num / 3;
      System.out.println( num + " / 3 = " + result);
    }
}
1234567

运行案例点击 "运行案例" 可查看在线运行效果

编译执行程序,屏幕上将会打印:


10 / 3 = 3
代码块1

对于操作数为整型的除法表达式,其计算结果将始终取整数部分。所以上面的 10 / 3
的结果等于 3
。如果我们想得到小数,可以使用浮点类型的变量来作为操作数(10.0 / 3
),其返回的值也是一个浮点型。

除了除法表达式之外,在使用自增 / 自减表达式运算的时候,也要额外注意前后自增 / 自减运算符的差别。我们来看下面一个实例:

实例演示



public class ArithmeticExpression2 {
  public static void main(String[] args) {
     // 前自增
      System.out.println("------ 前自增 ------");
    int num = 10;
      System.out.println("++num = " + (++num));
      System.out.println("num = " + num);
      // 前自减
        System.out.println("------ 前自减 ------");
    num = 10;
      System.out.println("--num = " + (--num));
      System.out.println("num = " + num);
      // 后自增
        System.out.println("------ 后自增 ------");
    num = 10;
      System.out.println("num++ = " + (num ++));
        System.out.println("num = " + num);
      // 前自减
      System.out.println("------ 前自减 ------");
      num = 10;
      System.out.println("num-- = " + (num --));
        System.out.println("num = " + num);
    }
}
12345678910111213141516171819202122232425

注意观察前后自增自减的区别,运行结果:


------ 前自增 ------
++num = 11
num = 11
------ 前自减 ------
--num = 9
num = 9
------ 后自增 ------
num++ = 10
num = 11
------ 前自减 ------
num-- = 10
num = 9
代码块123456789101112

结论:

  1. 前自增 / 自减的运算规则是:先进行自增或者自减运算,再进行表达式运算;

  2. 后自增 / 自减的运算规则是:先进行表达式运算,再进行自增或者自减运算。

1.2.2 布尔表达式

布尔表达式(Boolean expression)的结果只有 true
(真)和 false
(假)两个值。在 Java
语言中,布尔表达式可以使用关系运算符逻辑运算符来代替算数运算符。

我们来看一个使用关系运算符的实例:

实例演示


public class BooleanExpression1 {
public static void main(String[] args) {
      // 初始化两个整型变量a、b,值分别为2、3
      int a = 2, b = 3;
      // 分别打印比较运算符比较的结果
      System.out.println(a == b);
      System.out.println(a != b);
      System.out.println(a > b);
      System.out.println(a < b);
      System.out.println(a >= b);
      System.out.println(a <= b);
    }
}
12345678910111213

请阅读上面代码,并算出每一次打印的结果。这里不再展示代码打印结果。

布尔表达式常作为条件分支语句中的条件。因此下面的示例需要你对条件语句有一定的了解,我们再来看一个稍微复杂一些的实例:

实例演示


public class BooleanExpression2 {
  public static void main(String[] args) {
        // 初始化4个整型变量
      int i = 4, j = 5, k = 7, m = 8;
        // i > j && m < k++ 即为条件表达式
      if(i > j && m < k++) {
          k++;
        } else {
          k--;
        }
      System.out.println("k = " + k);
    }
}
12345678910111213

编译执行代码,屏幕上将会打印:


k = 6
代码块1

上述代码,是使用逻辑运算符和算数运算符结合的布尔表达式示例,如果布尔表达式 i > j && m < k++
结果为真,则执行 if
分支,k 自增 1,否则执行 else
分支,k 自减 1,最后打印出 k 的值。由于 i
的值小于 j
,并且 &&
运算符有短路作用,所以 m < k++
不做运算,直接走到 else
分支,最后得到结果 k = 6

这里再次强调一下逻辑运算符的短路:

在表达式中 (a && b)
,如果 a 为假,则 b 不会被求值,因为无论如何表达式都会为假。

同理,在表达式中 (a || b)
,如果 a 为真,则 b 不会被求值,因为无论如何表达式都会为真。

这就是我们所说的短路。如果想要取消短路,可以使用 &
代替 &&
、使用 |
代替 ||
,但是不建议这样写,会降低代码的可读性。

试想,如果将表达式中 i > j && m < k++
&&
改为 &
,变量 k
的值将会是多少?

 

2. 语句

在计算机科学的编程中,一个语句是指令式编程语言中最小的独立元素,语句用以表达程序要执行的一些动作。多数语句是以高级语言编写成一个或多个语句的序列,用于命令计算机执行指定的一系列操作。

语句和自然语言(例如英语、汉语)中的句子大致相同。一条语句构成了完整的执行单元。通过使用英文分号(;
)终止表达式,可以将以下类型的表达式制成语句:

  • 赋值表达式

  • 自增 / 自减 ++
    --

  • 方法调用

  • 对象创建表达式(面向对象部分将会学到)

请结合如下示例理解语句的概念:

变量声明语句:


int age;
代码块1

赋值语句:


age = 20;
代码块1

自增语句:


age ++;
代码块1

方法调用语句:


System.out.println("Hello World! ");
代码块1

 

3. 块

块通常用来将两条或多条语句组合在一起,使其在格式上看更像一条语句。

一堆语句可以放在大括号中,以作为单个块执行。可以为此类语句命名或为其提供执行条件(下一节的条件判断将会讲到)。

下面是将一系列的语句放在一个块中的示例代码:


{
    int a = 1;
    int b = 2;
    int c = 3;
    int result = a + b + c;
}
代码块123456

 

Java 条件语句

条件语句通过判断给定条件的真假来控制程序的执行。在上一小节中,我们已经简要介绍过了语句和块的概念。那么本小节我们将进一步展开介绍 Java
中所有类型的条件语句。

 

1. if 语句

 

1.1 语法

当我们需要根据给定的条件来决定是否执行一段代码时,if
语句就派上用场了。if
块仅在与其关联的布尔表达式为 true
时执行。if
块的结构如下:


if (条件) {
    // 当条件成立时执行此处代码
}
代码块123

大括号中包含的内容就称为语句块。

 

1.2 实例

我们来看一个 if
语句的实例:

实例演示


public class IfStatement1 {
    public static void main(String args[]) {
        int age = 18;
        if(age >= 18) {
            System.out.println("在中国你已经成年");
        }
    }
}
12345678

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


在中国你已经成年
代码块1

条件age >= 18
成立时,也就是布尔表达式计算结果为 true
(真),if
语句块会执行。显然上面实例中 age
变量的值为 18,条件是成立的,执行程序,屏幕上将会打印 “在中国你已经成年”。

如果语句块内只有一条语句,我们也可以去掉花括号 {}


if(age >= 18)
    System.out.println("在中国你已经成年");
代码块12

当然,即使 if
语句块只有一条语句,也并不推荐这种不易于阅读的写法。

 

2. if … else … 语句

 

2.1 语法

if
语句可以结合 else
来使用,当布尔表达式计算结果为 false
(假)时,else
语句块将会执行。

if .. .else
语句用于有条件地执行两个代码块的其中一个,具体执行哪一个代码块,取决于布尔条件的结果。


if (条件) {
    // 如果条件成立,执行此处代码
} else {
    // 如果条件不成立,执行此处代码
}
代码块12345

 

2.2 实例

改写上面 if
语句的代码:

实例演示


public class IfElseStatement1 {
    public static void main(String args[]) {
        int age = 15;
        if(age >= 18) {
            System.out.println("在中国你已经成年");
        } else {
            System.out.println("在中国你还未成年");
        }
    }
}
12345678910

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


在中国你还未成年
代码块1

我们将变量 age
赋值为 15,并且在 if
语句块的后面加了一段 else {...}
语句块。这个时候,条件 age >= 18
的计算结果就为 false
了,程序将会执行 else
语句块中的代码。执行代码,屏幕将会打印 "在中国你还未成年"。

补充

Java 支持使用条件表达式(又称三目运算符)表达式1 ? 表达式2 : 表达式3
来简化 if else
语句的代码。

表达式 1 的作用等同于 if
语句后面的条件,如果表达式 1 为 true
, 则执行 表达式2
, 否则执行 表达式3

也就是说上面的代码可以使用三目运算符来实现同样的功能。实例如下:

实例演示


public class IfElseStatement2 {
    public static void main(String args[]) {
        int age = 15;
        System.out.println(age >= 18 ? "在中国你已经成年" :  "在中国你还未成年");
    }
}
123456

运行案例点击 "运行案例" 可查看在线运行效果

 

3. if … else if … else 语句

 

3.1 语法

if
语句可以结合 else if
来实现更复杂的程序分支结构:


if (条件1) {
    // 如果条件1成立,执行此处代码
} else if (条件2) {
    // 如果条件1不成立,并且条件2成立,执行此处代码
} else {
    // 如果条件1、条件2都不成立,执行此处代码
}
代码块1234567

 

3.2 实例

if
语句可以搭配任意多数量的 else if
语句使用,但是只能有一个 else
。下面我们来看一段代码:

实例演示


// 根据给定分数向屏幕打印评级
public class IfElseIfStatement {
  public static void main(String args[]) {
        int score = 70;
        if (score >= 90) {
          System.out.println("优秀");
        } else if(score >= 70) {
          System.out.println("良好");
        } else if (score >= 60) {
          System.out.println("及格");
        } else {
          System.out.println("不及格");
        }
    }
}
123456789101112131415

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


良好
代码块1

运行结果为 "良好",你也许会疑惑,score 为 70,同样也大于等于 60,为什么没有输入 "及格" 呢?这是由于当程序遇到符合条件的分支就会执行其分支语句块中的语句,不会执行其他分支语句块的语句。

 

3.3 嵌套 if … else 语句

你也可以在另一个 if
或者 else if
语句中使用 if
或者 else if
语句:


if(条件1){
   // 如果条件1为真,执行这里的语句
   if(条件2){
      ////如果条件2为真,执行这里的语句
   }
}
代码块123456

我们来看一个嵌套语句的实例:

实例演示


public class IfElseStatement1 {
    public static void main(String[] args) {
      // 初始化整型变量age,值为25
        int age = 25;
int sex = 1;  // 此处用sex变量表示性别,1:男  2:女
        if(age >= 20) {
            System.out.println("在中国你已经成年");
          if(sex == 2) {
              System.out.println("并且到了法定的结婚年龄");
            }
          if(sex == 1 && age >= 22) {
              System.out.println("并且到了法定的结婚年龄");
            }
        } else {
            System.out.println("在中国你还未成年");
        }
    }
}
123456789101112131415161718

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


在中国你已经成年
并且到了法定的结婚年龄
代码块12

 

4. switch 语句

 

4.1 语法

switch
条件语句可以理解为简写版的多个 if .. else
语句。switch
语句的语法如下:


switch (值) {
    case 值1:
       语句1.1
       ...
   语句n.1
       break;
    case 值2:
        语句2.1
        ...
        语句2.n
        break;
    default:
        语句n.1
        ...
        语句n.n
}
代码块12345678910111213141516

switch case 语句有如下规则:

  • switch 语句中的变量类型可以是:byte
    short
    int
    char
    或者 String

  • switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号;

  • case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量;

  • 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句;

  • 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不一定要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句;

  • switch 语句可以包含一个 default 分支,该分支一般是 switch 语句的最后一个分支(可以在任何位置,但建议在最后一个)。default 在没有 case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句。

 

4.2 实例

我们先来看下面的一个简单实例:

实例演示


public class SwitchStatement1 {
  public static void main(String args[]) {
        int i = 2;
      switch (i) {
          case 1:
              // i 的值不等于1,所以不执行此处代码
              System.out.println("i的值为1");
            break;
          case 2:
              // i 的值等于2,所以执行此处代码
              System.out.println("i的值为2");
              break;
          default:
  // case 2 分支已执行并break,所以此处代码不会执行
              System.out.println("i的值既不等于1,也不等于2");
        }
    }
}
123456789101112131415161718

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


i的值为2
代码块1

从 JDK5 开始,switch
语句可以与 枚举值一起使用。例如,下面是根据数字显示对应星期几的实例代码:


public class SwitchStatement2 {
   public static void main(String args[]) {
      Day day = day.MONDAY; // 假设 Day 是一种枚举类型,里面包含星期一到星期天。
      switch (day) {
         case MONDAY :
            System.out.println("星期一");
            break;
         case TUESDAY :
          System.out.println("星期二");
            break;
         case WEDNESDAY :
            System.out.println("星期三");
            break;
         case THURSDAY :
            System.out.println("星期四");
            break;
         case FRIDAY :
            System.out.println("星期五");
            break;
         case SATURDAY :
            System.out.println("星期六");
            break;
         case SUNDAY :
            System.out.println("星期天");
      }
   }
}
代码块123456789101112131415161718192021222324252627

从 JDK8 开始,switch
语句可以与 String
值一起使用:

实例演示


public class SwitchStatement3 {
   public static void main(String args[]) {
      String day = "TUESDAY";
      switch (day) {
         case "Wednesday" :
            System.out.println("星期一");
            break;
         case "TUESDAY" :
          System.out.println("星期二");
            break;
         case "WEDNESDAY" :
            System.out.println("星期三");
            break;
         case "THURSDAY" :
            System.out.println("星期四");
            break;
         case "FRIDAY" :
            System.out.println("星期五");
            break;
         case "SATURDAY" :
            System.out.println("星期六");
            break;
         case "SUNDAY" :
            System.out.println("星期天");
      }
   }
}
123456789101112131415161718192021222324252627

可查看在线运行效果


星期二
代码块1

 

Java 循环语句

循环结构能够让程序员以最少的精力去完成大量重复的工作,它可以让计算机根据条件做循环计算,当条件成立时继续循环,当条件不成立时结束循环。

依据前面所学的知识,如果我们想在屏幕上依次打印1到5,可以编写以下程序:

实例演示


// PrintNums.java
class PrintNums {
    public static void main(String[] args) {
      // 依次打印1到5
        System.out.println("1");
        System.out.println("2");
        System.out.println("3");
        System.out.println("4");
        System.out.println("5");
    }
}
1234567891011

可查看在线运行效果

运行结果:


1
2
3
4
5
代码块12345

但是这种编写代码的方案存在一些弊端:

  • 不灵活:如果我们想要更改需求,打印从6到10,那么就不得不逐行更改;

  • 难于维护:如果有大量代码,更容易产生bug

  • 伸缩性差:依次打印从1到5貌似很简单,如果需求变为打印从1到100呢?这意味着需要编写大量的代码。

使用循环结构,就可以解决上述弊端。下面我们打开代码编辑器,新建一个LoopPrintNums.java
,复制如下代码:

实例演示


// LoopPrintNums.java
class LoopPrintNums {
    public static void main(String[] args) {
        for(int i = 1; i <= 10; i ++) {
            System.out.print(i + "\t");
        }
    }
}
12345678

可查看在线运行效果

运行结果:


12345678910
代码块1

聪明的你可能发现,如果将i <= 10
改为 i <= 100
,屏幕将依次从1打印100。上述代码中,我们看到不需要再去编写多条打印语句,同样得到了我们想要的结果,代码量大大减少。那么上述代码具体有什么含义呢,为什么这样写就实现了多个数字的打印呢?在本小节中,我们就会进行详细介绍。

 

1. while 循环

 

1.1 语法

while
循环是最简单的循环形式。我们先来看看它的基本用法:


while (条件) {
    // 循环体,条件成立时执行
    ...
}
// 循环完成后执行
代码块12345

while
循环在每次循环开始前,首先会判断条件是否成立,如果计算结果为true
, 就会执行循环体内部语句。如果计算结果为false
,会跳出循环,执行后续代码。

 

1.2 实例

对于打印从1到5的例子,可以使用while
循环可以这样写:

实例演示


public class WhileLoop1 {
    public static void main(String args[]) {
        int i = 1;
        while (i <= 5) {
            System.out.println(i); // 打印i
            i ++; // i自增1
        }
    }
}
123456789

可查看在线运行效果

你也许注意到在循环体内部,除了打印变量i
的值,还有一个语句:i ++
,这个语句的作用是让变量i
自增1。如果没有这个语句,i
的值永远不会改变,所以循环条件永远成立,程序将陷入死循环,直到将资源耗尽才会停止,所以要杜绝编写死循环代码。

Tips:如果循环的条件永远不会变成 false
(比如使用字面量true
作为条件),则称这种循环为无限循环或死循环。循环体内的代码会无限地重复执行,直到中断。

再看一个例子,得到1到100的累加和:

实例演示


public class WhileLoop2 {
    public static void main(String[] args) {
        int sum = 0; // 累加和
        int i = 1;
        while (i <= 100) {
            sum = sum + i; // 使sum和i相加,并将值再次赋值给sum
            i ++; // i自增1
        }
        System.out.println("1到100的累加和为:" + sum);
    }
}
1234567891011

可查看在线运行效果

运行结果:


1到100的累加和为:5050
代码块1

我们来对程序进行解析:

  1. 定义两个变量sum
    i
    分别用于存放累加和以及要累加的数字

  2. 循环开始前判断条件 i <= 100
    是否成立,此时 i = 1
    ,成立,执行循环体内代码。

  3. 循环体内代码第一次执行,sum = 1
    i
    自增1变为2。

  4. 再次判断循环条件,成立就继续执行循环体,直到 i = 100
    ,自增1 变为101,此时条件不成立。执行循环后面的代码。

  5. 执行打印语句,打印最终的 sum
    值,程序结束。

 

2. do while 循环

 

2.1 语法

do while
循环的功能与while
循环类似,不同点在于:while
循环是先判断条件,再执行循环体;而do while
循环则是先执行循环体,再判断条件,如果条件成立继续执行循环,条件不成立则终止循环。do while
循环的语法如下:


do {
    // 循环体
} while (条件);
代码块123

无论条件成立与否,do while
循环都至少执行一次。而while
循环可能一次都不会执行。

 

2.2 实例

我们现在使用 do while
循环实现1到100的累加求和,代码如下:

实例演示


public class DoWhileLoop {
    public static void main(String[] args) {
        int sum = 0; // 累加和
        int i = 1;
        do {
            sum = sum + i; // 使sum和i相加,并将值再次赋值给sum
            i ++; // i自增1
        } while (i <= 100);
        System.out.println("1到100的累加和为:" + sum);
    }
}
1234567891011

可查看在线运行效果

运行结果:


1到100的累加和为:5050
代码块1

 

3. for 循环

 

3.1 语法

下面是for
循环的语法结构:


for (变量声明; 条件; 迭代语句) {
    // 循环体
}
代码块123

for
循环是一种特殊的while
循环,也是被使用最广泛的循环。它使用计数器来实现循环。在关键字 for
后面的括号中,会有三个语句,第一个语句是变量声明语句,允许声明一个或多个整型变量;第二个语句是条件,条件的检测方式与while
循环相同(每次循环开始前判断条件成立与否);第三个语句是迭代语句,虽然可以是任何语句,但该语句通常用于递增或递减变量。

 

3.2 实例

我们使用for
循环连续打印5行”夜猫编程真棒“的字样,代码如下:

实例演示


public class ForLoop1 {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i ++) {
            System.out.println("夜猫编程真棒");
        }
    }
}
1234567

可查看在线运行效果

运行结果:


夜猫编程真棒
夜猫编程真棒
夜猫编程真棒
夜猫编程真棒
夜猫编程真棒
代码块12345

我们现在使用for
来实现1到100的累加求和,代码如下:

实例演示


public class ForLoop2 {
    public static void main(String[] args) {
        int sum = 0; // 累加和
        for (int i = 1; i <= 100; i ++) {
            sum += i; // 加和赋值运算
        }
        System.out.println("1到100的累加和为:" + sum);
    }
}
123456789

可查看在线运行效果

运行结果:


1到100的累加和为:5050
代码块1

程序解析:

在执行循环体前,会先执行括号中的变量声明语句int i = 1
,它定义了一个计数器变量i
并且赋值为1(注意这个语句只执行一次)。然后会执行条件判断语句i <= 100
,显然条件成立,执行循环体,循环体执行完成后会才会执行括号中的第三个语句i ++
,再次判断条件是否成立,直到当i
的值为100时,最后一次执行循环体,这个时候i
再次自增1
101
,条件不成立,结束循环。

实际使用中,通常使用for
循环来遍历一个数组,我们将在 Java 数组小节举例介绍。

for
循环中第一个语句,变量声明语句可以一次声明多个整型变量,实例代码如下:

实例演示


public class ForLoop2 {
    public static void main(String[] args) {
        for (int i = 1, j = 10; i <= 10; i++, j--) {
            System.out.print(i + "\t");
            System.out.print(j + "\t");
        }
    }
}
12345678

可查看在线运行效果

运行结果:


1102938475665748392101
代码块1

另外,for
循环还可以缺省变量声明语句、循环条件和迭代语句,实例:


// 缺省变量声明语句
for (int i = 0; ; i ++) {
    // 语句
}
代码块1234
// 缺省循环条件语句和迭代语句
for (int i = 0; ; ) {
    // 语句
}
代码块1234
// 缺省所有语句
for (;;) {
    // 语句
}
代码块1234

但请注意,通常情况下不建议这样写。

 

4. for each 循环

由于学习 for each
循环需要一些数组和集合的前置知识,我们将会在 Java数组小节举例讲解。

 

5. break 和 continue 关键字

我们可以使用break
continue
语句来重定向程序执行流。

 

5.1 break

break
关键字可以出现在一个循环中,用以跳出当前循环。我们来看一个实例:

实例演示


public class BreakKeywords1 {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i ++) {
            if(i == 3) { // 条件语句
                System.out.println("当i等于3时,终止循环!");
                break;
            }
            System.out.println(i);
        }
    }
}
1234567891011

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


1
2
当i等于3时,终止循环!
代码块123

上面是一段循环打印数字的代码,当循环到达第3次迭代时,执行条件分支中的语句,将终止循环。注意:break
语句通常配合if
语句使用。

对于多层循环的情况,break
语句只能终止它自己所在的那一层循环,并不会影响到外层循环。请阅读如下代码:

实例演示


public class BreakKeywords2 {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i ++) {
            // 打印i的值
            System.out.println(i);
            for (int j = 1; j<=5; j ++) {
                if(j == 3) { // 条件语句
                    System.out.println("当j等于3时,终止循环!");
                    break;
                }
                // 打印j的值
                System.out.println(j);
            }
        }
    }
}
12345678910111213141516

可查看在线运行效果

运行结果:


1
1
2
当j等于3时,终止循环!
2
1
2
当j等于3时,终止循环!
3
1
2
当j等于3时,终止循环!
4
1
2
当j等于3时,终止循环!
5
1
2
当j等于3时,终止循环!
代码块1234567891011121314151617181920

上面的代码有两个for
循环嵌套,break
语句位于内层循环,所以当表达式j == 3
成立时,会跳出内层循环,进而继续执行外层循环。

 

5.2 continue

continue
关键字可以跳过当次循环,继续执行下一次循环,我们来看一个实例:

实例演示


public class ContinueKeywords {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i ++) {
            if(i == 3) {
                System.out.println("当i等于3时,跳过~");
                continue;
            }
            System.out.println(i);
        }
    }
}
1234567891011

可查看在线运行效果

运行结果:


1
2
当i等于3时,跳过~
4
5
代码块12345

在多层嵌套的循环中,continue
语句只能跳过它自己所在位置的循环。

 

Java 字符串

Java 基本数据类型一节中,我们已经知道 Java 中有两大数据类型:一个是基本数据类型,另一个是引用数据类型。

字符串(String
)便属于引用数据类型。字符串在 Java 程序中无处不在,其实我们在第一个 Java 程序中就已经使用过了字符串,打印语句中双引号中的Hello World
就是一个字符串:System.out.println("Hello World");

本小节我们将介绍字符串的基础知识,告诉你如何创建一个字符串,也会讲到 Java 13
支持的多行字符串的创建方法和注意事项,还会介绍很常用的字符串的连接操作,最后我们也会着重讨论字符串的一个重要特性:不可变性。

需要注意的是,String
是在java.lang
包中定义的内置类,了解它的相关操作需要面向对象的前置知识,为了减少初学者的困扰,字符串的相关操作不会在本小节讨论。我们将在完成面向对象的学习后专门讲解String
类。

 

1. 什么是字符串

字符串(string
)是由零个或多个字符组成的有限序列,它是编程语言中表示文本的数据类型。简单来说,字符串就是一串字符。

 

2. 创建字符串

 

2.1 创建字符和字符串

提到字符串,就很容易与字符关联起来,回忆我们已经学过的字符类型char
,在代码中我们是这样创建字符的:


// 依次创建三个字符 夜 猫 编 程
char c1 = '夜';
char c2 = '猫';

char c3 = '编';

char c4 = '程';

代码块1234

char
类型不同的是,String
类型使用双引号来表示一个字符串(例如:"字符串文字"
),在代码中我们可以这样创建字符串:


String str = "夜猫编程";
代码块1

我们再来看一个创建并打印字符串的程序示例:

实例演示


public class StringTest1 {
    public static void main(String[] args) {
        // 创建一个空字符串
        String str1 = "";
        // 创建一个只包含一个字符的字符串
        String str2 = "q";
        // 创建包含多个字符的字符串
        String str3 = "imooc is great!";
        // 依次打印它们
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);
    }
}
1234567891011121314

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


q
imooc is great!
代码块123

字符串可以声明为空,因此第一行将打印一个空行。

 

2.2 创建多行字符串

Java 13
以后,我们可以使用三引号来表示一个多行字符串,被官方称为“文本块”。文本块常用来表示多行的或大段的文字。例如:


public class StringTest3 {
    public static void main(String[] args) {
        String str = """
            Java 很棒!
            夜猫编程很棒!!
            能够在夜猫编程学 Java 更棒!!!""";
        System.out.println(str);
    }
}
代码块123456789

Tips:

这里需要注意的是,文本块中起始的三引号后面要另起一行,也就是说下面这种写法是错误的:


String str = """Java 很棒!
      夜猫编程很棒!!
      能够在夜猫编程学 Java 更棒!!!""";
代码块123

如果我们直接使用javac
命令编译代码,将会报错:


javac StringTest3.java
StringTest3.java:4: 错误: 文本块 是预览功能,默认情况下禁用。
        String str = """
                     ^
  (请使用 --enable-preview 以启用 文本块)
1 个错误
代码块123456

报错告诉我们:文本块是预览功能,默认是禁用的。我们可以给编译器加上一些参数来编译执行代码:


$ javac -source 14 --enable-preview StringTest3.java
$ java --enable-preview StringTest3
Java 很棒!
夜猫编程很棒!!
能够在夜猫编
学 Java 更棒!!!
代码块12345

 

2. 字符串的连接

我们可以使用加法运算符+
将字符串和任意其他的数据类型进行连接操作。

可以将两个或多个字符串连接在一起,例如:

实例演示


public class StringJoinTest1 {
    public static void main(String[] args) {
        // 定义两个字符串
        String str1 = "Hello";
        String str2 = "夜猫编程";
        // 将字符串str1连接一个空格,再连接str2,最后再连接一个感叹号
        String str3 = str1 + " " + str2 + "!";
        System.out.println(str3);
    }
}
12345678910

运行案例点击 "运行案例" 可查看在线运行效果

运行结果:


$ javac StringJoinTest1.java
$ java StringJoinTest1
Hello 夜猫编程!
代码块123

我们还可以将字符串与其他类型的值相连接,例如:

实例演示


public class StringJoinTest2 {
    public static void main(String[] args) {
        // 定义整型变量 age
        int age = 12;
        // 定义浮点型变量 height
        float height = 132.5f;
        // 定义一个字符串变量 name
        String name = "小明";
        // 将上面三个变量连接,拼成一个更长的字符串
        String result = name + "今年" + age + "岁了," + "他的身高为" + height + "cm";
        System.out.println(result);
    }
}
12345678910111213

可查看在线运行效果

运行结果:


小明今年10岁了,他的身高为132.5cm
代码块1

我们知道加法运算符除了可以连接字符串,也可以进行数学的加法运算。那我们再来看一个实例:

实例演示


public class StringJoinTest3 {
    public static void main(String[] args) {
        // 定义两个整型变量a、b
        int a = 100;
        int b = 200;
        // 打印一个空字符串+a+b的值
        System.out.println("" + a + b);
    }
}
123456789

运行案例点击 "运行案例" 可查看在线运行效果

试想屏幕上将会得到什么结果呢?编译执行代码:


$javac StringJoinTest3
java StringJoinTest
100200
代码块123

这里结果没有打印300
的原因很简单:按照从左到右的执行顺序,(空字符串 + 数值100
)的运算结果应该是字符串100
,然后再运算(字符串100
+数值200
),其最终结果为字符串100200
。由于运算中有字符串的存在,+
运算符在这里用于字符串的连接而不是数值的计算。

试想,如果将表达式中的操作数倒过来(即b + a + ""
),将得到什么结果呢?

 

3. 字符串的不可变性

字符串有一个重要特性:不可变性。也就是说,字符串一经创建便无法修改。我们来看一个示例:

实例演示


public class StringTest4 {
    public static void main(String[] args) {
        // 创建一个字符串 str
        String str = "hello imooc!";
        // 对 str 重新赋值
        str = "Java is great!";
        System.out.println(str);
    }
}
123456789

可查看在线运行效果

运行结果:


Java is great!
代码块1

童鞋们可能发现,咦?不是说字符串一旦创建就无法修改了吗,怎么str
变量依然被修改成了新的值?

这里直接给出答案:上述例子中,变量str
没有修改,而是变量str
的“指向”被修改了。

我们通过图示来描述上述代码的执行流程,首先创建一个str
,指向"hello imooc!":

当对str
重新赋值后,在内存中先创建了字符串"Java is great",然后改变了变量str
的指向,原来的"hello imooc!"并没有发生改变:

 

Java 数组

数组在编程语言中是非常重要的数据结构。本小节我们来一起学习 Java 数组,通过本小节的学习,你将了解到数组的基本概念,如何声明数组以及数组的声明有哪些方式,如何初始化数组以及数组初始化有哪些方式,数组的常用操作有哪些,多维数组的声明、创建、初始化以及迭代等等。多维数组部分将以二维数组进行为例讲解,理解了二维数组,再去理解多维数组就相对容易了。

 

1. 什么是数组

数组是相同类型的数据按照顺序组成的一种引用数据类型

Java 中有基本数据类型和引用数据类型两种数据类型。数组就是引用数据类型。

 

2. 数组声明

在Java语言中,数组声明有两种语法:

  • 中括号跟在数据类型后DataType[] arrayName;

  • 中括号跟在数组名称后DataType arrayName[];

其中DataType
是数组中要存放元素的数据类型,例如int
String
等,arrayName
是数组名称,遵守变量的命名规范。

在实际的编码中,我们更常用的是第一种语法。实例如下:


// 声明一个int类型的数组,名称为 firstIntArray:
int[] firstIntArray;  // 推荐写法
int firstIntArray[];
代码块123

也可以修改数据类型,以生成其他类型的数组。实例如下:


// 声明一个float类型的数组:
float[] firstFloatArray;
// 声明一个字符串类型的数组:
String[] firstStringArray;
代码块1234

 

3. 数组创建

 

3.1 先声明再创建

先声明再创建,需要编写两条语句:


DataType[] arrayName;
arrayName = new DataType[数组长度];
代码块12

数组的创建使用new
关键字,后面跟上一个空格+数据类型+中括号[]
,中括号中间是数组的长度,这里是必须指定的,它是一个整型的数字。实例如下:


// 声明一个整型的数组:
int[] intArray;
// 创建数组,长度为10
intArray = new int[10];
代码块1234

 

3.2 声明时同时创建

声明时同时创建,需要编写一条语句:


DataType[] arrayName = new DataType[数组长度];
代码块1

实例如下:


// 声明时同时创建
int[] intArray = new int[10];
代码块12

数组声明用到的中括号,也可以放到数组名称的后面,实例如下:


int intArray[] = new int[10];
代码块1

所创建的数组数据类型必须与其声明的数据类型相同。对于其他类型数组的创建,实例如下:



// 创建一个数据类型为字符串、长度为5的数组:
String[] stringArray = new String[5];
// 创建一个数据类型为双精度浮点型、长度为10的数组:
double[] floatArray = new double[10];
// 创建一个数据类型为字符型、长度为10的数组:
char[] charArray;
charArray = new char[10];
代码块123456789

 

4. 数组初始化

数组创建后,所有元素都初始化为默认值,整型数组的元素都为 0,浮点型都为 0. 0 ,布尔型都为 false
。例如 int[] arr = new int[5];
语句创建了一个数组,它在结构可参考下图:

除了数组的默认初始化,还有另外两种常见形式:

  1. 静态初始化

  2. 动态初始化

下面我们将分别介绍两种数组的初始化形式。

 

4.1 静态初始化

静态初始化数组,就是声明的同时,给数组赋值。其语法为:


DataType[] arrayName = {元素1, 元素2, 元素3, 元素n};
代码块1

赋值符号右边为用中括号所包围的 n 个元素,实例如下:


int[] arr = {1, 2, 3, 4, 5};
代码块1

上面数组arr
存放的元素为从 1 到 5 这几个整型。其的长度为 5 。数组的长度就是初始化时所给数组元素的个数。

 

4.2 动态初始化

动态初始化数组,即数组的声明以及创建是与数组的赋值操作分开进行的。实例如下:


// 声明并创建数组,长度为3
int[] arr = new int[3];
// 给下标位置0赋值为1
arr[0] = 1;
// 给下标位置1赋值为2
arr[1] = 2;
// 给下标位置2赋值为3
arr[2] = 3;
代码块12345678

数组是有下标的,下标从0开始,因此长度为 3 的数组,最大下标为 2 。下图展示了上述代码的执行流程:

 

5. 数组的操作

 

5.1 数组元素的引用

语法:数组名[下标],下标从0
开始。有一个整型数组,引用其第一个元素,实例如下:

实例演示


public class ArrayDemo {
    public static void main(String[] args) {
        // 初始化整型数组arr:
        int[] arr = {1, 2, 3};
        // 引用arr的第一个元素:
        int element1 = arr[0];
        System.out.println("数组arr中,第一个元素为:" + element1);
    }
}
123456789

可查看在线运行效果

运行结果:


数组arr中,第一个元素为:1
代码块1

注意,上面的数组下标最大为 2,也就是说,引用元素时,不能超过其下标最大值。下面是一个反例:


public class OutOfIndexDemo {
  public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        // 引用arr的第四个元素:
        int element4 = arr[3];
    }
}
代码块1234567

由于数组中只有三个元素,但引用了索引为3的第四个元素,编译执行代码,会抛出如下异常:


Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at OutOfIndexDemo.main(OutOfIndexDemo.java:5)
代码块12

 

5.2 数组元素的修改

既然可以引用数组元素,就可以修改元素,实例如下:

实例演示


public class ArrayDemo1 {
    public static void main(String[] args) {
        // 初始化整型数组arr:
        int [] arr = {1, 2, 3};
        // 修改下标为1的元素为4
        arr[1] = 4;
        System.out.println("数组arr中,第二个元素为:" + arr[1]);
    }
}
123456789

可查看在线运行效果

运行结果:


数组arr中,第二个元素为:4
代码块1

 

5.3 获取数组长度

我们可以使用数组的内置属性length
来获取数组的长度,使用点操作符调用其内置属性:arrayName.length
。实例如下:

实例演示


public class ArrayDemo2 {
    public static void main(String[] args) {
        // 初始化整型数组arr:
        int[] arr = {1, 2, 3};
        // 打印数组arr的长度:
        System.out.println("数组arr的长度为:" + arr.length);
    }
}
12345678

可查看在线运行效果


数组arr的长度为:3
代码块1

有时我们想引用数组中最后一个元素,由于数组下标从0开始,所以最后一个元素的下标为数组的长度减去1,这时可以结合length
属性来进行引用。实例如下:

实例演示


public class ArrayDemo3 {
    public static void main(String[] args) {
        // 初始化一个char类型的数组:
        char[] charArr = {'I', 'm', 'o', 'o', 'c'};
        // 引用最后一个元素:
        char lastElement = charArr[charArr.length-1];
        System.out.println("charArr数组的最后一个元素为:" + lastElement);
    }
}
123456789

可查看在线运行效果


charArr数组的最后一个元素为:c
代码块1

 

5.4 数组的迭代

5.4.1 循环赋值

我们知道了数组如何赋值,在实际的编码中,对整型数组循环赋值是很常用的。

实例:

运行结果:

实例演示


public class ArrayDemo4 {
    public static void main(String[] args) {
        // 声明一个整型数组
        int[] arr = new int[10];
        // 使用for循环对数组arr进行遍历,将数字1到10赋值给数组arr
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i + 1;
        }
        // 循环赋值完成,此时 arr = {1,2,3,4,5,6,7,8,9,10}
        // 遍历数组,打印数组中每一个元素
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t");
        }
    }
}
123456789101112131415

可查看在线运行效果


12345678910
代码块1

5.4.2 循环引用

我们可以使用循环引用依次打印数组中的每个元素。

实例如下:

实例演示


public class ArrayDemo5 {
    public static void main(String[] args) {
        // 初始化一个整型数组
        int[] arr = {1,2,3,4,5};
        // 使用for循环遍历数组arr
        for (int i = 0; i < arr.length; i++) {
            // 打印位置i的元素
            System.out.println("索引位置" + i + "的元素为:" + arr[i]);
        }
    }
}
1234567891011

可查看在线运行效果

运行结果:


索引位置0的元素为:1
索引位置1的元素为:2
索引位置2的元素为:3
索引位置3的元素为:4
索引位置4的元素为:5
代码块12345

5.4.3 增强 for 循环

上一小节我们提到for each
循环可以更简单地对数组进行迭代。以下是for each
循环的语法结构:


for(变量声明: 数组或列表) {
    // 循环体
}
代码块123

我们来看一个实例:

实例演示


public class ForEachLoop {
    public static void main(String[] args) {
        // 初始化字符串数组 words
        String[] words = {"Welcome ", "to ", "imooc"};
        for(String word: words) {
            System.out.print(word);
        }
    }
}
123456789

可查看在线运行效果

运行结果:


Welcome to imooc
代码块1

实例中遍历了一个单词数组,并且将它们打印成了一个句子。for each
循环对words
数组进行了遍历,并依次将每个索引的值赋值给了word
变量,然后再执行循环体中的语句。显然 for each
循环的代码看起来更加清晰。但增强for
循环
无法指定遍历顺序,也无法获取数组的索引。

5.4.4 更多实例

对于数组的循环还有很多案例,下面我们一起来学习几个。

实例1,求整型数组中,偶数元素的累加和:

实例演示


public class ArraySumDemo {
    public static void main(String[] args) {
        // 初始化变量sum,用于存放累加和
        int sum = 0;
        // 创建一个包含100个元素的整型数组
        int[] arr = new int[100];
        // 对arr进行循环赋值,将整数1~100赋值到数组中
        for(int i = 0; i < arr.length; i++) {
            arr[i] = i + 1;
        }
        // 遍历赋值好的数组
        for(int i = 0; i < arr.length; i++) {
            if(arr[i] % 2 == 0) {
                // 如果当前元素对二取余等于0,则为偶数,执行累加计算
                sum += arr[i];
            }
        }
        // 数组循环计算结束,输出最终结果
        System.out.println("数组arr中偶数元素的累加和为:" + sum);
    }
}
123456789101112131415161718192021

可查看在线运行效果

运行结果:


数组arr中偶数元素的累加和为:2550
代码块1

实例2,求数组中最大值:

实例演示


public class ArrayGetMaxDemo {
    public static void main(String[] args) {
        int[] arr = {20, 30, 15, 70, 92, 11};
        int max = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        System.out.println("最大值为:" + max);
    }
}
123456789101112

可查看在线运行效果

运行结果:


最大值为:92
代码块1

实例3,使用for each
循环遍历整型数组,获取数组中的最小值:

实例演示


public class ArrayGetMinDemo {
    public static void main(String[] args) {
        int[] arr = {20, 30, 15, 70, 92, 11};
        int min = arr[0];
        for(int n: arr) {
            if(n < min) {
                min = n;
            }
        }
        System.out.println("最小值为:" + min);
    }
}
123456789101112

可查看在线运行效果

运行结果:


最小值为:11
代码块1

 

6. 多维数组

在Java中,多维数组也是非常常用的数据结构,下面以二维数组为例,介绍二维数组的声明、创建、初始化和引用。

 

6.1 声明

二维数组有 3 种声明方式:

  • 中括号跟在数据类型后DataType[][] arrayName;
    (最推荐写法)

  • 中括号跟在数组名后DataType arrayName[][];

  • 中括号一个在前,一个在后DataType[] arranName[];

实例:


// 声明一个整型的二维数组
int[][] intArray;
// 声明一个单精度浮点型的二维数组
float floatArray[][];
// 声明一个char类型的二维数组
char[] charArray[];
代码块123456

 

6.2创建

二维数组可以想象成一个存放数据的表格,二维数组的创建和一维数组相似。可以声明数组的同时创建:


javaDataType[][] arrayName = new int[行数][列数];
代码块1

也可以先声明再创建:


DataType[][] arrayName;
arrayName = new DataType[行数][列数];
代码块12

实例:


// 声明并创建一个2行3列的数组
int[][] intArray = new int[2][3];
// 声明一个单精度浮点型的二维数组
float floatArray[][];
// 创建一个3行3列的二维数组
floatArray = new float[3][3];
代码块123456

在创建数组的时候,我们也可以先不指定列的数量,再在后面进行逐行创建。

实例:


// 创建一个3行的二维数组
int intArray[][] = new int[3][];
// 第一行3列
intArray[0] = new int[3];
// 第二行2列
intArray[1] = new int[2];
// 第三行1列
intArray[2] = new int[1];
代码块12345678

 

6.3 初始化

多维数组也有静态初始化和动态初始化之分,对于静态初始化,一维数组使用一对大括号{}
包含其元素,而二维数组的初始化可以使用两对大括号包含行数和列数。实例如下:


// 创建一个3行2列的二维数组
int[][] intArray = {{1,2}, {3,4}, {5,6}};
代码块12

动态初始化实例如下:


// 声明并创建一个数组
int intArray[][] = new int[2][3];
// 为第1行第1列的元素赋值:
intArray[0][0] = 10;
代码块1234

Tips:为数组赋值时,要注意数组的下标索引是从0开始的。

一维数组可以通过length
属性获取元素个数,同样二维数组的行数和列数也可以使用length
属性获取。实例如下:

实例演示


public class ArrayDemo6 {
    public static void main(String[] args) {
        // 初始化一个3行2列的二维数组
        int[][] intArray = {{1,2,7}, {3,4}, {5,6}};
        // 获取intArray的行数
        System.out.println("intArray的行数为:" + intArray.length);
        // 获取intArray第1行的列数
        System.out.println("intArray第一行的列数为:" + intArray[0].length);
    }
}
12345678910

可查看在线运行效果

运行结果:


intArray的行数为:3
intArray第一行的列数为:3
代码块12

 

6.4 二维数组的迭代

一维数组使用单层for
循环就可以遍历,二维数组的遍历需要使用双层嵌套for
循环。

实例:

实例演示


public class ArrayDemo7 {
    public static void main(String[] args) {
        // 初始化一个3行2列的二维数组
        int[][] intArray = {{1,2,7}, {3,4}, {5,6}};
        // 遍历intArray
        for(int i = 0; i < intArray.length; i++) {
            for(int j = 0; j <intArray[i].length; j++) {
                // 打印索引位置[i][j]的元素:
                System.out.println((i+1) + "行" + (j+1) + "列的元素为:" + intArray[i][j]);
            }
            // 打印一个空行
            System.out.println();
        }
    }
}
123456789101112131415

可查看在线运行效果

运行结果:


1行1列的元素为:1
1行2列的元素为:2
1行3列的元素为:7
2行1列的元素为:3
2行2列的元素为:4
3行1列的元素为:5
3行2列的元素为:6
代码块123456789

 

1、本小节我们学习了 Java 数组,知道了数组是引用数据类型。它在创建时,会在内存中开辟一个连续的空间;数组是同一数据类型的集合。可以使用数组下标来引用数组元素,数组元素的下标都是从0开始,使用下标不要超出范围,否则会抛出异常。可以使用length
属性获取数组的长度。对于多维数组,实际开发中建议不要使用超过三维的数组,否则会让你的程序难以理解和维护。

2、通过本小节的学习,我们了解了字符类型char
是基本数据类型,而字符串类型String
是引用类型。在创建字符串时,我们可以使用双引号表示,从Java 13
起,加入了多行字符串的表示方法。字符串的连接操作是使用加法运算符实现的。最后要特别注意字符串的不可变性,这在面试中经常会考到。

3、本节中,我们依次介绍了Java
中的四种循环结构:while
循环、do while
循环、for
循环以及for each
循环。并且介绍了break
continue
关键字在循环中的使用。

其中,while
循环的循环体可能一次都不执行,而do while
循环的循环体至少执行一次。

for
循环通过计数器实现复杂循环。for each
循环可以直接遍历数组的每个元素。

在使用循环结构编写业务代码时,为了避免死循环,一定要确保循环条件能够被影响。

4、在 Java 中,条件语句主要有 if
语句和 switch
语句两种。在实际的编码中,条件语句非常常用,要根据合适的场景选择使用,例如对于多个 ==
判断的情况下,使用 switch
语句就更加清晰。而对于复杂的条件表达式,选择 if
语句就更适合。

对于 if
语句的使用,建议:

  1. 每个分支都要用 {}
    括起来;

  2. 当有多个 if ... else
    的时候,要注意判断顺序,把可能性越大的分支越排在越前面;

  3. if ... else
    语句的嵌套层级不要太深。

对于 switch
语句的使用,建议:

  1. 每个分支都不要漏写 break

  2. 总是写上 default
    分支。

5、本节我们学习了表达式,它的计算结果为单独的值。还要特别注意前后自增 / 自减的区别,要理解逻辑运算符在表达式中的短路作用,这在任何语言的基础面试中都会经常考到。对于语句和块的概念,我们也有了一个初步的认识,想要完全理解这些内容,还需要继续向下学习更多知识。下一小节开始,我们将学习 Java 条件语句、循环语句等内容,这些都将加深你对本节概念的理解。

6、本小节我们按照分类介绍了Java
的运算符,并且在最后给出了运算符的优先级表格。本节内容可能有些繁杂,但细节不必全部记住,你可以在需要的时候回过头来查查表格。当然,最好的方式还是多写多练,对照实例和表格自己敲敲代码,用心分析代码执行的流程,是增强记忆最好的方式。

7、学完了本小节,我们来回顾一下,Java 提供两大类型:基本数据类型和引用数据类型。一共有 8 种基本数据类型。基本类型又可分为数字型(整型和浮点型),字符型以及布尔型。在编码时要注意,为变量所赋的值不要超出其类型的范围。

8、在本小节中,我们知道了变量是存储数据的载体,声明变量时要注意变量的命名规范,给变量赋值时要根据声明的数据类型赋值。

Java 中变量有4个种类,分别是:实例变量、类变量、局部变量、参数。其中变量如果使用了final
关键字修饰,就可定义一个不可变的常量。

当然,需要再次强调的是:不要使用中文拼音来命名变量,这是很常见的但非常不好的习惯。英文基础差的童鞋可以下载一个英文词典,当你要选择一个变量的名称时,多查阅一下单词,选择出最符合变量特征的单词。好的变量命名不仅让你的代码易于阅读理解,也有助于你更好地梳理实际编码中繁琐的业务逻辑。

9、本小节我们学习了 Java 的基础语法。我们知道了 Java 语言区分大小写,类是一个程序的基本单位,所以说我们要编写 Java 代码,就要知道如何声明一个类,而类中的主方法是一个程序执行的起点。标识符是我们程序员在编程时所使用的名字,当我们为标识符命名时,一定不能使用 Java 中的关键字。理解了注释的概念和分类,另外也建议大家在编写代码的过程中多写注释,在学习别人代码的过程中多看注释。我们也将在后面的示例代码中加入大量的注释来帮助你理解程序。


文章转载自编码逻辑,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论