Skip to content

2. Java 基础语法

2.1 标识符 ✅

什么是标识符

  1. 在 Java 中,标识符是用来给变量、方法、类和包等命名的字符序列。
  2. 标识符的长度没有限制,但是建议使用有意义的、简洁的标识符,以提高代码的可读性和可维护性。

标识符标识符可以标识什么?

  1. 变量名

  2. 方法名

  3. 类名、接口名、枚举名、注解名

  4. 包名

  5. 常量名

......

标识符命名规则

  1. 标识符可以由字母、数字、下划线(_)和美元符号($)组成,不能含有其他符号。(java 支持全球所有语言,所以这里的 字母 指的是任何一个国家的文字都可以)。

  2. 标识符不能以数字开头。

  3. 标识符不能是 Java 中的关键字,如 public、class、void 等。

  4. 标识符是区分大小写的,即 Foo 和 foo 是两个不同的标识符。

  5. 标识符的长度没有限制,但是 Java 建议使用有意义的、简短的标识符。

标识符命名规范

  1. 见名知意

  2. 驼峰式命名方式

  3. 类名、接口名、枚举、注解:首字母大写,后面每个单词首字母大写。(StudentService,UserService)

  4. 变量名和方法名:首字母小写,后面每个单词首字母大写。(doSome,doOther)

  5. 常量名:全部大写,每个单词用下划线连接。(LOGIN_SUCCESS,SYSTEM_ERROR)

  6. 包名:全部小写

2.2 关键字 ✅

什么是关键字

Java 关键字是 Java 编程语言中预定义的具有特殊含义的单词,这些单词不能被用作标识符,而是在语法中有特定的用法和限制。

Java 关键字有哪些

  1. Java 关键字都是小写的;
  2. abstract, assert, boolean, break, byte, case, catch, char, class, continue, default, do, double, else, enum, extends, final, finally, float, for, if, implements, import, instanceof, int, interface, long, native, new, package, private, protected, public, return, short, static, strictfp, super, switch, synchronized, this, throw, throws, transient, try, void, volatile, while
  3. Java 保留字:gotoconst

2.3 字面量 ✅

什么是字面量

字面量指的是在程序中直接使用的数据,字面量是 Java 中最基本的表达式,不需要进行计算或转换,直接使用即可。

Java 中有哪些字面量

  • 整数型:10、-5、0、100
  • 浮点型:3.14、-0.5、1.0
  • 布尔型:true、false
  • 字符型:'a'、'b'、'c'、'1'、'2'、'国'
  • 字符串型:"Hello"、"World"、"Java"、"你好呀"

2.4 变量 ✅

什么是变量?

  1. 变量是内存当中的一块空间。是计算机中存储数据最基本的单元。
  2. 变量三要素:
    • 数据类型(决定空间大小)【int, double, String】
    • 变量名(只要是合法的标识符即可)
    • 变量值(变量中具体存储的数据)
  3. 变量的声明、赋值、访问
    • int i; //声明一个整数型的变量,起名
    • i = 100; //给变量 i 赋值 100
    • System.out.println(i); //访问 i 变量:读操作
    • i = 200; //访问 i 变量:改操作【给变量 i 重新赋值 200】

变量的作用

  1. 变量的存在会让程序更加便于维护。
Java
System.out.println(100 + 111);
System.out.println(100 + 222);
// 以上代码的设计就不如以下的代码:
int num = 100;
System.out.println(num + 111);
System.out.println(num + 222);
  1. 变量的存在可以增强程序的可读性。
Java
System.out.println(3.14 * 10 * 10);
// 以上代码的设计就不如以下的代码:
double π = 3.14;
int r = 10;
System.out.println* r * r);

变量的小细节

  1. 变量必须先声明,再赋值,才能访问;
  2. 方法体当中的代码遵循自上而下的顺序依次逐行执行,变量先访问,再声明肯定是不行的;
  3. 一行代码上可以同时声明多个变量;
  4. 在同一个作用域当中,变量名不能重名,可以重新赋值;
  5. 变量值的数据类型必须和变量的数据类型一致,这样是不允许的:String name = 100;

变量的作用域

  • 作用域就是变量的有效范围。变量的作用域是怎样的呢?用一句大白话就可以概括了:出了大括号就不认识了。
  • 作用域的不同主要是因为声明在不同位置的变量具有不同的生命周期。所谓的生命周期是:从内存开辟到内存释放。
  • Java 遵循就近原则。

变量的分类

  • 局部变量
  • 成员变量
    • 静态变量
    • 实例变量

2.5 二进制、八进制与十六进制 ⭐

二进制概述

计算机底层只能识别二进制。计算机底层只识别二进制是因为计算机内部的电子元件只能识别两种状态,即开和关,或者高电平和低电平。二进制正好可以用两 种状态来表示数字和字符,因此成为了计算机最基本的表示方法。在计算机内部,所有的数据都被转化为二进制形式进行处理和存储。虽然计算机可以通过不同的编程语言和程序来处理不同的数据类型和格式,但最终都需要将其转化为二进制形式才能被计算机底层识别和处理。

