Java 基础语法详解

一、标识符规则

标识符(Identifier) 是程序中用来命名变量、方法、类、接口、包等程序元素的名称。在学习 Java 编程之前,首先需要了解如何正确命名这些程序元素。

1.1 基本规则

  1. 首字符规则

    • 必须以字母a-zA-Z)、**下划线(_ 美元符号($)**开头
    • 不能以数字开头
  2. 后续字符规则

    • 首字符之后可以是字母、数字、下划线或美元符号
    • 可以使用 Unicode 字符(包括中文,但不推荐)
  3. 关键字限制

    • 不能使用 Java 关键字和保留字作为标识符
    • Java 关键字包括:abstractassertbooleanbreakbytecasecatchcharclassconstcontinuedefaultdodoubleelseenumextendsfinalfinallyfloatforgotoifimplementsimportinstanceofintinterfacelongnativenewpackageprivateprotectedpublicreturnshortstaticstrictfpsuperswitchsynchronizedthisthrowthrowstransienttryvoidvolatilewhile
  4. 大小写敏感

    • Java 是大小写敏感的语言
    • ageAgeAGE 是三个不同的标识符
  5. 长度限制

    • 理论上没有长度限制
    • 但建议保持合理长度(通常不超过 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 ageString name
  • 方法public void calculate()public int getValue()
  • class Personclass Calculator
  • 接口interface Drawableinterface Runnable
  • package com.example.util
  • 常量final int MAX_SIZE
  • 参数public void print(String message)
  • 标签outer: for (...)

1.4 命名约定(Convention)

虽然以下不是语法规则,但遵循这些约定是 Java 编程的最佳实践:

  1. 类名和接口名 :使用大驼峰命名法(PascalCase),首字母大写

    java 复制代码
    class Person { }
    interface Drawable { }
    class UserService { }
  2. 变量名和方法名 :使用小驼峰命名法(camelCase),首字母小写

    java 复制代码
    int age;
    String userName;
    public void calculateTotal() { }
  3. 常量名 :使用全大写,单词间用下划线分隔

    java 复制代码
    final int MAX_SIZE = 100;
    final double PI = 3.14159;
    final String DEFAULT_NAME = "Unknown";
  4. 包名 :使用全小写,单词间用点号分隔

    java 复制代码
    package com.example.util;
    package java.util.concurrent;
  5. 避免使用

    • 单字母变量名(除了循环变量 ijk
    • 拼音命名(如 yonghu 应使用 user
    • 无意义的名称(如 abtemp
    • 下划线开头的标识符(通常用于特殊用途)

最佳实践(来自《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 大整数,需加 Ll 后缀
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 单精度浮点数,需加 fF 后缀
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 实现相关 truefalse 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》):

  1. 使用小驼峰命名法(camelCase)

    • 首字母小写,后续单词首字母大写
    • 示例:userNametotalCountisValidmaxValue
  2. 变量名应该有意义

    • 能够清晰表达变量的用途和含义
    • 避免使用无意义的名称(如 abtemp
    • 使用英文单词,避免拼音
  3. 布尔变量命名

    • 使用 ishascanshould 等前缀
    • 示例:isValidhasPermissioncanEditshouldRetry
  4. 循环变量命名

    • 可以使用单字母:ijk(仅限简单循环)
    • 复杂循环应使用有意义的名称:indexrowIndexcolumnIndex
  5. 常量命名

    • 使用全大写,单词间用下划线分隔
    • 示例:MAX_SIZEPIDEFAULT_TIMEOUT
  6. 避免使用

    • 下划线开头的变量名(通常用于特殊用途)
    • 美元符号开头的变量名(编译器内部使用)
    • 单字母变量名(除了循环变量)
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);  // 编译错误:无法访问

特点

  • 必须在使用前初始化
  • 作用域仅限于声明它的代码块
  • 不能使用访问修饰符(publicprivate 等)

实例变量(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 运算符优先级

运算符优先级决定了表达式的求值顺序。优先级从高到低:

  1. 括号 ()
  2. 一元运算符:++--!~
  3. 乘除模:*/%
  4. 加减:+-
  5. 位移:<<>>>>>
  6. 关系:<<=>>=instanceof
  7. 相等:==!=
  8. 位与:&
  9. 位异或:^
  10. 位或:|
  11. 逻辑与:&&
  12. 逻辑或:||
  13. 条件:?:
  14. 赋值:=+=-=
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 表达式必须是 byteshortintcharString 或枚举类型
  • 每个 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 适用于需要至少执行一次的情况
  • 大多数情况下,whilefor 更常用

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编程思想》):

  • 避免过度使用 breakcontinue,可能降低代码可读性
  • 考虑重构代码,使用更清晰的条件判断
  • 带标签的 breakcontinue 应该谨慎使用

七、方法

方法是执行特定任务的代码块,具有可重用性。方法定义了一组语句,可以通过方法名调用执行。

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)

方法重载是指在同一个类中,允许存在多个方法名相同但参数列表不同的方法。

重载规则

  1. 方法名必须相同
  2. 参数列表必须不同(参数类型、参数个数、参数顺序)
  3. 返回类型可以不同(但不能仅凭返回类型区分)
  4. 访问修饰符可以不同

示例

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 编译器根据以下规则选择最匹配的方法:

  1. 精确匹配:参数类型完全匹配
  2. 自动类型提升 :基本类型可以自动提升(如 byteint
  3. 装箱/拆箱:基本类型和包装类型之间的转换
  4. 可变参数:作为最后的选择
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);

特点

  • 静态方法不能访问实例变量和实例方法
  • 静态方法可以直接通过类名调用
  • 静态方法中不能使用 thissuper

7.7 方法设计原则

最佳实践(来自《Effective Java》和《Java编程思想》):

  1. 方法应该短小精悍:一个方法只做一件事
  2. 方法名应该清晰表达意图calculateTotal()calc() 更好
  3. 避免过长的方法:如果方法超过 20-30 行,考虑拆分
  4. 参数应该尽可能少:超过 3 个参数考虑使用对象封装
  5. 避免副作用:方法应该只做它声明要做的事
  6. 优先返回 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 的基础语法,按照循序渐进的学习顺序,包括:

  1. 标识符规则:如何正确命名变量、方法、类等程序元素,遵循 Java 命名约定
  2. 数据类型:基本类型(8 种)和引用类型,理解它们的区别和用途
  3. 变量:变量声明、命名规范、作用域和初始化
  4. 常量 :使用 final 关键字声明常量,遵循命名规范
  5. 运算符:算术、关系、逻辑、赋值等运算符的使用和优先级
  6. 控制流if-elseswitchforwhiledo-while 等控制语句
  7. 方法:方法声明、调用、参数传递、返回值和方法重载

关键要点

  • Java 是强类型语言,所有变量必须先声明类型
  • 基本类型存储在栈内存,引用类型对象存储在堆内存
  • 参数传递都是值传递(基本类型传值,引用类型传引用副本)
  • 控制流语句应该始终使用大括号,提高代码可读性和安全性
  • 方法应该短小精悍,职责单一
  • 方法重载要谨慎使用,避免产生混淆

参考资源

  • Oracle Java Tutorials
  • 《Java核心技术》(Core Java)- Cay S. Horstmann
  • 《Effective Java》- Joshua Bloch
  • 《Java编程思想》(Thinking in Java)- Bruce Eckel
相关推荐
bcbnb4 小时前
详细教程:iOS应用中Swift代码混淆步骤与工具推荐
后端
expect7g4 小时前
Paimon源码解读 -- Compaction-8.专用压缩任务
大数据·后端·flink
开心就好20254 小时前
H5 混合应用加密 Web 资源暴露到 IPA 层防护的完整技术方案
后端
bcbnb4 小时前
最新版本iOS系统设备管理功能全面指南
后端
开心就好20254 小时前
Fastlane + Appuploader 的工程组合,自动化发布中的分工
后端
YDS8294 小时前
SpringCould —— 网关详解
后端·spring·spring cloud
华仔啊4 小时前
如何避免MySQL死锁?资深DBA的9条黄金法则
后端·mysql
老华带你飞4 小时前
列车售票|基于springboot 列车售票系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习·spring
青韵5 小时前
Claude 高级工具使用解析:从上下文优化到程序化调用的工程实践
后端