一、标识符规则
标识符(Identifier) 是程序中用来命名变量、方法、类、接口、包等程序元素的名称。在学习 Java 编程之前,首先需要了解如何正确命名这些程序元素。
1.1 基本规则
-
首字符规则
- 必须以字母 (
a-z、A-Z)、**下划线(_)或 美元符号($)**开头 - 不能以数字开头
- 必须以字母 (
-
后续字符规则
- 首字符之后可以是字母、数字、下划线或美元符号
- 可以使用 Unicode 字符(包括中文,但不推荐)
-
关键字限制
- 不能使用 Java 关键字和保留字作为标识符
- Java 关键字包括:
abstract、assert、boolean、break、byte、case、catch、char、class、const、continue、default、do、double、else、enum、extends、final、finally、float、for、goto、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
-
大小写敏感
- Java 是大小写敏感的语言
age、Age、AGE是三个不同的标识符
-
长度限制
- 理论上没有长度限制
- 但建议保持合理长度(通常不超过 50 个字符)
1.2 合法与不合法的标识符示例
java
// ✅ 合法的标识符
int age; // 字母开头
String userName; // 字母开头,驼峰命名
double _price; // 下划线开头
int $count; // 美元符号开头
String user_name; // 下划线连接(不推荐,但合法)
String 用户名; // Unicode 字符(不推荐,但合法)
int MAX_SIZE; // 全大写(常量命名)
String getValue; // 方法命名
// ❌ 不合法的标识符
// int 2age; // 错误:不能以数字开头
// String user-name; // 错误:不能包含连字符(-)
// int class; // 错误:class 是关键字
// String public; // 错误:public 是关键字
// int void; // 错误:void 是关键字
// String user name; // 错误:不能包含空格
// int user@name; // 错误:不能包含特殊字符(@)
1.3 标识符的用途
标识符可以用于命名以下程序元素:
- 变量 :
int age、String name - 方法 :
public void calculate()、public int getValue() - 类 :
class Person、class Calculator - 接口 :
interface Drawable、interface Runnable - 包 :
package com.example.util - 常量 :
final int MAX_SIZE - 参数 :
public void print(String message) - 标签 :
outer: for (...)
1.4 命名约定(Convention)
虽然以下不是语法规则,但遵循这些约定是 Java 编程的最佳实践:
-
类名和接口名 :使用大驼峰命名法(PascalCase),首字母大写
javaclass Person { } interface Drawable { } class UserService { } -
变量名和方法名 :使用小驼峰命名法(camelCase),首字母小写
javaint age; String userName; public void calculateTotal() { } -
常量名 :使用全大写,单词间用下划线分隔
javafinal int MAX_SIZE = 100; final double PI = 3.14159; final String DEFAULT_NAME = "Unknown"; -
包名 :使用全小写,单词间用点号分隔
javapackage com.example.util; package java.util.concurrent; -
避免使用:
- 单字母变量名(除了循环变量
i、j、k) - 拼音命名(如
yonghu应使用user) - 无意义的名称(如
a、b、temp) - 下划线开头的标识符(通常用于特殊用途)
- 单字母变量名(除了循环变量
最佳实践(来自《Effective Java》和《Java编程思想》):
- 标识符应该有意义,能够清晰表达其用途
- 使用英文单词,避免使用拼音或中文
- 遵循 Java 命名约定,提高代码可读性
- 保持一致性,在整个项目中统一命名风格
二、数据类型
Java 是一种强类型语言 ,所有变量都必须先声明类型后使用。Java 的数据类型分为两大类:基本类型(Primitive Types)和引用类型(Reference Types)。
2.1 基本类型(Primitive Types)
基本类型是 Java 语言内置的、不可再分的类型,直接存储值本身,存储在栈内存中。Java 提供了 8 种基本类型:
整数类型
| 类型 | 大小 | 取值范围 | 默认值 | 用途 |
|---|---|---|---|---|
byte |
1 字节(8 位) | -128 ~ 127 | 0 | 节省内存,适用于小范围整数 |
short |
2 字节(16 位) | -32,768 ~ 32,767 | 0 | 较少使用 |
int |
4 字节(32 位) | -2³¹ ~ 2³¹-1 | 0 | 最常用的整数类型 |
long |
8 字节(64 位) | -2⁶³ ~ 2⁶³-1 | 0L | 大整数,需加 L 或 l 后缀 |
java
// 整数类型示例
byte b = 100; // 必须在 -128 到 127 之间
short s = 1000;
int i = 100000; // 最常用
long l = 10000000000L; // 注意:long 类型字面量需要加 L 后缀
// 不同进制的表示
int decimal = 100; // 十进制
int binary = 0b1100100; // 二进制(Java 7+)
int octal = 0144; // 八进制(以0开头,等于十进制100)
int octal2 = 0o144; // 八进制(Java 7+推荐写法,更清晰)
int hex = 0x64; // 十六进制
最佳实践(来自《Effective Java》):
- 优先使用
int,除非有特殊需求 - 使用
long时,始终使用大写的L后缀,避免与数字1混淆
浮点类型
| 类型 | 大小 | 精度 | 默认值 | 用途 |
|---|---|---|---|---|
float |
4 字节(32 位) | 约 7 位有效数字 | 0.0f | 单精度浮点数,需加 f 或 F 后缀 |
double |
8 字节(64 位) | 约 15-17 位有效数字 | 0.0d | 默认的浮点类型,双精度 |
java
// 浮点类型示例
float f = 3.14f; // 必须加 f 或 F 后缀
double d = 3.141592653589793; // 默认类型,可加 d 或 D 后缀
// 科学计数法
double scientific = 1.23e10; // 1.23 × 10¹⁰
double negative = 1.23e-5; // 1.23 × 10⁻⁵
// 浮点数精度问题(重要!)
System.out.println(0.1 + 0.2); // 输出:0.30000000000000004
// 原因:二进制无法精确表示某些十进制小数
重要提示(来自《Java核心技术》):
- 浮点数不适合用于精确计算(如货币),应使用
BigDecimal double的精度是float的两倍,大多数情况下应使用double
字符类型
| 类型 | 大小 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|---|
char |
2 字节(16 位) | '\u0000' ~ '\uffff'(0 ~ 65535) | '\u0000' | Unicode 字符,使用单引号 |
java
// 字符类型示例
char c1 = 'A'; // 字符字面量
char c2 = '\u0041'; // Unicode 转义序列(也是 'A')
char c3 = 65; // 整数(ASCII 码)
char c4 = '\n'; // 转义字符:换行
char c5 = '\t'; // 转义字符:制表符
char c6 = '\\'; // 转义字符:反斜杠
char c7 = '\''; // 转义字符:单引号
char c8 = '\"'; // 转义字符:双引号
// 常用转义字符
// \n - 换行
// \t - 制表符
// \r - 回车
// \\ - 反斜杠
// \' - 单引号
// \" - 双引号
布尔类型
| 类型 | 大小 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|---|
boolean |
JVM 实现相关 | true 或 false |
false |
布尔值,不能与整数类型相互转换 |
java
// 布尔类型示例
boolean flag = true;
boolean isDone = false;
// Java 中 boolean 不能转换为 int(与 C/C++ 不同)
// int x = flag; // 编译错误!
重要特性(来自《Java编程思想》):
- Java 的
boolean类型不能与其他基本类型相互转换 - 这避免了 C/C++ 中常见的错误(如
if (x = 5)这样的误写)
2.2 引用类型(Reference Types)
引用类型存储的是对象的引用(地址),而不是对象本身。对象存储在堆内存中,引用存储在栈内存中。
类(Class)
java
// String 是最常用的引用类型
String str = "Hello World";
String str2 = new String("Hello World");
// 自定义类
class Person {
String name;
int age;
}
Person person = new Person();
person.name = "张三";
person.age = 25;
接口(Interface)
java
interface Drawable {
void draw();
}
class Circle implements Drawable {
public void draw() {
System.out.println("绘制圆形");
}
}
Drawable shape = new Circle(); // 接口引用
数组(Array)
java
// 数组是对象,属于引用类型
int[] arr1 = new int[10]; // 方式1:声明并分配空间
int[] arr2 = {1, 2, 3, 4, 5}; // 方式2:初始化数组
int[] arr3 = new int[]{1, 2, 3}; // 方式3:声明并初始化
// 多维数组
int[][] matrix = new int[3][4];
int[][] matrix2 = {{1, 2}, {3, 4}};
重要特性(来自《Java核心技术》):
- 数组长度固定,创建后不能改变
- 数组索引从 0 开始
- 访问越界会抛出
ArrayIndexOutOfBoundsException
2.3 基本类型与引用类型的区别
| 特性 | 基本类型 | 引用类型 |
|---|---|---|
| 存储位置 | 栈内存 | 堆内存(对象),栈内存(引用) |
| 存储内容 | 值本身 | 对象的引用(地址) |
| 默认值 | 有默认值(如 int 为 0) | null |
| 参数传递 | 值传递(传递副本) | 引用传递(传递引用副本) |
| 内存管理 | 自动回收 | 由垃圾回收器管理 |
java
// 值传递示例(基本类型)
void modifyInt(int x) {
x = 100; // 只修改副本
}
int num = 10;
modifyInt(num);
System.out.println(num); // 输出:10(原值未改变)
// 引用传递示例(引用类型)
void modifyArray(int[] arr) {
arr[0] = 100; // 修改对象内容
}
int[] array = {1, 2, 3};
modifyArray(array);
System.out.println(array[0]); // 输出:100(对象内容已改变)
三、变量
变量是程序中用于存储数据的命名空间。Java 中的变量必须先声明后使用。变量名必须遵循标识符规则(见第一章)。
3.1 变量声明
java
// 基本语法:类型 变量名;
int age;
String name;
// 声明并初始化(可以合并为一行)
int age2 = 25;
String name2 = "张三";
// 同时声明多个同类型变量
int x, y, z;
int a = 1, b = 2, c = 3;
3.2 变量命名规则
变量名必须遵循标识符规则(见第一章),此外还有以下变量命名的具体规范:
基本规则
变量命名必须符合标识符的所有规则:
- 必须以字母、下划线或美元符号开头
- 不能以数字开头
- 不能使用 Java 关键字和保留字
- 区分大小写
- 后续字符可以是字母、数字、下划线或美元符号
命名规范
变量命名约定(来自《Java编程思想》和《Effective Java》):
-
使用小驼峰命名法(camelCase)
- 首字母小写,后续单词首字母大写
- 示例:
userName、totalCount、isValid、maxValue
-
变量名应该有意义
- 能够清晰表达变量的用途和含义
- 避免使用无意义的名称(如
a、b、temp) - 使用英文单词,避免拼音
-
布尔变量命名
- 使用
is、has、can、should等前缀 - 示例:
isValid、hasPermission、canEdit、shouldRetry
- 使用
-
循环变量命名
- 可以使用单字母:
i、j、k(仅限简单循环) - 复杂循环应使用有意义的名称:
index、rowIndex、columnIndex
- 可以使用单字母:
-
常量命名
- 使用全大写,单词间用下划线分隔
- 示例:
MAX_SIZE、PI、DEFAULT_TIMEOUT
-
避免使用
- 下划线开头的变量名(通常用于特殊用途)
- 美元符号开头的变量名(编译器内部使用)
- 单字母变量名(除了循环变量)
java
// ✅ 推荐的变量命名
int age; // 简单明了
String userName; // 驼峰命名
boolean isValid; // 布尔变量使用 is 前缀
int totalCount; // 有意义的名称
final int MAX_SIZE = 100; // 常量全大写
// 循环变量
for (int i = 0; i < 10; i++) { } // 简单循环可以使用 i
for (int rowIndex = 0; rowIndex < rows; rowIndex++) { } // 复杂循环使用有意义名称
// ❌ 不推荐的变量命名
int a; // 无意义
String yonghu; // 使用拼音
int user_name; // 使用下划线(应使用驼峰)
double _price; // 下划线开头(特殊用途)
int $count; // 美元符号开头(编译器内部)
命名示例对比:
java
// 不推荐
int d; // 无意义
String n; // 无意义
boolean f; // 无意义
// 推荐
int days; // 清晰表达含义
String name; // 清晰表达含义
boolean isValid; // 清晰表达含义
// 不推荐
String userNameStr; // 冗余的类型信息(Str)
// 推荐
String userName; // 简洁明了
3.3 变量作用域
变量的作用域决定了变量在哪些地方可以被访问。
局部变量(Local Variables)
在方法、构造器或代码块中声明的变量。
java
public void method() {
int localVar = 10; // 局部变量
// localVar 只能在此方法内访问
}
// System.out.println(localVar); // 编译错误:无法访问
特点:
- 必须在使用前初始化
- 作用域仅限于声明它的代码块
- 不能使用访问修饰符(
public、private等)
实例变量(Instance Variables)
在类中声明,但在方法、构造器或代码块外。
java
class Person {
String name; // 实例变量
int age; // 实例变量
public Person(String name, int age) {
this.name = name; // 使用 this 区分实例变量和参数
this.age = age;
}
}
特点:
- 有默认值(基本类型为 0/false,引用类型为
null) - 每个对象实例都有自己的一份副本
- 可以使用访问修饰符
类变量(Class Variables / Static Variables)
使用 static 关键字声明的变量。
java
class Counter {
static int count = 0; // 类变量(静态变量)
int instanceCount = 0; // 实例变量
Counter() {
count++; // 所有实例共享
instanceCount++; // 每个实例独立
}
}
特点:
- 属于类,不属于任何实例
- 所有实例共享同一个类变量
- 可以通过类名直接访问:
Counter.count - 有默认值
3.4 变量初始化
java
// 1. 声明时初始化
int x = 10;
// 2. 先声明后初始化
int y;
y = 20;
// 3. 局部变量必须在使用前初始化
void method() {
int z;
// System.out.println(z); // 编译错误:可能尚未初始化
z = 30;
System.out.println(z); // 正确
}
// 4. 实例变量有默认值
class Test {
int a; // 默认值为 0
String s; // 默认值为 null
}
四、常量
常量是指在程序执行过程中其值不会发生改变的变量。Java 中使用 final 关键字声明常量。
4.1 常量声明
java
// 基本类型常量
final int MAX_SIZE = 100;
final double PI = 3.14159;
final String COMPANY_NAME = "MyCompany";
// 引用类型常量(引用不能改变,但对象内容可以改变)
// StringBuilder 是 Java 标准库中的字符串构建类,用于高效拼接字符串
final StringBuilder sb = new StringBuilder("Hello");
// sb = new StringBuilder(); // 编译错误:不能重新赋值(引用不能改变)
sb.append(" World"); // 正确:可以修改对象内容(对象本身可以改变)
// 此时 sb 的内容变为 "Hello World"
4.2 常量命名规范
常量命名遵循标识符规则(见第一章),并遵循以下约定:
约定:常量名使用全大写字母,单词间用下划线分隔。详细规范请参考第一章"命名约定"部分。
java
// 推荐的常量命名
final int MAX_VALUE = 100;
final double PI = 3.14159;
final String DEFAULT_NAME = "Unknown";
final int HTTP_OK = 200;
// 不推荐的命名(虽然合法)
final int maxValue = 100; // 应该使用 MAX_VALUE
4.3 编译时常量与运行时常量
java
// 编译时常量(必须在编译时就能确定值)
final int COMPILE_TIME_CONSTANT = 100;
final String GREETING = "Hello";
// 运行时常量(值在运行时确定)
final int runtimeConstant = new Random().nextInt(100);
final String currentTime = new Date().toString();
最佳实践(来自《Effective Java》):
- 优先使用编译时常量,性能更好
- 对于需要多个地方共享的常量,使用
public static final声明为类常量
4.4 类常量
使用 public static final 声明的常量可以在类外部访问。
java
class Constants {
public static final int MAX_SIZE = 100;
public static final String DEFAULT_NAME = "Unknown";
private static final double PI = 3.14159; // 私有常量
}
// 使用类常量
int size = Constants.MAX_SIZE;
五、运算符
运算符用于对操作数执行各种运算。Java 提供了丰富的运算符。
5.1 算术运算符
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
+ |
加法 | 5 + 3 |
8 |
- |
减法 | 5 - 3 |
2 |
* |
乘法 | 5 * 3 |
15 |
/ |
除法 | 5 / 3 |
1(整数除法) |
% |
取模(余数) | 5 % 3 |
2 |
java
// 整数除法
int result1 = 10 / 3; // 结果:3(整数除法,截断小数部分)
double result2 = 10.0 / 3; // 结果:3.3333333333333335(浮点除法)
// 取模运算
int remainder = 10 % 3; // 结果:1
int negative = -10 % 3; // 结果:-1(符号与被除数相同)
// 字符串连接(+ 运算符的特殊用法)
String greeting = "Hello" + " " + "World"; // "Hello World"
String message = "Age: " + 25; // "Age: 25"(自动转换)
注意事项:
- 整数除法会截断小数部分
- 除以零会抛出
ArithmeticException(整数)或得到Infinity/NaN(浮点数)
5.2 自增自减运算符
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
++ |
自增 | x++ 或 ++x |
x 增加 1 |
-- |
自减 | x-- 或 --x |
x 减少 1 |
java
int x = 5;
// 后置自增(先使用后增加)
int a = x++; // a = 5, x = 6
// 前置自增(先增加后使用)
int b = ++x; // b = 7, x = 7
// 等价写法
x++; // 等价于 x = x + 1
++x; // 等价于 x = x + 1
最佳实践(来自《Effective Java》):
- 避免在表达式中使用自增自减运算符,容易产生混淆
- 优先使用
x += 1这样的清晰写法
5.3 关系运算符(比较运算符)
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
== |
相等 | 5 == 3 |
false |
!= |
不等 | 5 != 3 |
true |
> |
大于 | 5 > 3 |
true |
< |
小于 | 5 < 3 |
false |
>= |
大于等于 | 5 >= 3 |
true |
<= |
小于等于 | 5 <= 3 |
false |
java
int a = 5;
int b = 3;
boolean eq = (a == b); // false
boolean ne = (a != b); // true
boolean gt = (a > b); // true
boolean ge = (a >= b); // true
// 字符串比较(重要!)
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
System.out.println(s1 == s2); // true(字符串常量池)
System.out.println(s1 == s3); // false(不同对象)
System.out.println(s1.equals(s3)); // true(内容相同)
重要提示(来自《Java核心技术》):
- 对于引用类型,
==比较的是引用(地址),不是内容 - 使用
equals()方法比较对象内容 - 基本类型使用
==比较值
5.4 逻辑运算符
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
&& |
逻辑与(短路) | true && false |
false |
| ` | ` | 逻辑或(短路) | |
! |
逻辑非 | !true |
false |
& |
逻辑与(非短路) | true & false |
false |
| ` | ` | 逻辑或(非短路) | `true |
java
boolean a = true;
boolean b = false;
// 短路运算符(推荐使用)
boolean result1 = a && b; // false(b 不会被求值)
boolean result2 = a || b; // true(b 不会被求值)
// 非短路运算符(不推荐)
boolean result3 = a & b; // false(b 会被求值)
boolean result4 = a | b; // true(b 会被求值)
// 短路求值的优势
String str = null;
if (str != null && str.length() > 0) { // 安全:不会抛出 NullPointerException
// ...
}
// 逻辑非
boolean result = !a; // false
最佳实践(来自《Effective Java》):
- 优先使用
&&和||(短路运算符),性能更好 - 利用短路特性避免不必要的计算和潜在的错误
5.5 赋值运算符
| 运算符 | 说明 | 示例 | 等价于 |
|---|---|---|---|
= |
赋值 | x = 5 |
x = 5 |
+= |
加后赋值 | x += 5 |
x = x + 5 |
-= |
减后赋值 | x -= 5 |
x = x - 5 |
*= |
乘后赋值 | x *= 5 |
x = x * 5 |
/= |
除后赋值 | x /= 5 |
x = x / 5 |
%= |
取模后赋值 | x %= 5 |
x = x % 5 |
java
int x = 10;
x += 5; // x = 15
x -= 3; // x = 12
x *= 2; // x = 24
x /= 4; // x = 6
x %= 5; // x = 1
5.6 条件运算符(三元运算符)
java
// 语法:条件 ? 表达式1 : 表达式2
int max = (a > b) ? a : b;
// 等价于
int max;
if (a > b) {
max = a;
} else {
max = b;
}
// 嵌套使用(不推荐,可读性差)
int result = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);
最佳实践(来自《Effective Java》):
- 简单条件可以使用三元运算符
- 复杂逻辑应使用
if-else语句,提高可读性
5.7 位运算符
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
& |
按位与 | 5 & 3 |
1 |
| ` | ` | 按位或 | `5 |
^ |
按位异或 | 5 ^ 3 |
6 |
~ |
按位取反 | ~5 |
-6 |
<< |
左移 | 5 << 1 |
10 |
>> |
右移(符号扩展) | -5 >> 1 |
-3 |
>>> |
无符号右移 | -5 >>> 1 |
2147483645 |
java
int a = 5; // 二进制:00000101
int b = 3; // 二进制:00000011
int and = a & b; // 00000001 = 1
int or = a | b; // 00000111 = 7
int xor = a ^ b; // 00000110 = 6
int not = ~a; // 11111010 = -6(补码)
// 位移运算
int leftShift = a << 1; // 00001010 = 10(左移1位,相当于乘以2)
int rightShift = a >> 1; // 00000010 = 2(右移1位,相当于除以2)
使用场景:
- 位运算通常用于底层编程、性能优化
- 日常开发中较少使用
5.8 运算符优先级
运算符优先级决定了表达式的求值顺序。优先级从高到低:
- 括号
() - 一元运算符:
++、--、!、~ - 乘除模:
*、/、% - 加减:
+、- - 位移:
<<、>>、>>> - 关系:
<、<=、>、>=、instanceof - 相等:
==、!= - 位与:
& - 位异或:
^ - 位或:
| - 逻辑与:
&& - 逻辑或:
|| - 条件:
?: - 赋值:
=、+=、-=等
java
// 使用括号明确优先级(推荐)
int result = (a + b) * (c - d);
// 避免依赖运算符优先级(提高可读性)
// 不推荐:int x = a + b * c;
// 推荐:int x = a + (b * c);
最佳实践(来自《Java编程思想》):
- 使用括号明确表达意图,不要过度依赖运算符优先级
- 复杂表达式应该拆分成多行
六、控制流
控制流语句用于控制程序的执行顺序。Java 提供了条件语句和循环语句。
6.1 条件语句:if-else
if 语句根据条件的真假执行不同的代码块。
基本语法
java
// 1. 单 if 语句
if (condition) {
// 条件为 true 时执行
}
// 2. if-else 语句
if (condition) {
// 条件为 true 时执行
} else {
// 条件为 false 时执行
}
// 3. if-else if-else 语句
if (condition1) {
// condition1 为 true 时执行
} else if (condition2) {
// condition2 为 true 时执行
} else {
// 所有条件都为 false 时执行
}
示例
java
int score = 85;
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 80) {
System.out.println("良好");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
注意事项
java
// 1. 条件必须是布尔表达式
int x = 5;
// if (x) { } // 编译错误:不能使用 int 作为条件
// 2. 单语句可以省略大括号(但不推荐)
if (x > 0)
System.out.println("正数"); // 合法但不推荐
// 3. 推荐始终使用大括号
if (x > 0) {
System.out.println("正数");
}
// 4. 避免在条件中使用赋值运算符
int y;
// if (y = 5) { } // 编译错误:赋值表达式不是布尔类型
if (y == 5) { } // 正确:使用比较运算符
最佳实践(来自《Effective Java》和《Java编程思想》):
- 始终使用大括号,即使只有一条语句(避免潜在的错误)
- 条件表达式应该简洁明了
- 避免深层嵌套,考虑使用早期返回(early return)
java
// 早期返回模式(推荐)
public String getGrade(int score) {
if (score < 0 || score > 100) {
return "无效分数";
}
if (score >= 90) {
return "优秀";
}
if (score >= 80) {
return "良好";
}
if (score >= 60) {
return "及格";
}
return "不及格";
}
6.2 条件语句:switch
switch 语句根据表达式的值选择执行不同的代码分支。
基本语法(传统 switch)
java
switch (expression) {
case value1:
// 代码块1
break;
case value2:
// 代码块2
break;
default:
// 默认代码块
}
示例
java
int day = 3;
String dayName;
switch (day) {
case 1:
dayName = "星期一";
break;
case 2:
dayName = "星期二";
break;
case 3:
dayName = "星期三";
break;
case 4:
dayName = "星期四";
break;
case 5:
dayName = "星期五";
break;
case 6:
dayName = "星期六";
break;
case 7:
dayName = "星期日";
break;
default:
dayName = "无效日期";
}
重要特性
java
// 1. case 穿透(fall-through)
int x = 2;
switch (x) {
case 1:
case 2:
case 3:
System.out.println("1-3");
break; // 如果没有 break,会继续执行下一个 case
case 4:
System.out.println("4");
break;
}
// 2. 字符串 switch(Java 7+)
String fruit = "apple";
switch (fruit) {
case "apple":
System.out.println("苹果");
break;
case "banana":
System.out.println("香蕉");
break;
default:
System.out.println("未知水果");
}
// 3. 枚举 switch
enum Color { RED, GREEN, BLUE }
Color color = Color.RED;
switch (color) {
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
case BLUE:
System.out.println("蓝色");
break;
}
注意事项:
switch表达式必须是byte、short、int、char、String或枚举类型- 每个
case后通常需要break,否则会继续执行下一个case(case 穿透) default分支是可选的,但建议始终包含
Switch 表达式(Java 14+)
Java 14 引入了新的 switch 表达式语法,更加简洁:
java
// 传统 switch 语句
String dayName;
switch (day) {
case 1:
dayName = "星期一";
break;
case 2:
dayName = "星期二";
break;
default:
dayName = "未知";
}
// Switch 表达式(Java 14+)
String dayName = switch (day) {
case 1 -> "星期一";
case 2 -> "星期二";
case 3 -> "星期三";
default -> "未知";
};
// 多行代码块
String result = switch (day) {
case 1, 2, 3, 4, 5 -> {
System.out.println("工作日");
yield "工作日"; // 使用 yield 返回值
}
case 6, 7 -> {
System.out.println("周末");
yield "周末";
}
default -> "未知";
};
最佳实践(来自《Effective Java》):
- 优先使用 switch 表达式(Java 14+),更简洁且不会忘记
break - 如果必须使用传统 switch,确保每个 case 都有
break或明确需要穿透 - 始终包含
default分支处理意外情况
6.3 循环语句:for
for 循环用于已知循环次数的情况。
基本语法
java
for (初始化; 条件; 更新) {
// 循环体
}
示例
java
// 1. 基本 for 循环
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// 2. 循环变量可以在外部声明
int i;
for (i = 0; i < 10; i++) {
System.out.println(i);
}
// 3. 多个初始化/更新表达式
for (int i = 0, j = 10; i < j; i++, j--) {
System.out.println("i=" + i + ", j=" + j);
}
// 4. 无限循环(不推荐,但有时需要)
boolean running = true;
for (;;) {
// 无限循环,需要在循环体内使用 break 退出
if (!running) {
break;
}
// ... 其他代码
}
增强 for 循环(for-each,Java 5+)
java
// 遍历数组
int[] arr = {1, 2, 3, 4, 5};
for (int element : arr) {
System.out.println(element);
}
// 遍历集合
List<String> list = Arrays.asList("a", "b", "c");
for (String item : list) {
System.out.println(item);
}
// 等价于传统 for 循环
for (int i = 0; i < arr.length; i++) {
int element = arr[i];
System.out.println(element);
}
最佳实践(来自《Effective Java》):
- 优先使用增强 for 循环,更简洁且不容易出错
- 只有在需要索引时才使用传统 for 循环
- 避免在循环中修改集合(使用迭代器或传统 for 循环)
java
// 需要索引时使用传统 for 循环
for (int i = 0; i < arr.length; i++) {
System.out.println("索引 " + i + ": " + arr[i]);
}
// 只需要元素值时使用增强 for 循环
for (int element : arr) {
System.out.println(element);
}
6.4 循环语句:while
while 循环在条件为真时重复执行代码块。
基本语法
java
while (condition) {
// 循环体
}
示例
java
// 1. 基本 while 循环
int i = 0;
while (i < 10) {
System.out.println(i);
i++;
}
// 2. 条件判断在前,可能一次都不执行
int count = 0;
while (count > 0) {
// 不会执行,因为条件一开始就是 false
}
// 3. 无限循环
boolean running = true;
while (running) {
// 需要在循环体内使用 break 或修改条件退出
if (/* 某个条件 */) {
running = false; // 或使用 break;
}
}
6.5 循环语句:do-while
do-while 循环先执行一次循环体,然后判断条件。
基本语法
java
do {
// 循环体
} while (condition);
示例
java
// do-while 至少执行一次
int i = 0;
do {
System.out.println(i);
i++;
} while (i < 10);
// 即使条件为 false,也会执行一次
int count = 0;
do {
System.out.println("执行一次");
} while (count > 0); // 输出:执行一次
使用场景:
do-while适用于需要至少执行一次的情况- 大多数情况下,
while和for更常用
6.6 循环控制语句
break
break 用于跳出循环或 switch 语句。
java
// 1. 跳出循环
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // 跳出循环,i=5 时停止
}
System.out.println(i);
}
// 2. 跳出 switch
switch (x) {
case 1:
System.out.println("1");
break; // 跳出 switch
case 2:
System.out.println("2");
break;
}
// 3. 带标签的 break(跳出多层循环)
outer: for (int i = 0; i < 3; i++) {
inner: for (int j = 0; j < 3; j++) {
if (i == 1 && j == 1) {
break outer; // 跳出外层循环
}
System.out.println("i=" + i + ", j=" + j);
}
}
continue
continue 用于跳过当前循环的剩余代码,继续下一次循环。
java
// 跳过偶数,只打印奇数
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // 跳过本次循环的剩余代码
}
System.out.println(i); // 只打印奇数
}
// 带标签的 continue
outer: for (int i = 0; i < 3; i++) {
inner: for (int j = 0; j < 3; j++) {
if (j == 1) {
continue outer; // 继续外层循环的下一次迭代
}
System.out.println("i=" + i + ", j=" + j);
}
}
最佳实践(来自《Java编程思想》):
- 避免过度使用
break和continue,可能降低代码可读性 - 考虑重构代码,使用更清晰的条件判断
- 带标签的
break和continue应该谨慎使用
七、方法
方法是执行特定任务的代码块,具有可重用性。方法定义了一组语句,可以通过方法名调用执行。
7.1 方法声明
基本语法
java
[访问修饰符] [static] [final] 返回类型 方法名([参数列表]) {
// 方法体
[return 返回值;]
}
示例
java
// 1. 无参数无返回值
public void greet() {
System.out.println("Hello!");
}
// 2. 有参数无返回值
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
// 3. 有参数有返回值
public int add(int a, int b) {
return a + b;
}
// 4. 多个参数
public double calculate(double x, double y, String operation) {
if ("add".equals(operation)) {
return x + y;
} else if ("multiply".equals(operation)) {
return x * y;
}
return 0;
}
7.2 方法调用
java
// 调用无返回值方法
greet();
// 调用有返回值方法
int sum = add(5, 3);
// 调用静态方法(通过类名)
int max = Math.max(5, 3); // 返回较大的值
// 调用实例方法(通过对象)
String str = "Hello";
int length = str.length(); // 返回字符串长度
7.3 方法参数
值传递
Java 中所有参数传递都是值传递(详见第二章"基本类型与引用类型的区别"):
- 基本类型:传递值的副本
- 引用类型:传递引用的副本(对象本身不会被复制)
重要提示:参数传递机制已在第二章详细说明,这里不再重复示例代码。
可变参数(Varargs,Java 5+)
java
// 可变参数必须是最后一个参数
public int sum(int... numbers) {
int total = 0;
for (int num : numbers) {
total += num;
}
return total;
}
// 调用
int result1 = sum(1, 2, 3); // 3 个参数
int result2 = sum(1, 2, 3, 4, 5); // 5 个参数
int result3 = sum(); // 0 个参数
// 可变参数实际上是一个数组
public void print(String... messages) {
for (String msg : messages) {
System.out.println(msg);
}
// 等价于
// String[] messages = ...;
}
7.4 返回语句
java
// 1. 有返回值的方法必须使用 return
public int getValue() {
return 10;
}
// 2. 无返回值的方法可以使用 return 提前退出
public void process(int x) {
if (x < 0) {
return; // 提前退出,不返回值
}
System.out.println("处理: " + x);
}
// 3. 方法可以有多个返回点
public String getStatus(int value) {
if (value >= 100) {
return "完成";
}
if (value >= 50) {
return "进行中";
}
return "未开始";
}
7.5 方法重载(Method Overloading)
方法重载是指在同一个类中,允许存在多个方法名相同但参数列表不同的方法。
重载规则
- 方法名必须相同
- 参数列表必须不同(参数类型、参数个数、参数顺序)
- 返回类型可以不同(但不能仅凭返回类型区分)
- 访问修饰符可以不同
示例
java
public class Calculator {
// 1. 参数个数不同
public int add(int a, int b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
// 2. 参数类型不同
public double add(double a, double b) {
return a + b;
}
// 3. 参数顺序不同
public void print(String name, int age) {
System.out.println("姓名: " + name + ", 年龄: " + age);
}
public void print(int age, String name) {
System.out.println("年龄: " + age + ", 姓名: " + name);
}
// 4. 返回类型不同(但参数列表必须不同)
public int multiply(int a, int b) {
return a * b;
}
public double multiply(double a, double b) {
return a * b;
}
}
// 使用
Calculator calc = new Calculator();
int sum1 = calc.add(5, 3); // 调用 int add(int, int)
int sum2 = calc.add(5, 3, 2); // 调用 int add(int, int, int)
double sum3 = calc.add(5.5, 3.2); // 调用 double add(double, double)
重载解析(Overload Resolution)
Java 编译器根据以下规则选择最匹配的方法:
- 精确匹配:参数类型完全匹配
- 自动类型提升 :基本类型可以自动提升(如
byte→int) - 装箱/拆箱:基本类型和包装类型之间的转换
- 可变参数:作为最后的选择
java
public void test(int x) {
System.out.println("int: " + x);
}
public void test(long x) {
System.out.println("long: " + x);
}
public void test(Integer x) {
System.out.println("Integer: " + x);
}
// 调用示例
test(5); // 输出:int: 5(精确匹配)
test(5L); // 输出:long: 5(精确匹配)
test((byte)5); // 输出:int: 5(自动提升:byte → int)
test(Integer.valueOf(5)); // 输出:Integer: 5(精确匹配,推荐使用 valueOf)
// 注意:new Integer(5) 在 Java 9+ 中已废弃,应使用 Integer.valueOf(5)
常见陷阱
java
// 1. 仅返回类型不同不能构成重载(编译错误)
public int getValue() { return 1; }
// public double getValue() { return 1.0; } // 编译错误!
// 2. 参数名称不同不能构成重载
public void print(int a) { }
// public void print(int b) { } // 编译错误!参数名不同不算重载
// 3. 可变参数和数组参数可能产生歧义
public void test(int... nums) { }
public void test(int[] nums) { } // 编译错误!会产生歧义
最佳实践(来自《Effective Java》):
- 谨慎使用方法重载,容易产生混淆
- 如果多个重载方法执行相同的逻辑,考虑使用一个方法配合可变参数
- 避免在重载方法中使用自动类型转换,可能导致意外的行为
java
// 不推荐:多个重载方法执行相同逻辑
public void print(int x) { System.out.println(x); }
public void print(long x) { System.out.println(x); }
public void print(double x) { System.out.println(x); }
// 推荐:使用泛型或 Object
public <T> void print(T x) {
System.out.println(x);
}
7.6 静态方法
使用 static 关键字声明的方法属于类,不属于任何实例。
java
class MathUtils {
// 静态方法
public static int max(int a, int b) {
return a > b ? a : b;
}
// 实例方法
public int min(int a, int b) {
return a < b ? a : b;
}
}
// 调用静态方法(通过类名)
int max = MathUtils.max(5, 3);
// 调用实例方法(通过对象)
MathUtils utils = new MathUtils();
int min = utils.min(5, 3);
特点:
- 静态方法不能访问实例变量和实例方法
- 静态方法可以直接通过类名调用
- 静态方法中不能使用
this和super
7.7 方法设计原则
最佳实践(来自《Effective Java》和《Java编程思想》):
- 方法应该短小精悍:一个方法只做一件事
- 方法名应该清晰表达意图 :
calculateTotal()比calc()更好 - 避免过长的方法:如果方法超过 20-30 行,考虑拆分
- 参数应该尽可能少:超过 3 个参数考虑使用对象封装
- 避免副作用:方法应该只做它声明要做的事
- 优先返回 Optional :对于可能返回 null 的方法,考虑返回
Optional<T>
java
// 不推荐:方法过长,职责不清
public void processOrder(Order order) {
// 验证订单
if (order == null) { ... }
if (order.getItems().isEmpty()) { ... }
// 计算总价
double total = 0;
for (Item item : order.getItems()) { ... }
// 应用折扣
if (order.isVip()) { ... }
// 保存订单
orderDao.save(order);
// 发送通知
emailService.send(order);
}
// 推荐:拆分成多个小方法
public void processOrder(Order order) {
validateOrder(order);
double total = calculateTotal(order);
applyDiscount(order, total);
saveOrder(order);
sendNotification(order);
}
private void validateOrder(Order order) { ... }
private double calculateTotal(Order order) { ... }
private void applyDiscount(Order order, double total) { ... }
private void saveOrder(Order order) { ... }
private void sendNotification(Order order) { ... }
总结
本文详细介绍了 Java 的基础语法,按照循序渐进的学习顺序,包括:
- 标识符规则:如何正确命名变量、方法、类等程序元素,遵循 Java 命名约定
- 数据类型:基本类型(8 种)和引用类型,理解它们的区别和用途
- 变量:变量声明、命名规范、作用域和初始化
- 常量 :使用
final关键字声明常量,遵循命名规范 - 运算符:算术、关系、逻辑、赋值等运算符的使用和优先级
- 控制流 :
if-else、switch、for、while、do-while等控制语句 - 方法:方法声明、调用、参数传递、返回值和方法重载
关键要点:
- Java 是强类型语言,所有变量必须先声明类型
- 基本类型存储在栈内存,引用类型对象存储在堆内存
- 参数传递都是值传递(基本类型传值,引用类型传引用副本)
- 控制流语句应该始终使用大括号,提高代码可读性和安全性
- 方法应该短小精悍,职责单一
- 方法重载要谨慎使用,避免产生混淆
参考资源:
- Oracle Java Tutorials
- 《Java核心技术》(Core Java)- Cay S. Horstmann
- 《Effective Java》- Joshua Bloch
- 《Java编程思想》(Thinking in Java)- Bruce Eckel