十进制与二进制的转换

十进制 -> 二进制:除 2 取余,一直到商为 0,最后将所有的余数逆序输出。 二进制 -> 十进制:每一位与权值相乘求和。

十进制与八进制的转换

十进制与十六进制转换

二进制与十六进制转换

2.6 原码反码补码 ✅

byte 与 bit

  • byte(字节)是计算机存储和处理数据的基本单位,通常由 8 个比特(bit)组成。每个比特是计算机中最小的存储单位,只能存储 0 或 1 两个状态。因此,一个字节可以存储 8 个比特的数据。
  • 两者之间的关系是:1 byte = 8 bit,即 8 个比特(bit)组成一个字节(byte)。
  • 在计算机中,数据通常以字节(byte)为单位进行存储和传输,而比特(bit)则是用来表示数据的最小单位。
  • 1KB = 1024byte
  • 1MB = 1024KB
  • 1GB = 1024MB
  • 1TB = 1024GB

原码、反码、补码

  1. 原码、反码、补码是计算机二进制的三种表示形式;
  2. 计算机在底层都是采用二进制补码形式表示的;
  3. 二进制位最高位成为符号位,0 为正数,1 为负数。

正数的原码、反码、补码

  1. 正数的原码、反码、补码是相同;
  2. 请问正数 127 的原码、反码、补码分别是多少?(三者都是:0111 1111)

负数的原码、反码、补码

  1. 负数的原码运算规则:将绝对值转化为二进制后,最高位改为 1;
  2. -5 的原码:10000101;
  3. -5 的反码:11111010;(原则是:以原码作为参考,符号位不变,其他位取反
  4. -5 的补码:11111011;(原则是:以反码作为参考,符号位不变,加 1
  5. 补码 -> 原码:补码最高位不变,其余取反加 1;
  6. -128 的原码、反码、补码:
    • 原码:1000 0000
    • 反码:1111 1111
    • 补码:1000 0000

一个比特(1 bit)可以表示的数的范围:-128~127。

计算机底层为什么采用补码

  1. 可以简化电路设计:采用补码形式可以将加减法运算转化为相同的操作,从而简化电路设计。
  2. 解决了 0 的正负问题:在原码中,0 有两个表示,+0 和-0,这样会导致计算结果不唯一,而在补码中,0 只有一种表示,即全 0,可以避免这个问题。
  3. 解决了负数溢出问题:在原码中,负数的表示范围比正数少 1,这样在进行减法运算时容易出现负数溢出的情况,而在补码中,负数的表示范围与正数相同,可以避免负数溢出的问题。
  4. 方便计算机进行运算:补码形式可以方便计算机进行加减法运算,而且可以使用相同的电路进行运算,从而提高了计算机的运算效率。

2.7 数据类型 ✅

基本数据类型

  1. 整数型
  • byte: 小整数

  • short: 中等大小整数

  • int: Java 最常用的整数

  • long: 极大或极小的整数 (BigInteger)

自动类型转换:

Java 中任何一个整数型字面量都会默认被当做 int 类型来处理。Java 中允许小容量的数据赋值给大容量的变量(自动类型转换)。取值容量排序: byte < short < int < long < float < double

强制类型转换

① Java 中大容量是无法直接转换成小容量的,因为这种操作可能会导致精度损失。

② 强制类型转换时,底层二进制是如何变化的?原则:砍掉左侧多余的二进制。

③ 强制类型转换时,精度可能会损失,也可能不会损失,这要看具体的数据是否真正的超出了强转后的类型的取值范围。

byte 的赋值:

① 在 Java 中有这样一个规定,当整数型字面量没有超出 byte 的范围:可以直接赋值给 byte 类型的变量。 byte b = 127; 这是允许的,很显然,这是一种编译优化。同时也是为了方便程序员写代码。

② 如果超出了范围,例如: byte b = 128; (编译报错)。这样就会报错,需要做强制类型转换,例如: byte b = (byte)128; (结果为-128)

③ 在整数类型中,除了 byte 有这个待遇之外, short 同样也是支持的。也就是说:如果整数型字面量没有超出 short 取值范围时,也是支持直接赋值的。

注:short 的赋值用法类似。

两个 int 类型做运算

① 两个 int 类型的数据做运算,最终的结果还是 int 类型;

多种数据类型混合运算

① 在 Java 中,多种数据类型混合运算时,各自先转换成容量最大的类型,再做运算

Java
byte a = 100;
int b = 200;
long c = 300L;
long d = a + b + c;
// 测试一下,如果 d 变量是 int 类型则编译器会报错

byte 和 short 混合运算的时候,各自先转换成 int 再做运算。

  • byte + byte ---> int
  • byte + short ---> int
  • short + short ---> int
Java
short m = 10;
byte n = 10;
short result = m + n; // 编译器报错
int result = m + n; // 正确
  1. 浮点型
  • float: 单精度,精度为 7 位小数

-double: 双精度,精度为 15 位小数,Java 中最常用的浮点类型。(BigDecimal)

浮点型字面量默认被当做 double

  • Java 中,浮点型字面量默认被当做 double 类型,如果要当做 float 类型,需要在数字后面添加 F 或 f。
Java
float f = 3.0; // 编译报错
// 报错原因是:3.0 默认被当做 double 类型,大容量无法直接赋值给小容量。可以修改为:
float f = 3.0F;
  • double 精度高于 float:
Java
double d = 1.5656856894;
System.out.println(d); // 1.5656856894

float f = 1.5656856894F;
System.out.println(f); // 1.5656856

浮点型数据两种表示形式:

  • 十进制
Java
double x = 1.23;
double y = 0.23;
double z = .23;
  • 科学计数法
Java
double x = 0.123E2; // 0.123 * 10 的平方
double y = 123.34E-2; // 123.34 / 10 的平方

浮点型数据存储原理⭐ :

  • 符号位:0 表示整数。1 表示负数。
  • 指数位:比如小数 0.123E30,其中 30 就是指数。表示 0.123 * 10 的 30 次幂。所以也有把指数位叫做偏移量的。最大偏移量 127。
  • 尾数位:浮点数的小数部分的有效数字。例如:0.00123,那么尾数位存储 123 对应的二进制。
  • 从浮点型数据存储原理上可以看到,二进制中的指数位决定了数字呈指数级增大。因此 float 虽然是 4 个字节,但却可以表示比 long 更大的数值。因此 float 容量比 long 的容量大。

alt text

浮点型数据使用注意事项

一旦有浮点型数据参与运算得出的结果,一定不要使用“==”与其它数字进行“相等比较”

Java
// 不要这样使用
double x = 6.9;
double y = 3.0;
double z = x / y; // 2.3000000000000003
if(z == 2.3) {
    System.out.println("相等");
}
// 可以这样比较
double x = 6.9;
double y = 3.0;
double z = x / y;
if(z - 2.3 < 0.000001) {
    System.out.println("相等");
}
  1. 布尔型
  • boolean: 主要用于逻辑判断

在 Java 中 boolean 类型只有两个值:true、false。没有其它值,没有 0 和 1 这一说。通常用于表示一些逻辑上的真假值,并在程序中进行逻辑控制,例如以下代码:

Java
boolean gender = true;
if(gender) {
    System.out.println("男");
} else {
    System.out.println("女");
}
  1. 字符型
  • char: 单个字符

  • 占用两个字节,取值范围:0 ~ 65535,和 short 容量相同,但 char 可以取更大的整数;

  • 单个字符,使用单引号括起来,不能是多个字符;

  • 可以保存一个汉字;

  • char c = ''; 这是不允许的;

  • char c = '\u0000'; 这表示一个空字符,也是 char 的默认值。\u0000 是一个 Unicode 码;(空格的 Unicode 码是 \u0020)

  • 空字符与空格字符是不同的。空字符表示什么也没有。空格字符表示一个空格。

转义字符:

  • \t: 表示制表符,相当于按下 Tab 键;
  • \n: 表示换行符;
  • \": 表示双引号(");
  • \': 表示单引号(');
  • \\: 表示反斜线(\)本身。

字符编码:

字符编码是人为规定的文字与二进制之间的转换关系。在早期计算机系统中,字符编码主要采用的是 ASCII 编码,采用 1 个字节编码。最多可以表示 256 个字符(实际上 ASCII 码表只用了 128 个),程序员需要记住这几个:

  • a 对应 ASCII 码 97(b 是 98,...)
  • A 对应 ASCII 码 65(B 是 66,...)
  • 0 对应 ASCII 码 48(1 是 49,...)

常见的字符编码⭐ :

  • ASCII 编码(American Standard Code for Information Interchange:美国信息交换标准编码):采用 1 个字节编码,包括字母、数字、符号和控制字符等。
  • Latin-1 编码(ISO 8859-1),采用 1 个字节编码。该编码方式是为了表示欧洲语言(如荷兰语、西班牙语、法语、德语等)中的字符而设计的,共支持 256 个字符。
  • ANSI 编码(American National Standards Institute:美国国家标准协会):采用 1 个字节编码,支持英文、拉丁文等字符。两个 ANSI 码可以表示一个汉字。
  • Unicode 编码:可表示所有语言的字符。采用了十六进制表示,占用 2 个字节或 4 个字节,最多可表示超过一百万个字符。(使用这种方式是有点浪费空间的,例如英文字符'a'其实采用一个字节存储就够了)Unicode 在线转码工具
  • UTF-8 编码(Unicode Transformation Format,8-bit):基于 Unicode 编码的可变长度字符编码,能够支持多语言和国际化的需求,使用 1~4 个字节来表示一个字符,是目前 Web 开发中最常用的字符编码方式。 (一个英文字母 1 个字节,一个汉字 3 个字节)
  • UTF-16 编码:基于 Unicode 编码的可变长度字符编码,使用 2 或 4 个字节来表示一个字符,应用于很多较早的系统和编程语言中。 (一个英文字母 2 个字节。一个汉字 4 个字节。)
  • UTF-32 编码:基于 Unicode 编码的固定长度字符编码,其特点是每个字符占用 4 个字节。
  • GB2312 编码(小):是中国国家标准的简体中文字符集,使用 2 个字节来表示一个汉字,是 GBK 编码的前身。
  • GBK 编码(Guo Biao Ku)(中):是针对中文设计的一个汉字编码方式,使用 2 个字节来表示一个汉字,能够表示中国内地的所有汉字。
  • GB18030 编码(大):是中国国家标准 GB 18030-2005《信息技术 中文编码字符集》中规定的字符集编码方案,用于取代 GB2312 和 GBK 编码。
  • Big5 编码(大五码):是台湾地区的繁体中文字符集,使用 2 个字节来表示一个汉字,适用于使用繁体中文的应用场景。

char 参与的运算:

Java 中允许将一个整数赋值给 char 类型变量,但这个整数会被当做 ASCII 码值来处理需要特别注意的是,这个码值有要求,不能超出 char 的取值范围。 只要没有超出 byte short char 的取值范围,是可以直接赋值给 byte short char 类型变量的。

Java
System.out.println('a' + 1); // 98
char c = 'a' + 1;
System.out.println(c); // b

// 以下程序结果是什么?
byte a = 1;
short b = 1;
char c = 1;
short num = a + b + c; // 编译器报错

注意,byte short char 混合运算时,各自会先转换成 int 再做运算!

数据类型占用字节数取值范围具体取值范围默认值
byte127 ~ 271-128 ~ 1270
short2215 ~ 2151-32768 ~ 327670
int4231 ~ 2311-2147483648 ~ 21474836470
long8263 ~ 2631-9223372036854775808 ~ 92233720368547758070L
float41.4E-45 ~ 3.4028235E381.4E-45 ~ 3.4028235E380.0f
double84.9E-324 ~ 1.79769313448623157E3084.9E-324 ~ 1.79769313448623157E3080.0d
boolean1true/falsetrue/falsefalse
char20 ~ 21610 ~ 65535'\u0000'

关于默认值: Java 语言中变量必须先声明,再赋值,才能使用。对于局部变量来说必须手动赋值,而对于成员变量来说,如果没有手动赋值,系统会自动赋默认值。

引用数据类型

类、接口、数组、枚举等

2.8 运算符 ✅

概览:

  • 算术运算符:+、-、*、/、%、++、--
  • 关系运算符:==、!=、>、>=、<、<=
  • 逻辑运算符:&、|、!、&&、||
  • 按位运算符:&、|、^、~、<<、>>、>>>
  • 赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=、>>>=
  • 条件运算符:?:
  • instanceof 运算符:instanceof
  • new 运算符:new
  • . 运算符:.

算数运算符

  • + :求和、字符串拼接、正数
  • - :相减、负数
  • * :乘积
  • / :商(除法)
  • % :取模(求余数),取模公式:x - x / y * y
  • ++ :自加 1
  • -- :自减 1

关系运算符

关系运算符又叫做比较运算符。包括: >>=<<===!= 。所有关系运算符的运算结果都是布尔类型,不是 true,就是 false。

Java
int a = 10;
int b = 10;
System.out.println(a > b); // false
System.out.println(a >= b); // true
System.out.println(a < b); // false
System.out.println(a <= b); // true
System.out.println(a == b); // true
System.out.println(a != b); // false

逻辑运算符

逻辑运算符: & (逻辑与)、 | (逻辑或)、 ! (逻辑非)、 ^ (逻辑异或)、 && (短路与)、 || (短路或)。

逻辑运算符特点:逻辑运算符两边的操作数要求必须是布尔类型,并且最终运算结果也一定是布尔类型。

  • 逻辑与 &:两边操作数都是 true,结果才是 true。

  • 逻辑或 |:两边操作数只要有一个是 true,结果就是 true。

  • 逻辑非 !: !false 就是 true,!true 就是 false。

  • 逻辑异或 ^:咱俩不一样,结果就是 true。

  • 短路与 &&:和逻辑与&的运算结果相同。只是存在一种短路现象。(左边操作数为 false 时,右边操作数不执行)

  • 短路或 ||:和逻辑或|的运算结果相同。只是存在一种短路现象。(左边操作数为 true 时,右边操作数不执行)

虽然短路与 && 效率高于逻辑与 &,但逻辑与 & 也有用武之地,具体看需求是怎样的。

按位运算符

按位运算符用于在二进制位级别上处理整数数据。主要包括:

  • 左移 <<
  • 右移 >>
  • 无符号右移 >>>
  • 按位与 &
  • 按位或 |
  • 按位异或 ^
  • 按位取反 ~

注意:按位运算符的操作数要求必须是整数,否则会出现编译错误。

**左移 << **:

它能够将一个二进制数的所有位向左移动指定的位数。左移运算符的运算规则如下:

  1. 将二进制数左移 n 位,相当于将数值乘以 2 的 n 次方。例如,将二进制数 0b1011 左移 2 位,即为 0b101100,相当于将 11 乘以 2 的 2 次方(即 4),得到 44。>

  2. 左移运算符不会改变操作数的符号。左移后,右补 0。无论操作数是正数、负数还是零,左移运算符都只进行位级移动,不会改变符号。

  3. 左移运算符会对溢出进行截断。

例子:

Java
int c = -100;
// 原码:10000000 00000000 00000000 01100100
// 反码:11111111 11111111 11111111 10011011(原码取反)
// 补码:11111111 11111111 11111111 10011100(补码加1)
// 左移:11111111 11111111 11111110 01110000 (左移2位)

// 原码:10000000 00000000 00000001 10010000(-400)
System.out.println(c << 2); // -400(-100 * 2^2)

**右移 >> **:

它能够将一个二进制数的所有位向右移动指定的位数。右移运算符的运算规则如下:

  1. 将二进制数右移 n 位,相当于将数值除以 2 的 n 次方。例如,将二进制数 0b101100 右移 2 位,即为 0b1011,相当于将 44 除以 2 的 2 次方(即 4 ),得到 11。

  2. 右移运算符对正数、负数和零的处理方式不同。对于正数,符号位不变,右移时左补 0。对于负数,符号位不变,右移时左补 1。对于零,右移运算符操作后结果仍为零。

  3. 右移运算符会对溢出进行截断。

**无符号右移 >>> **:

它能够将一个二进制数的所有位向右移动指定的位数,而不考虑符号位。无符号右移运算符的运算规则如下:

  1. 将二进制数右移 n 位,相当于将数值除以 2 的 n 次方,并将最高位填充为 0;

  2. 任意一个数字经过无符号右移之后,最终结果一定是非负数(0 或正整数);

  3. 无符号右移运算符对溢出进行截断。

注意:byte 的无符号右移动

Java
byte b = -128;
System.out.println(b >>> 2); // 1073741792 并不是 -32
// byte 和 int 混合运算,会先将 byte 转换成 int,再做运算
System.out.println((byte)b >>> 2); // -32

**按位与 & **:

将两个整数的二进制表示按位进行与运算,只有当相应的二进制位都为 1 时,结果才为 1,否则结果为 0。

Java
int a = 32;
int b = 25;
System.out.println(a & b); // 0
// a的二进制: 00100000
// b的二进制: 00011001
// 按位与之后:00000000

应用

请使用按位与运算符判断某个数字是否为奇数?思路:拿着这个数字和 1 进行按位与,如果结果是 1,则表示该数字为奇数。

**按位或 | **:

将两个整数的二进制表示按位进行或运算,只有当相应的二进制位都为 0 时,结果才为 0,否则结果为 1。

Java
int a = 32;
int b = 25;
System.out.println(a | b); // 57
// a的二进制: 00100000
// b的二进制: 00011001
// 按位或之后:00111001

应用-设置标志位

请将 0 这个数字中第 4 位的二进制位设置为 1(按位或的具体应用,将某个二进制位设置为 1)

Java
int flag = 0;
flag = flag | (1 << 3);

**按位异或 ^ **:

将两个整数的二进制表示按位进行异或运算,只有当相应的二进制位不同,结果才为 1,否则结果为 0。

Java
int a = 100;
int b = 200;
System.out.println(a ^ b); // 172
// a的二进制:01100100
// b的二进制:11001000
// 按位异或之后:10101100

按位异或运算符具有自反性,所谓的自反性是指:数字 A 连续对数字 B 进行两次按位异或运算之后,可以得到原始的数字 A。因为按位异或运算符具有这样的特征,所以在密码学方面应用广泛。

应用

按位异或可以实现简单的加密和解密。

**按位取反 ~ **:

将整数的二进制表示按位进行取反运算,即 0 变为 1,1 变为 0。

Java
System.out.println(~100); // -101
// 100的二进制:01100100
// 取反后:10011011(这是一个补码哦)
// 将补码转为原码:11100101 (-101)

应用

位清除操作(将某个二进制位中指定位清除为 0),例如有这样一个二进制:0b01101101,将第 4 个低位清除为 0

Java
int value = 0b01101101;// 待清除数据
int flag = 1 << 3; // 需要清除第4个低位
int result = value & (~flag);// 使用这种方式运算进行位清除

赋值运算符

基本赋值运算符

= 等号右边先执行,将直接结果赋值给左边的变量

扩展赋值运算符

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

  2. += 为例。i += 3; 表示 i = i + 3;

  3. += 就是先 + 后 =,也就是先求和,然后将求和的结果重新赋值。

  4. 对于扩展赋值运算符来说,有一个非常重要的运算规则需要注意:扩展赋值运算符不会改变运算结果的类型。(即使精度损失了,也不会改变运算结果类型)

Java
byte m = 10;
m = m + 20; // 编译报错
m += 20; // 编译通过
m += 10000; // 编译通过

// m = m + 20; 不会进行强制类型转换,
// 而 m += 20; 会进行强制类型转换, m = (byte)(m + 20)。

条件运算符

Java 语言中的条件运算符由 ? 和 : 组成,也被称为三元运算符。它的语法格式为:

布尔表达式 ? 表达式 1 : 表达式 2;

当布尔表达式的值为 true 时,条件运算符的结果为表达式 1 的值,否则为表达式 2 的值。这种运算符常用于简化 if-else 语句的代码量。

Java
// 下面是一个条件运算符的简单示例:
int a = 5, b = 7;
int max = (a > b) ? a : b;
System.out.println("最大值为:" + max);

在上述代码中,首先定义了两个变量 a 和 b,然后使用条件运算符比较这两个变量的大小,取其中较大值作为变量 max 的值,最后输出结果。当 a > b 的结果为 false 时,条件运算符的结果为表达式 2,即 b 的值为变量 max 的值。当 a > b 的结果为 true 时,条件运算符的结果为表达式 1,即 a 的值为变量 max 的值。

总的来说,条件运算符在 Java 中的使用相对简单,能够减少代码重复和代码量,常用于简单的条件处理和表达式值的判断。

instanceof 运算符

new 运算符

. 运算符

2.9 控制语句 ✅

控制语句:用于控制程序的执行流程,改变程序执行的次序。

分支语句

if 语句

if 语句写法 1:

Java
if(布尔表达式) {
    分支语句;
}

如果布尔表达式 true,则执行分支语句。如果为 false,则不执行。

if 语句写法 2:

Java
if(布尔表达式) {
    分支1;
} else {
    分支2;
}

if 语句写法 3:

Java
if(布尔表达式) {
    分支1;
 }else if(布尔表达式) {
    分支2;
} else if(布尔表达式) {
    分支3;
}

if 语句写法 4:

Java
if(布尔表达式) {
    分支1;
} else if(布尔表达式) {
    分支2;
} else if(布尔表达式) {
    分支3;
} else {
    分支4;
}

switch 语句

Java
switch(expression) {
    case value1:
        // ...
        break;
    case value2:
        // ...
        break;
    case value3:
        // ...
        break;
    default:
        // ...
}

switch 语句使用注意事项:

  1. switch 语句适用于判断固定值。if 语句适用于判断范围或区间时使用。switch 能做的 if 肯定能做,if 能完成的 switch 不一定能完成。
  2. JDK7 之前,switch 只支持 int 类型枚举类型,在 JDK7 之后,增加了对字符串类型的支持。
  3. case 语句中的值必须是字面量,不能是变量。
  4. case 语句中的值必须和 switch 后面的值是同一类型,或者能够相互转换。
  5. case 可以合并。
  6. 在每个 case 分支中要加上 break 语句,以避免 case 穿透现象。
  7. 在 switch 语句中,一般都应该有一个 default 分支,用于处理一些特殊情况,以避免程序出错。(当然,default 语句不写,也不会编译报错)
  8. switch 语句中的 default 分支可以放在 switch 块的任意位置,但是通常建议将 default 分支放在所有 case 分支的最后面。(可读性好)

Java12 switch 新特性:

Java
// 写法1
switch(x) {
    case value1 -> 语句1;
    case value2 -> 语句2;
    default -> 语句3;
}
// 写法2
switch(x) {
    case value1, value2, value3 -> 语句1;
    default -> 语句2;
}
// 写法3
switch(x) {
    case 1 -> {
        语句1;
        语句2;
    }
}

循环语句

for 循环

Java
for(初始化表达式; 条件表达式; 更新表达式) {
    // 循环体
}
  • 初始化表达式最先执行,并且只执行 1 次;
  • 条件表达式执行结果必须是一个布尔类型的值;
  • 更新表达式用于更新变量值;

while 循环

while 循环语法格式:

Java
while(布尔表达式) {
    循环体;
}

执行原理:只要布尔表达式为 true 就会一直循环,直到布尔表达式结果为 false,循环结束。while 循环体的执行次数可能是:0 ~ n 次。 for 循环适用于循环次数固定的。while 循环适用于循环次数不固定的。

do while 循环

do while 循环语法格式:

Java
do {
    循环体;
} while(布尔表达式);

执行原理:先执行一次循环体,再判断布尔表达式,为 true 继续循环,直到布尔表达式结果为 false,循环结束。 do while 循环体的执行次数可能是:1 ~ n 次。do while 循环比较适合用在不管条件是否成立,第一次必须要执行的业务。

跳转语句

break 语句

break:

  • 出现在 switch 语句用来终止 switch 语句的执行。
  • 出现在循环中,用来终止循环的执行。
  • break; 用来终止离它最近的循环。
  • break 循环标记; 用来终止指定的循环。

continue 语句

continue:

  • 终止当前本次循环,直接进入下一次循环继续执行。
  • continue; 终止当前本次循环,直接进入离它最近的循环继续。
  • continue 循环标记; 终止当前本次循环,直接进入指定的循环继续。

break;return; 的区别:

  • break; 终止循环。
  • return; 终止方法。

2.10 方法 ✅

方法的定义和调用

方法(Method)是一段可以被重复利用的代码片段。一个方法一般都是一个独立的功能。在 C 语言中叫做函数(Function)。

语法格式:

Java
[修饰符列表] 返回值类型 方法名(形式参数列表){
    方法体;
}
  • 修饰符列表:可选项。目前固定写法 public static (后面讲解)。
  • 返回值类型:用来指定方法返回值的数据类型(方法执行结束后的结果类型)。只要是 Java 合法的数据类型,都可以,例如:byte, short, int, long, float, double, boolean, char, String...。如果方法执行结束时没有返回任何数据,返回值类型也不能空着,需要写 void 关键字。
  • 方法名:只要是合法的标识符即可。但最好见名知意。方法通常反应行为,所以方法名一般为动词
  • 形式参数列表:简称形参。用来接收数据。参数个数 0 ~ N 个。如果有多个,使用逗号隔开。例如(int a, double b, long c)。每一个形式参数都可以看做局部变量。
  • 每个方法都有方法体,方法体是一对大括号。在大括号中编写 Java 语句。
  • 方法的调用:如果修饰符列表中 static 关键字,采用“类名. 方法名(实际参数列表); ”调用方法。
    • 调用者和被调用者在同一个类中,“类名.”可以省略。
    • 实际参数列表:简称实参,实参和形参要一一对应,个数对应,数据类型对应。
  • 调用方法,如果方法执行结束后有返回值,可以采用变量接收该返回值。当然,也可以选择不接收。

方法执行时的内存变化

  • 方法只定义不调用是不会分配内存的。只是方法的字节码指令存储在元空间中。
  • 方法调用时会给该方法在 JVM 的栈内存中分配空间,此时发生压栈动作。这个方法的空间被称为栈帧。
  • 栈帧中主要包括:局部变量表,操作数栈等。
  • 方法执行结束时,该栈帧弹栈,方法内存空间释放。

alt text

方法重载

方法重载(overload):编译阶段的一种机制(静态多态)。

  1. 什么情况下构成方法重载?

    • 在同一个类中

    • 方法名相同

    • 参数列表不同:

      • 类型不同算不同
      • 顺序不同算不同
      • 个数不同算不同
  2. 什么时候我们考虑使用方法重载?

    • 在同一个类中,如果功能相似,建议使用方法重载。
  3. 方法重载好处?

    • 简化代码调用。
    • 更易维护。
    • 代码美观。

递归

  • 什么是方法的递归调用?方法自己调用自己。
  • 递归时,内存是如何变化的?
  • 递归使用注意事项?
    • 递归必须要有结束条件。
    • 递归和循环都能完成的话,优先选择循环。(递归更耗费内存。)
  • 递归有结束条件,就一定不会栈内存溢出吗?
  • 实际开发中,使用递归时,发生栈内存溢出,你该怎么办?
    • 首先可以调整栈内存的大小,扩大栈内存;

alt text

2.11 package 和 import ✅

package(包机制)

  • 包机制作用:便于代码管理。
  • 怎么定义包:在 java 源码第一行编写 package 语句。注意:package 语句只能出现在 java 代码第一行。
  • 包名命名规范中要求是全部小写。
  • 包名命名规范:公司域名倒序 + 项目名 + 模块名 + 功能名。例如:com.baidu.oa.empgt.service。 如果带包编译:javac -d + 编译后的存放目录 + java 源文件路径。
  • 有了包机制后,完整类名是包含包名的,例如类名是:com.powernode.javase.chapter02.PackageTest

import

  • import 语句用来引入其他类。
  • A 类中使用 B 类,A 类和 B 类不在同一个包下时,就需要在 A 类中使用 import 引入 B 类。
  • java.lang 包下的类不需要手动引入。
  • import 语句只能出现在 package 语句之下,class 定义之前。
  • import 语句可以编写多个。
  • import 语句可以模糊导入:java.util.*;
  • import 静态导入:import static java.lang.System.*;

补充知识:常用的 IDEA 快捷键(For Win)

  • 新建/新增任何东西:alt + insert
  • 退出任何窗口:ESC
  • 编写源码的窗口最大化: ctrl+shift+F12
  • 生成 main 方法: psvm
  • 快速生成输出语句: sout
  • IDEA 会自动保存,自动编译
  • 打开 Project 窗口: alt+1
  • 查找某个类:敲两次 shift,选择 classes,输入类名
  • 切换选项卡:alt + 左右方向键
  • 自动生成变量: .var
  • 删除一行: ctrl + y
  • 复制一行: ctrl + d
  • 在一个类当中查找方法: ctrl + F12
  • 生成 for 循环:fori
  • 自动生成 if 语句: .if
  • 单行注释:ctrl + /
  • 多行注释:ctrl + shift + /
  • 查看源码:按 ctrl 别松手,鼠标移动到对应的类名下方,出现下划线,点击过去,可以查看类源码
  • 多行编辑:按 alt 别松手,鼠标拖动多行,完成多行编辑
  • 怎么快速生成创建对象语句:类名.new.var
  • 怎么快速生成 if 语句:布尔类型值.if
  • 怎么快速生成 setter 和 getter 方法:alt + insert,然后选择 setter and getter 生成
  • 怎么快速生成构造方法:alt + insert,然后选择 Constructor。
  • 在 IDEA 当中如何自动纠错:将光标移动到错误的位置,按 atl + enter。会有提示,根据提示进行纠错
  • 移动代码到上一行:alt + shift + 上/下方向
  • 怎么快速重写方: alt + insert,选择 Override....
  • 怎么快速重写方法: ctrl + o
  • 快速向下转型,并同时生成变量名:变量名.castvar
  • 快速查看方法的参数:ctrl + p
  • 返回上一步:ctrl + alt + 左方向键; 下一步:ctrl + alt + 右方向键
  • 代码格式化:ctrl + alt + L
  • 查看继承结构:ctrl + H

补充知识:常用的 IDEA 快捷键(For Mac)

常用快捷键

  • command + F 在当前文件进行文本查找
  • command + shift + F 进行工程和模块中的文件搜索
  • command+u 找到这个方法的接口
  • command+ option + b 找到这个接口的实现类
  • command + / 对代码进行注释,并且自动移动到下一行
  • option + command + L 进行格式化代码
  • command + shift + R 进行整个项目或者指定目录文件进行替换

Editing(编辑)

  • command + J 快速查看文档 (按F1也可以)
  • shift + F1 快速查看外部文档
  • command + N 生成get、set方法
  • control + O 重写父类方法
  • control + I 实现接口方法
  • command + option + T 包围代码
  • command + option + / 块注释
  • option + 向上 选中代码块,向下取消
  • option + enter 显示意向动作
  • control + option + I 自动缩进线
  • command + option + L 格式化代码
  • command + option + O 优化import
  • command + shift + V 从最近的缓存区选择粘贴
  • command + D 复制当前行或选定的块
  • command + delete 删除当前行或选定的块
  • shift + enter 开始新的一行
  • command + shift + U 大小写切换
  • command + shift + [ /command + shift + ] 选择代码块开始/结束
  • option + fn + delete 删除到单词末尾
  • option + delete 删除到单词开始
  • command + 加号/command + 减号 展开/折叠代码块
  • command + shift + 加号 展开所有代码块
  • command + shift + 减号 折叠所有代码块
  • command + W 关闭活动的编辑选项卡

查询/替换(search/replace)

  • double shift 查询任何东西
  • command + G 向下查找
  • command + shift + G 向上查找
  • command + R 文件内替换
  • command + shift + F 全局查找(根据路径)
  • command + shift + R 全局替换(根据路径)

编译和运行(compile and run)

  • command + F9 编译project
  • control + option + R 弹出run的可选菜单
  • control + option + D 弹出debug可选菜单
  • control + R运行
  • control + D 调试
  • option + F7/command + F7 在文件中查找用法/在类中查找用法
  • command + option + F7 显示用法

debug 调试

  • F8 进入下一步,不进入方法
  • F7 进入下一步,进入方法,不进入嵌套方法
  • shift + F7 智能步入,断点运行的行上如果调用多个行,会弹出进入哪个方法
  • shift + F8 跳出
  • option + F9 运行到光标出,如果在光标前面还有断点,则进入到断点
  • option + F8 计算表达式(可以改变变量值,使其生效)
  • command + option + R 恢复断点运行,进入到下一个断点(如果还有)
  • command + F8 切换断点(若光标当前行有断点则取消断点,没有则加上断点)
  • command + shift + F8 查看断点信息
  • command + O 查找类文件
  • command + shift + O 查找所有类型文件、打开文件、打开目录,打开目录需要在输入的内容前面加上一个反斜杠
  • command + option + O 前往指定的变量/方法
  • command + L 在当前文件跳转到指定行位置
  • command + E 显示最近打开的文件记录
  • option + 方向键 光标跳转到当前语句的首位或末尾
  • command + shift + 方向键 退回/前进到上一个操作的地方
  • command + shift + delete 跳转到最后一个编辑地方
  • command + Y 快速打开光标所在的方法、定义
  • control + shift + B 跳转到类型定义处
  • command + U 跳转到光标所在的方法所在父类的方法/接口定义
  • control + 方向键 上一个方法/下一个方法
  • command + F12 在类中找方法
  • control + H 显示当前类的结构层次
  • command + shift + H 显示方法的结构层次
  • control + option + H 显示调用层次结构
  • F2 跳转到下一个警告或错误处

Refactoring(重构)

  • F5 复制文件到指定目录
  • F6 移动文件到指定目录
  • Command + Delete 在文件上为安全删除文件,弹出确认框
  • Shift + F6 重命名文件
  • Command + F6 更改签名
  • Command + Option + N 一致性
  • Command + Option + M 将选中的代码提取为方法
  • Command + Option + V 提取变量
  • Command + Option + F 提取字段
  • Command + Option + C 提取常量
  • Command + Option + P 提取参数