01-Java开发环境与基础语法

学习目标

  • 掌握JDK的安装与环境变量配置
  • 熟练使用IDEA开发工具进行Java开发
  • 理解Java程序的基本结构和执行流程
  • 掌握Java基础语法(变量、数据类型、运算符)
  • 熟练使用控制流程语句(if、switch、for、while)
  • 掌握数组和字符串的基本操作
  • 能够编写简单的Java控制台程序

知识结构思维导图

Java开发环境与基础语法

开发环境

JDK安装

环境变量配置

IDEA安装

IDEA配置

第一个程序

基础语法

变量与常量

数据类型

类型转换

运算符

表达式

控制流程

顺序结构

选择结构

if语句

switch语句

循环结构

for循环

while循环

do-while循环

跳转语句

break

continue

return

数组

一维数组

二维数组

数组遍历

数组排序

字符串

String类

字符串操作

字符串比较

字符串拼接

一、为什么需要学习Java?

1.1 实际工作中的场景

假设你想进入互联网公司做后端开发,你会发现:

场景1:招聘要求

  • 阿里巴巴:熟练掌握Java,了解Spring框架
  • 腾讯:精通Java,熟悉多线程编程
  • 字节跳动:Java基础扎实,了解JVM原理
  • 美团:熟练使用Java进行后端开发

场景2:技术选型

  • 电商系统:淘宝、京东、拼多多都使用Java
  • 金融系统:支付宝、微信支付核心系统用Java
  • 企业应用:大部分企业级应用都基于Java
  • 大数据:Hadoop、Spark等大数据框架都是Java编写

场景3:薪资待遇

  • Java初级工程师:8K-15K
  • Java中级工程师:15K-30K
  • Java高级工程师:30K-50K
  • Java架构师:50K+

1.2 Java的优势

为什么Java这么流行?

  1. 跨平台性

    • 一次编写,到处运行(Write Once, Run Anywhere)
    • 通过JVM实现跨平台
    • 支持Windows、Linux、Mac等操作系统
  2. 面向对象

    • 更符合人类思维方式
    • 代码复用性强
    • 易于维护和扩展
  3. 丰富的生态

    • 海量的开源框架和库
    • Spring、MyBatis、Netty等优秀框架
    • 活跃的社区支持
  4. 企业级应用

    • 稳定可靠
    • 性能优秀
    • 安全性高
  5. 就业机会多

    • 市场需求大
    • 薪资待遇好
    • 职业发展空间大

1.3 Java能做什么?

Java应用领域
├── 后端开发
│   ├── Web应用(电商、社交、内容平台)
│   ├── 微服务架构
│   └── RESTful API
├── 大数据
│   ├── Hadoop生态
│   ├── Spark计算
│   └── Flink流处理
├── Android开发
│   └── 移动应用
├── 企业应用
│   ├── ERP系统
│   ├── CRM系统
│   └── OA系统
└── 游戏开发
    └── 服务端开发

二、JDK安装与配置

2.1 什么是JDK?

在开始之前,我们需要理解几个概念:

JDK、JRE、JVM的关系:

┌─────────────────────────────────────┐
│              JDK                     │
│  (Java Development Kit)              │
│  ┌───────────────────────────────┐  │
│  │          JRE                   │  │
│  │  (Java Runtime Environment)    │  │
│  │  ┌─────────────────────────┐  │  │
│  │  │        JVM              │  │  │
│  │  │  (Java Virtual Machine) │  │  │
│  │  │                         │  │  │
│  │  │  执行Java字节码         │  │  │
│  │  └─────────────────────────┘  │  │
│  │                                │  │
│  │  Java核心类库                  │  │
│  └───────────────────────────────┘  │
│                                      │
│  开发工具(javac、jar等)            │
└─────────────────────────────────────┘
  • JVM:Java虚拟机,负责执行Java程序
  • JRE:Java运行环境,包含JVM和核心类库,用于运行Java程序
  • JDK:Java开发工具包,包含JRE和开发工具,用于开发Java程序

为什么需要JDK?

  • 编写Java程序需要使用javac编译器(JDK提供)
  • 运行Java程序需要JVM(JDK包含)
  • 开发过程需要各种工具(jar、javadoc等,JDK提供)

2.2 JDK版本选择

JDK版本历史:

版本 发布时间 重要特性 推荐度
JDK 8 2014年 Lambda表达式、Stream API ⭐⭐⭐⭐⭐
JDK 11 2018年 长期支持版本(LTS) ⭐⭐⭐⭐
JDK 17 2021年 长期支持版本(LTS) ⭐⭐⭐⭐
JDK 21 2023年 长期支持版本(LTS) ⭐⭐⭐

建议:

  • 学习阶段:使用JDK 8(企业使用最广泛)
  • 新项目:可以考虑JDK 11或JDK 17
  • 本教程:基于JDK 8讲解

2.3 Windows系统安装JDK

2.3.1 下载JDK

方式1:Oracle官网下载

  1. 访问:https://www.oracle.com/java/technologies/downloads/
  2. 选择Java 8版本
  3. 下载Windows x64版本的安装包(jdk-8uXXX-windows-x64.exe)

方式2:使用OpenJDK

  1. 访问:https://adoptium.net/
  2. 选择JDK 8
  3. 下载Windows x64版本
2.3.2 安装JDK
  1. 双击安装包

    • 运行下载的.exe文件
    • 点击"下一步"
  2. 选择安装路径

    建议路径:D:\Java\jdk1.8.0_XXX
    不建议:C:\Program Files\Java\...(路径有空格)
    
  3. 完成安装

    • 记住安装路径,后面配置环境变量需要用到
    • 点击"完成"
2.3.3 配置环境变量

为什么要配置环境变量?

  • 让系统能在任何位置找到java和javac命令
  • 方便在命令行中使用Java工具

配置步骤:

  1. 打开环境变量设置

    右键"此电脑" → 属性 → 高级系统设置 → 环境变量
    
  2. 新建JAVA_HOME变量

    • 点击"系统变量"下的"新建"
    • 变量名:JAVA_HOME
    • 变量值:D:\Java\jdk1.8.0_XXX(你的JDK安装路径)
    • 点击"确定"
  3. 配置Path变量

    • 在"系统变量"中找到Path变量
    • 点击"编辑"
    • 点击"新建"
    • 添加:%JAVA_HOME%\bin
    • 点击"确定"
  4. 新建CLASSPATH变量(可选)

    • 变量名:CLASSPATH
    • 变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar
    • 点击"确定"

配置示意图:

环境变量配置
├── JAVA_HOME
│   └── D:\Java\jdk1.8.0_XXX
├── Path
│   ├── %JAVA_HOME%\bin
│   └── 其他路径...
└── CLASSPATH(可选)
    └── .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar
2.3.4 验证安装

打开命令提示符(Win+R,输入cmd),执行以下命令:

# 查看Java版本
java -version

正确输出示例:

java version "1.8.0_XXX"
Java(TM) SE Runtime Environment (build 1.8.0_XXX-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.XXX-b13, mixed mode)
# 查看编译器版本
javac -version

正确输出示例:

javac 1.8.0_XXX

如果出现"不是内部或外部命令"错误:

  • 检查JAVA_HOME是否配置正确
  • 检查Path中是否添加了%JAVA_HOME%\bin
  • 重新打开命令提示符窗口

2.4 Mac系统安装JDK

2.4.1 使用Homebrew安装(推荐)
# 安装Homebrew(如果还没安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 安装JDK 8
brew install openjdk@8

# 创建软链接
sudo ln -sfn /usr/local/opt/openjdk@8/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-8.jdk
2.4.2 配置环境变量

编辑/.bash_profile或/.zshrc文件:

# 打开配置文件
vim ~/.zshrc  # 如果使用zsh
# 或
vim ~/.bash_profile  # 如果使用bash

# 添加以下内容
export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-8.jdk/Contents/Home
export PATH=$JAVA_HOME/bin:$PATH

# 保存后执行
source ~/.zshrc  # 或 source ~/.bash_profile
2.4.3 验证安装
java -version
javac -version

2.5 Linux系统安装JDK

2.5.1 Ubuntu/Debian系统
# 更新包列表
sudo apt-get update

# 安装JDK 8
sudo apt-get install openjdk-8-jdk

# 验证安装
java -version
javac -version
2.5.2 CentOS/RHEL系统
# 安装JDK 8
sudo yum install java-1.8.0-openjdk-devel

# 验证安装
java -version
javac -version
2.5.3 配置环境变量

编辑/etc/profile文件:

# 编辑配置文件
sudo vim /etc/profile

# 添加以下内容
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

# 保存后执行
source /etc/profile

三、IDEA开发工具安装与配置

3.1 为什么选择IDEA?

IDEA vs Eclipse vs VS Code:

特性 IDEA Eclipse VS Code
智能提示 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
性能 ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
插件生态 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
Java支持 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐
学习曲线 ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
企业使用率 85% 10% 5%

IDEA的优势:

  1. 智能的代码提示和补全
  2. 强大的重构功能
  3. 内置的版本控制集成
  4. 丰富的插件生态
  5. 优秀的调试功能

3.2 IDEA安装

3.2.1 下载IDEA

访问JetBrains官网:https://www.jetbrains.com/idea/download/

版本选择:

  • Ultimate(旗舰版):功能完整,支持Web开发、数据库工具等,需要付费
  • Community(社区版):免费,功能够用,适合学习

学生福利:

  • 学生可以申请免费的教育许可使用旗舰版
  • 访问:https://www.jetbrains.com/community/education/
  • 使用学校邮箱注册即可
3.2.2 Windows安装步骤
  1. 运行安装程序

    • 双击下载的.exe文件
    • 点击"Next"
  2. 选择安装路径

    建议路径:D:\Program Files\JetBrains\IntelliJ IDEA
    
  3. 选择安装选项

    • ✓ Create Desktop Shortcut(创建桌面快捷方式)
    • ✓ Update PATH variable(添加到环境变量)
    • ✓ Update context menu(添加右键菜单)
    • ✓ Create Associations(关联.java文件)
  4. 完成安装

    • 点击"Install"
    • 等待安装完成
    • 点击"Finish"
3.2.3 首次启动配置

1. 导入设置

  • 首次启动选择"Do not import settings"

2. 选择主题

  • Darcula(暗色主题):护眼,适合长时间编码
  • Light(亮色主题):清爽,适合白天使用

3. 安装推荐插件

必装插件:

1. Lombok
   - 简化Java代码,自动生成getter/setter
   
2. Maven Helper
   - Maven依赖管理助手
   
3. Rainbow Brackets
   - 彩虹括号,让代码层次更清晰
   
4. Translation
   - 翻译插件,快速翻译英文注释
   
5. Alibaba Java Coding Guidelines
   - 阿里巴巴Java编码规范检查
   
6. GitToolBox
   - Git增强工具
   
7. Key Promoter X
   - 快捷键提示工具

安装插件方法:

File → Settings → Plugins → Marketplace → 搜索插件名 → Install

3.3 IDEA基础配置

3.3.1 配置JDK
File → Project Structure → SDKs → + → JDK → 选择JDK安装路径

验证JDK配置:

  • 查看SDKs列表中是否有JDK 1.8
  • 查看JDK路径是否正确
3.3.2 字体和编码设置

1. 编辑器字体

File → Settings → Editor → Font

推荐配置:

  • Font: JetBrains Mono(IDEA自带的等宽字体)
  • Size: 14(根据屏幕大小调整)
  • Line height: 1.2
  • Enable ligatures: ✓(启用连字)

2. 控制台字体

File → Settings → Editor → Color Scheme → Console Font

3. 文件编码

File → Settings → Editor → File Encodings

全部设置为UTF-8:

  • Global Encoding: UTF-8
  • Project Encoding: UTF-8
  • Default encoding for properties files: UTF-8
  • ✓ Transparent native-to-ascii conversion
3.3.3 代码风格设置
File → Settings → Editor → Code Style → Java

推荐配置:

  • Tab size: 4
  • Indent: 4
  • Continuation indent: 8
  • ✓ Use tab character: 取消勾选(使用空格)
3.3.4 自动导入设置
File → Settings → Editor → General → Auto Import

勾选:

  • ✓ Add unambiguous imports on the fly(自动导入明确的包)
  • ✓ Optimize imports on the fly(自动优化导入)
3.3.5 代码模板设置
File → Settings → Editor → Live Templates

常用模板:

  • psvm + Tab:生成main方法
  • sout + Tab:生成System.out.println()
  • fori + Tab:生成for循环
  • ifn + Tab:生成if null判断

自定义模板示例:

创建一个快速生成注释的模板:

Abbreviation: /**
Template text:
/**
 * $END$
 * @author YourName
 * @date $date$
 */

3.4 IDEA常用快捷键

必须掌握的快捷键:

功能 Windows/Linux Mac 说明
查找类 Ctrl + N Cmd + O 快速打开类
查找文件 Ctrl + Shift + N Cmd + Shift + O 快速打开文件
全局搜索 Ctrl + Shift + F Cmd + Shift + F 在项目中搜索
运行程序 Shift + F10 Ctrl + R 运行当前程序
调试程序 Shift + F9 Ctrl + D 调试当前程序
格式化代码 Ctrl + Alt + L Cmd + Option + L 格式化代码
优化导入 Ctrl + Alt + O Ctrl + Option + O 优化import语句
快速修复 Alt + Enter Option + Enter 智能提示修复
重命名 Shift + F6 Shift + F6 重命名变量/方法/类
查看定义 Ctrl + B Cmd + B 跳转到定义
返回上一位置 Ctrl + Alt + ← Cmd + Option + ← 返回上一个编辑位置
前进下一位置 Ctrl + Alt + → Cmd + Option + → 前进到下一个位置
复制当前行 Ctrl + D Cmd + D 复制当前行
删除当前行 Ctrl + Y Cmd + Delete 删除当前行
移动代码行 Ctrl + Shift + ↑/↓ Cmd + Shift + ↑/↓ 上下移动代码
注释/取消注释 Ctrl + / Cmd + / 单行注释
块注释 Ctrl + Shift + / Cmd + Shift + / 多行注释
代码提示 Ctrl + Space Ctrl + Space 代码补全
查看参数 Ctrl + P Cmd + P 查看方法参数
查看文档 Ctrl + Q Ctrl + J 查看快速文档

快捷键记忆技巧:

查找相关:Ctrl/Cmd + N/Shift+N/Shift+F
运行调试:Shift + F9/F10
代码编辑:Ctrl/Cmd + Alt/Option + 字母
导航跳转:Ctrl/Cmd + B/Alt+←/→

3.5 创建第一个Java项目

3.5.1 创建项目
  1. 启动IDEA

    • 点击"New Project"
  2. 配置项目

    Name: HelloJava
    Location: D:\JavaProjects\HelloJava
    Language: Java
    Build system: IntelliJ
    JDK: 1.8
    
  3. 创建项目结构

    HelloJava/
    ├── .idea/          # IDEA配置文件
    ├── src/            # 源代码目录
    └── HelloJava.iml   # 项目配置文件
    
3.5.2 创建Java类
  1. 右键src目录

    • New → Java Class
  2. 输入类名

    • Name: HelloWorld
    • 点击OK
  3. 生成的文件

    public class HelloWorld {
    }
    
3.5.3 编写第一个程序
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, Java!");
    }
}

代码解释:

public class HelloWorld {
//  ↑      ↑      ↑
//  |      |      └── 类名(必须与文件名相同)
//  |      └── class关键字,表示这是一个类
//  └── public关键字,表示公开的

    public static void main(String[] args) {
    //  ↑      ↑     ↑    ↑      ↑       ↑
    //  |      |     |    |      |       └── 参数(命令行参数)
    //  |      |     |    |      └── 参数类型(字符串数组)
    //  |      |     |    └── 方法名(程序入口)
    //  |      |     └── 返回类型(void表示无返回值)
    //  |      └── static关键字,表示静态方法
    //  └── public关键字,表示公开的
    
        System.out.println("Hello, Java!");
        //  ↑     ↑    ↑         ↑
        //  |     |    |         └── 要输出的内容
        //  |     |    └── println方法(输出并换行)
        //  |     └── out对象(标准输出流)
        //  └── System类(系统类)
    }
}
3.5.4 运行程序

方式1:使用快捷键

  • 按Shift + F10运行

方式2:使用菜单

  • Run → Run ‘HelloWorld’

方式3:使用右键

  • 右键代码编辑区 → Run ‘HelloWorld.main()’

方式4:使用绿色三角按钮

  • 点击main方法左侧的绿色三角按钮

运行结果:

Hello, Java!

Process finished with exit code 0

exit code说明:

  • 0:程序正常结束
  • 非0:程序异常结束

3.6 Java程序执行流程

编写Java源代码

使用javac编译

生成字节码文件.class

JVM加载字节码

JVM执行程序

程序结束

详细流程:

  1. 编写源代码

    • 文件名:HelloWorld.java
    • 内容:Java源代码
  2. 编译源代码

    javac HelloWorld.java
    
    • 编译器检查语法错误
    • 生成字节码文件:HelloWorld.class
  3. 运行程序

    java HelloWorld
    
    • JVM加载字节码
    • JVM解释执行或JIT编译执行
    • 输出结果

为什么Java是跨平台的?

源代码(.java)
    ↓ javac编译
字节码(.class)
    ↓
┌───────────────────────────────────┐
│         JVM(跨平台)              │
├───────────────────────────────────┤
│  Windows JVM  │  Linux JVM  │ Mac JVM │
└───────────────────────────────────┘
    ↓              ↓              ↓
Windows系统    Linux系统      Mac系统
  • 字节码是平台无关的
  • 不同操作系统有不同的JVM实现
  • JVM负责将字节码转换为特定平台的机器码

四、Java基础语法

4.1 注释

为什么需要注释?

  • 解释代码的作用和意图
  • 提高代码可读性
  • 方便团队协作
  • 帮助自己回忆代码逻辑

Java中的三种注释:

// 1. 单行注释
// 这是单行注释,用于简短的说明

/*
 * 2. 多行注释
 * 这是多行注释
 * 可以写多行内容
 * 用于较长的说明
 */

/**
 * 3. 文档注释
 * 这是文档注释,用于生成API文档
 * @author 作者名
 * @version 1.0
 */
public class CommentDemo {
    /**
     * 计算两个数的和
     * @param a 第一个数
     * @param b 第二个数
     * @return 两数之和
     */
    public int add(int a, int b) {
        return a + b;  // 返回计算结果
    }
}

注释的最佳实践:

// ✓ 好的注释:解释为什么这样做
// 使用二分查找提高查询效率
int result = binarySearch(arr, target);

// ✗ 不好的注释:重复代码内容
// 调用binarySearch方法
int result = binarySearch(arr, target);

4.2 标识符和关键字

标识符命名规则:

  1. 只能包含字母、数字、下划线(_)和美元符号($)
  2. 不能以数字开头
  3. 不能使用Java关键字
  4. 区分大小写
// ✓ 合法的标识符
int age;
String userName;
double _salary;
int $price;

// ✗ 非法的标识符
int 123abc;    // 不能以数字开头
int class;     // 不能使用关键字
int user-name; // 不能使用连字符

Java关键字(共53个):

类别 关键字
访问控制 private, protected, public
类、方法和变量修饰符 abstract, class, extends, final, implements, interface, native, new, static, strictfp, synchronized, transient, volatile
程序控制 break, continue, return, do, while, if, else, for, instanceof, switch, case, default
错误处理 try, catch, throw, throws, finally
包相关 import, package
基本类型 boolean, byte, char, double, float, int, long, short
变量引用 super, this, void
保留字 goto, const

4.3 变量和常量

什么是变量?

  • 变量是内存中的一块存储空间
  • 用于存储数据
  • 变量的值可以改变

变量声明和初始化:

public class VariableDemo {
    public static void main(String[] args) {
        // 声明变量
        int age;
        
        // 初始化变量
        age = 18;
        
        // 声明并初始化
        String name = "张三";
        
        // 声明多个变量
        int a, b, c;
        
        // 声明并初始化多个变量
        int x = 1, y = 2, z = 3;
        
        System.out.println("姓名:" + name);
        System.out.println("年龄:" + age);
    }
}

变量的作用域:

public class ScopeDemo {
    // 成员变量(类变量):在整个类中有效
    static int classVar = 100;
    
    // 成员变量(实例变量):在整个对象中有效
    int instanceVar = 200;
    
    public void method() {
        // 局部变量:只在方法内有效
        int localVar = 300;
        
        System.out.println(classVar);     // 可以访问
        System.out.println(instanceVar);  // 可以访问
        System.out.println(localVar);     // 可以访问
    }
    
    public void anotherMethod() {
        System.out.println(classVar);     // 可以访问
        System.out.println(instanceVar);  // 可以访问
        // System.out.println(localVar);  // 错误!无法访问
    }
}

常量:

public class ConstantDemo {
    // 使用final关键字声明常量
    public static final double PI = 3.14159;
    public static final int MAX_SIZE = 100;
    
    public static void main(String[] args) {
        System.out.println("圆周率:" + PI);
        
        // PI = 3.14;  // 错误!常量不能被修改
        
        // 计算圆的面积
        double radius = 5.0;
        double area = PI * radius * radius;
        System.out.println("圆的面积:" + area);
    }
}

命名规范:

// 变量命名:小驼峰命名法
int studentAge;
String userName;
double totalPrice;

// 常量命名:全大写,下划线分隔
final int MAX_COUNT = 100;
final String DEFAULT_NAME = "Guest";
final double TAX_RATE = 0.06;

4.4 数据类型

Java数据类型分类:

Java数据类型
├── 基本数据类型(8种)
│   ├── 整数类型
│   │   ├── byte(1字节)
│   │   ├── short(2字节)
│   │   ├── int(4字节)
│   │   └── long(8字节)
│   ├── 浮点类型
│   │   ├── float(4字节)
│   │   └── double(8字节)
│   ├── 字符类型
│   │   └── char(2字节)
│   └── 布尔类型
│       └── boolean(1位)
└── 引用数据类型
    ├── 类(Class)
    ├── 接口(Interface)
    └── 数组(Array)

基本数据类型详解:

类型 字节 取值范围 默认值 示例
byte 1 -128 ~ 127 0 byte b = 100;
short 2 -32768 ~ 32767 0 short s = 1000;
int 4 -2^31 ~ 2^31-1 0 int i = 100000;
long 8 -2^63 ~ 2^63-1 0L long l = 100000L;
float 4 ±3.4E+38 0.0f float f = 3.14f;
double 8 ±1.7E+308 0.0d double d = 3.14;
char 2 0 ~ 65535 ‘\u0000’ char c = ‘A’;
boolean 1位 true/false false boolean flag = true;

代码示例:

public class DataTypeDemo {
    public static void main(String[] args) {
        // 整数类型
        byte byteVar = 127;              // 1字节,-128~127
        short shortVar = 32767;          // 2字节
        int intVar = 2147483647;         // 4字节(最常用)
        long longVar = 9223372036854775807L;  // 8字节,注意L后缀
        
        System.out.println("byte: " + byteVar);
        System.out.println("short: " + shortVar);
        System.out.println("int: " + intVar);
        System.out.println("long: " + longVar);
        
        // 浮点类型
        float floatVar = 3.14f;          // 4字节,注意f后缀
        double doubleVar = 3.141592653;  // 8字节(最常用)
        
        System.out.println("float: " + floatVar);
        System.out.println("double: " + doubleVar);
        
        // 字符类型
        char charVar1 = 'A';             // 单个字符
        char charVar2 = '中';            // 中文字符
        char charVar3 = 65;              // ASCII码
        
        System.out.println("char1: " + charVar1);
        System.out.println("char2: " + charVar2);
        System.out.println("char3: " + charVar3);  // 输出A
        
        // 布尔类型
        boolean boolVar1 = true;
        boolean boolVar2 = false;
        
        System.out.println("boolean1: " + boolVar1);
        System.out.println("boolean2: " + boolVar2);
        
        // 字符串(引用类型)
        String strVar = "Hello, Java!";
        System.out.println("String: " + strVar);
    }
}

为什么有这么多整数类型?

public class IntegerTypeChoice {
    public static void main(String[] args) {
        // 场景1:存储年龄(0-150)
        byte age = 25;  // 使用byte节省内存
        
        // 场景2:存储商品价格(分为单位)
        int price = 9999;  // 使用int,范围足够
        
        // 场景3:存储用户ID(可能很大)
        long userId = 1234567890123L;  // 使用long
        
        // 场景4:大量数据存储
        // 假设有1亿条记录,每条记录存储一个年龄
        // 使用byte:100,000,000 * 1 = 100MB
        // 使用int:100,000,000 * 4 = 400MB
        // 节省了300MB内存!
    }
}

4.5 类型转换

自动类型转换(隐式转换):

小类型 → 大类型(自动转换)

byte → short → int → long → float → double
         ↑
        char
public class AutoConversion {
    public static void main(String[] args) {
        // 自动类型转换
        byte b = 10;
        int i = b;        // byte自动转换为int
        long l = i;       // int自动转换为long
        float f = l;      // long自动转换为float
        double d = f;     // float自动转换为double
        
        System.out.println("byte: " + b);
        System.out.println("int: " + i);
        System.out.println("long: " + l);
        System.out.println("float: " + f);
        System.out.println("double: " + d);
        
        // 字符类型转换
        char c = 'A';
        int ascii = c;    // char自动转换为int(ASCII码)
        System.out.println("字符A的ASCII码: " + ascii);  // 65
    }
}

强制类型转换(显式转换):

public class ForcedConversion {
    public static void main(String[] args) {
        // 强制类型转换:大类型 → 小类型
        double d = 3.14;
        int i = (int) d;  // 强制转换,小数部分会丢失
        System.out.println("double: " + d);  // 3.14
        System.out.println("int: " + i);     // 3
        
        // 注意:可能会溢出
        int bigNum = 130;
        byte b = (byte) bigNum;  // 强制转换
        System.out.println("int: " + bigNum);  // 130
        System.out.println("byte: " + b);      // -126(溢出)
        
        // 字符串转数字
        String str = "123";
        int num = Integer.parseInt(str);
        System.out.println("字符串转数字: " + num);
        
        // 数字转字符串
        int number = 456;
        String string = String.valueOf(number);
        System.out.println("数字转字符串: " + string);
    }
}

类型转换的注意事项:

public class ConversionPitfalls {
    public static void main(String[] args) {
        // 陷阱1:整数除法
        int a = 5;
        int b = 2;
        double result1 = a / b;  // 结果是2.0,不是2.5!
        System.out.println("5 / 2 = " + result1);  // 2.0
        
        // 正确做法:先转换为double
        double result2 = (double) a / b;
        System.out.println("5.0 / 2 = " + result2);  // 2.5
        
        // 陷阱2:溢出
        int max = Integer.MAX_VALUE;
        System.out.println("int最大值: " + max);  // 2147483647
        int overflow = max + 1;
        System.out.println("溢出后: " + overflow);  // -2147483648
        
        // 陷阱3:精度丢失
        float f = 123456789f;
        System.out.println("float: " + f);  // 1.23456792E8(精度丢失)
        
        // 陷阱4:字符串转换异常
        try {
            String invalid = "abc";
            int num = Integer.parseInt(invalid);  // 抛出异常
        } catch (NumberFormatException e) {
            System.out.println("字符串格式错误: " + e.getMessage());
        }
    }
}

4.6 运算符

运算符分类:

Java运算符
├── 算术运算符:+、-、*、/、%、++、--
├── 赋值运算符:=、+=、-=、*=、/=、%=
├── 比较运算符:==、!=、>、<、>=、<=
├── 逻辑运算符:&&、||、!
├── 位运算符:&、|、^、~、<<、>>、>>>
├── 三元运算符:? :
└── instanceof运算符
4.6.1 算术运算符
public class ArithmeticOperator {
    public static void main(String[] args) {
        int a = 10;
        int b = 3;
        
        // 基本算术运算
        System.out.println("a + b = " + (a + b));  // 13
        System.out.println("a - b = " + (a - b));  // 7
        System.out.println("a * b = " + (a * b));  // 30
        System.out.println("a / b = " + (a / b));  // 3(整数除法)
        System.out.println("a % b = " + (a % b));  // 1(取余)
        
        // 浮点数除法
        double c = 10.0;
        double d = 3.0;
        System.out.println("c / d = " + (c / d));  // 3.3333...
        
        // 自增自减运算符
        int x = 5;
        System.out.println("x = " + x);      // 5
        System.out.println("x++ = " + x++);  // 5(先使用后自增)
        System.out.println("x = " + x);      // 6
        System.out.println("++x = " + ++x);  // 7(先自增后使用)
        System.out.println("x = " + x);      // 7
        
        int y = 5;
        System.out.println("y-- = " + y--);  // 5(先使用后自减)
        System.out.println("y = " + y);      // 4
        System.out.println("--y = " + --y);  // 3(先自减后使用)
        System.out.println("y = " + y);      // 3
    }
}

++和–的区别:

public class IncrementDemo {
    public static void main(String[] args) {
        // 前置++:先自增,后使用
        int a = 5;
        int b = ++a;  // a先变成6,然后赋值给b
        System.out.println("a = " + a + ", b = " + b);  // a = 6, b = 6
        
        // 后置++:先使用,后自增
        int c = 5;
        int d = c++;  // c的值5先赋值给d,然后c变成6
        System.out.println("c = " + c + ", d = " + d);  // c = 6, d = 5
        
        // 实际应用场景
        int[] arr = {1, 2, 3, 4, 5};
        int index = 0;
        
        // 使用后置++
        System.out.println(arr[index++]);  // 输出1,index变成1
        System.out.println(arr[index++]);  // 输出2,index变成2
        System.out.println(arr[index++]);  // 输出3,index变成3
    }
}
4.6.2 赋值运算符
public class AssignmentOperator {
    public static void main(String[] args) {
        int a = 10;
        
        // 复合赋值运算符
        a += 5;  // 等价于 a = a + 5
        System.out.println("a += 5: " + a);  // 15
        
        a -= 3;  // 等价于 a = a - 3
        System.out.println("a -= 3: " + a);  // 12
        
        a *= 2;  // 等价于 a = a * 2
        System.out.println("a *= 2: " + a);  // 24
        
        a /= 4;  // 等价于 a = a / 4
        System.out.println("a /= 4: " + a);  // 6
        
        a %= 4;  // 等价于 a = a % 4
        System.out.println("a %= 4: " + a);  // 2
        
        // 注意:复合赋值运算符会自动进行类型转换
        byte b = 10;
        // b = b + 5;  // 错误!int不能自动转换为byte
        b += 5;        // 正确!复合赋值运算符会自动转换
        System.out.println("b = " + b);  // 15
    }
}
4.6.3 比较运算符
public class ComparisonOperator {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        
        System.out.println("a == b: " + (a == b));  // false
        System.out.println("a != b: " + (a != b));  // true
        System.out.println("a > b: " + (a > b));    // false
        System.out.println("a < b: " + (a < b));    // true
        System.out.println("a >= b: " + (a >= b));  // false
        System.out.println("a <= b: " + (a <= b));  // true
        
        // 字符串比较
        String str1 = "Hello";
        String str2 = "Hello";
        String str3 = new String("Hello");
        
        // ==比较的是引用地址
        System.out.println("str1 == str2: " + (str1 == str2));    // true
        System.out.println("str1 == str3: " + (str1 == str3));    // false
        
        // equals()比较的是内容
        System.out.println("str1.equals(str3): " + str1.equals(str3));  // true
    }
}
4.6.4 逻辑运算符
public class LogicalOperator {
    public static void main(String[] args) {
        boolean a = true;
        boolean b = false;
        
        // 逻辑与(&&):两个都为true才为true
        System.out.println("a && b: " + (a && b));  // false
        System.out.println("a && a: " + (a && a));  // true
        
        // 逻辑或(||):有一个为true就为true
        System.out.println("a || b: " + (a || b));  // true
        System.out.println("b || b: " + (b || b));  // false
        
        // 逻辑非(!):取反
        System.out.println("!a: " + (!a));  // false
        System.out.println("!b: " + (!b));  // true
        
        // 短路特性
        int x = 5;
        int y = 10;
        
        // &&短路:如果第一个条件为false,不会执行第二个条件
        if (x > 10 && ++y > 10) {
            System.out.println("条件成立");
        }
        System.out.println("y = " + y);  // 10(y没有自增)
        
        // ||短路:如果第一个条件为true,不会执行第二个条件
        if (x < 10 || ++y > 10) {
            System.out.println("条件成立");
        }
        System.out.println("y = " + y);  // 10(y没有自增)
        
        // 实际应用:避免空指针异常
        String str = null;
        // if (str.length() > 0) {  // 错误!会抛出空指针异常
        if (str != null && str.length() > 0) {  // 正确!利用短路特性
            System.out.println("字符串不为空");
        }
    }
}
4.6.5 三元运算符
public class TernaryOperator {
    public static void main(String[] args) {
        // 语法:条件 ? 值1 : 值2
        // 如果条件为true,返回值1;否则返回值2
        
        int a = 10;
        int b = 20;
        
        // 找出较大的数
        int max = (a > b) ? a : b;
        System.out.println("较大的数: " + max);  // 20
        
        // 判断奇偶
        int num = 15;
        String result = (num % 2 == 0) ? "偶数" : "奇数";
        System.out.println(num + "是" + result);  // 15是奇数
        
        // 嵌套使用(不推荐,可读性差)
        int score = 85;
        String grade = (score >= 90) ? "优秀" :
                      (score >= 80) ? "良好" :
                      (score >= 60) ? "及格" : "不及格";
        System.out.println("成绩等级: " + grade);  // 良好
        
        // 等价的if-else写法(推荐)
        String grade2;
        if (score >= 90) {
            grade2 = "优秀";
        } else if (score >= 80) {
            grade2 = "良好";
        } else if (score >= 60) {
            grade2 = "及格";
        } else {
            grade2 = "不及格";
        }
        System.out.println("成绩等级: " + grade2);
    }
}

运算符优先级:

优先级 运算符 说明
1 ()、[] 括号、数组下标
2 ++、– 自增、自减
3 !、~ 逻辑非、按位取反
4 *、/、% 乘、除、取余
5 +、- 加、减
6 <<、>>、>>> 位移
7 <、<=、>、>= 比较
8 ==、!= 相等、不等
9 & 按位与
10 ^ 按位异或
11 | 按位或
12 && 逻辑与
13 || 逻辑或
14 ?: 三元运算符
15 =、+=、-=等 赋值
public class OperatorPriority {
    public static void main(String[] args) {
        // 优先级示例
        int result1 = 10 + 20 * 3;  // 先乘后加
        System.out.println(result1);  // 70
        
        int result2 = (10 + 20) * 3;  // 括号优先级最高
        System.out.println(result2);  // 90
        
        boolean result3 = 5 > 3 && 10 < 20;  // 先比较后逻辑
        System.out.println(result3);  // true
        
        // 建议:复杂表达式使用括号提高可读性
        int a = 5, b = 10, c = 15;
        int result4 = (a + b) * c / (a - b);
        System.out.println(result4);
    }
}

五、控制流程语句

5.1 为什么需要控制流程?

在实际开发中,程序不可能总是从上到下顺序执行,我们需要:

  • 根据条件执行不同的代码(选择结构)
  • 重复执行某段代码(循环结构)
  • 在特定条件下跳出循环(跳转语句)

实际场景:

用户登录系统:
1. 判断用户名和密码是否正确(if语句)
2. 如果正确,跳转到首页
3. 如果错误,提示错误信息,重新输入(循环)

5.2 if语句

基本语法:

// 单分支if语句
if (条件) {
    // 条件为true时执行
}

// 双分支if-else语句
if (条件) {
    // 条件为true时执行
} else {
    // 条件为false时执行
}

// 多分支if-else if-else语句
if (条件1) {
    // 条件1为true时执行
} else if (条件2) {
    // 条件2为true时执行
} else if (条件3) {
    // 条件3为true时执行
} else {
    // 所有条件都为false时执行
}

代码示例1:判断年龄

public class IfDemo1 {
    public static void main(String[] args) {
        int age = 18;
        
        // 单分支if
        if (age >= 18) {
            System.out.println("你已经成年了");
        }
        
        // 双分支if-else
        if (age >= 18) {
            System.out.println("你可以考驾照了");
        } else {
            System.out.println("你还不能考驾照");
        }
        
        // 多分支if-else if-else
        if (age < 6) {
            System.out.println("学龄前儿童");
        } else if (age < 12) {
            System.out.println("小学生");
        } else if (age < 15) {
            System.out.println("初中生");
        } else if (age < 18) {
            System.out.println("高中生");
        } else {
            System.out.println("成年人");
        }
    }
}

代码示例2:用户登录验证

public class LoginDemo {
    public static void main(String[] args) {
        // 模拟用户输入
        String username = "admin";
        String password = "123456";
        
        // 正确的用户名和密码
        String correctUsername = "admin";
        String correctPassword = "123456";
        
        // 验证登录
        if (username.equals(correctUsername) && password.equals(correctPassword)) {
            System.out.println("登录成功!");
            System.out.println("欢迎回来," + username);
        } else {
            System.out.println("登录失败!");
            if (!username.equals(correctUsername)) {
                System.out.println("用户名错误");
            }
            if (!password.equals(correctPassword)) {
                System.out.println("密码错误");
            }
        }
    }
}

代码示例3:成绩等级判断

public class GradeDemo {
    public static void main(String[] args) {
        int score = 85;
        
        // 输入验证
        if (score < 0 || score > 100) {
            System.out.println("成绩输入错误!");
            return;
        }
        
        // 等级判断
        String grade;
        if (score >= 90) {
            grade = "优秀";
        } else if (score >= 80) {
            grade = "良好";
        } else if (score >= 70) {
            grade = "中等";
        } else if (score >= 60) {
            grade = "及格";
        } else {
            grade = "不及格";
        }
        
        System.out.println("成绩:" + score);
        System.out.println("等级:" + grade);
        
        // 额外提示
        if (score >= 90) {
            System.out.println("太棒了!继续保持!");
        } else if (score < 60) {
            System.out.println("需要加油了!");
        }
    }
}

代码示例4:闰年判断

public class LeapYearDemo {
    public static void main(String[] args) {
        int year = 2024;
        
        // 闰年判断规则:
        // 1. 能被4整除但不能被100整除
        // 2. 或者能被400整除
        boolean isLeapYear;
        
        if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
            isLeapYear = true;
        } else {
            isLeapYear = false;
        }
        
        if (isLeapYear) {
            System.out.println(year + "年是闰年");
        } else {
            System.out.println(year + "年不是闰年");
        }
    }
}

if语句的注意事项:

public class IfPitfalls {
    public static void main(String[] args) {
        int a = 5;
        
        // 陷阱1:使用=而不是==
        // if (a = 10) {  // 错误!赋值语句不能作为条件
        if (a == 10) {  // 正确!
            System.out.println("a等于10");
        }
        
        // 陷阱2:浮点数比较
        double d1 = 0.1 + 0.2;
        double d2 = 0.3;
        // if (d1 == d2) {  // 可能不相等!浮点数精度问题
        if (Math.abs(d1 - d2) < 0.0001) {  // 正确!使用误差范围
            System.out.println("相等");
        }
        
        // 陷阱3:空指针判断
        String str = null;
        // if (str.equals("hello")) {  // 错误!空指针异常
        if (str != null && str.equals("hello")) {  // 正确!先判断非空
            System.out.println("字符串是hello");
        }
        
        // 陷阱4:即使只有一行代码也建议使用大括号
        if (a > 0)
            System.out.println("a是正数");
            // System.out.println("这行代码总是执行");  // 容易误解
        
        // 推荐写法
        if (a > 0) {
            System.out.println("a是正数");
        }
    }
}

5.3 switch语句

基本语法:

switch (表达式) {
    case1:
        // 代码块1
        break;
    case2:
        // 代码块2
        break;
    case3:
        // 代码块3
        break;
    default:
        // 默认代码块
        break;
}

代码示例1:星期判断

public class SwitchDemo1 {
    public static void main(String[] args) {
        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 = "无效的日期";
                break;
        }
        
        System.out.println("今天是:" + dayName);
    }
}

代码示例2:季节判断

public class SwitchDemo2 {
    public static void main(String[] args) {
        int month = 6;
        String season;
        
        switch (month) {
            case 3:
            case 4:
            case 5:
                season = "春季";
                break;
            case 6:
            case 7:
            case 8:
                season = "夏季";
                break;
            case 9:
            case 10:
            case 11:
                season = "秋季";
                break;
            case 12:
            case 1:
            case 2:
                season = "冬季";
                break;
            default:
                season = "无效的月份";
                break;
        }
        
        System.out.println(month + "月是" + season);
    }
}

代码示例3:计算器

public class CalculatorDemo {
    public static void main(String[] args) {
        double num1 = 10;
        double num2 = 5;
        char operator = '+';
        double result = 0;
        boolean validOperation = true;
        
        switch (operator) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                if (num2 != 0) {
                    result = num1 / num2;
                } else {
                    System.out.println("错误:除数不能为0");
                    validOperation = false;
                }
                break;
            case '%':
                if (num2 != 0) {
                    result = num1 % num2;
                } else {
                    System.out.println("错误:除数不能为0");
                    validOperation = false;
                }
                break;
            default:
                System.out.println("错误:无效的运算符");
                validOperation = false;
                break;
        }
        
        if (validOperation) {
            System.out.println(num1 + " " + operator + " " + num2 + " = " + result);
        }
    }
}

代码示例4:成绩等级(使用switch)

public class GradeSwitchDemo {
    public static void main(String[] args) {
        int score = 85;
        String grade;
        
        // 将分数转换为等级(0-9)
        int level = score / 10;
        
        switch (level) {
            case 10:
            case 9:
                grade = "优秀";
                break;
            case 8:
                grade = "良好";
                break;
            case 7:
                grade = "中等";
                break;
            case 6:
                grade = "及格";
                break;
            default:
                grade = "不及格";
                break;
        }
        
        System.out.println("成绩:" + score);
        System.out.println("等级:" + grade);
    }
}

switch语句的注意事项:

public class SwitchPitfalls {
    public static void main(String[] args) {
        // 注意1:break的重要性
        int num = 2;
        System.out.println("没有break的情况:");
        switch (num) {
            case 1:
                System.out.println("case 1");
                // 没有break,会继续执行下一个case
            case 2:
                System.out.println("case 2");
                // 没有break,会继续执行下一个case
            case 3:
                System.out.println("case 3");
                break;
            default:
                System.out.println("default");
        }
        // 输出:case 2, case 3(发生了case穿透)
        
        // 注意2:支持的数据类型
        // JDK 7之前:byte、short、int、char、枚举
        // JDK 7及以后:增加了String
        
        String fruit = "apple";
        switch (fruit) {
            case "apple":
                System.out.println("苹果");
                break;
            case "banana":
                System.out.println("香蕉");
                break;
            case "orange":
                System.out.println("橙子");
                break;
            default:
                System.out.println("未知水果");
                break;
        }
        
        // 注意3:不支持的数据类型
        // long、float、double、boolean都不支持
        // long longNum = 100L;
        // switch (longNum) {  // 错误!不支持long类型
        //     case 100L:
        //         break;
        // }
    }
}

if vs switch:如何选择?

场景 推荐使用 原因
判断范围 if switch只能判断相等
多个相等值判断 switch 代码更简洁清晰
复杂条件 if switch不支持复杂表达式
字符串匹配 switch 性能更好(JDK 7+)
布尔判断 if switch不支持boolean
public class IfVsSwitch {
    public static void main(String[] args) {
        int score = 85;
        
        // 场景1:范围判断 - 使用if
        if (score >= 90) {
            System.out.println("优秀");
        } else if (score >= 80) {
            System.out.println("良好");
        } else if (score >= 60) {
            System.out.println("及格");
        } else {
            System.out.println("不及格");
        }
        
        // 场景2:相等值判断 - 使用switch
        int day = 3;
        switch (day) {
            case 1:
                System.out.println("星期一");
                break;
            case 2:
                System.out.println("星期二");
                break;
            case 3:
                System.out.println("星期三");
                break;
            // ...
        }
    }
}

5.4 for循环

基本语法:

for (初始化; 条件判断; 更新) {
    // 循环体
}

执行流程:

true

false

开始

初始化

条件判断

执行循环体

更新

结束

代码示例1:打印1到10

public class ForDemo1 {
    public static void main(String[] args) {
        // 打印1到10
        for (int i = 1; i <= 10; i++) {
            System.out.println(i);
        }
        
        // 打印10到1
        for (int i = 10; i >= 1; i--) {
            System.out.println(i);
        }
        
        // 打印偶数
        for (int i = 0; i <= 10; i += 2) {
            System.out.println(i);
        }
    }
}

代码示例2:计算累加和

public class ForDemo2 {
    public static void main(String[] args) {
        // 计算1+2+3+...+100
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        System.out.println("1到100的和:" + sum);  // 5050
        
        // 计算1+3+5+...+99(奇数和)
        int oddSum = 0;
        for (int i = 1; i <= 99; i += 2) {
            oddSum += i;
        }
        System.out.println("1到99的奇数和:" + oddSum);  // 2500
        
        // 计算阶乘:5! = 5*4*3*2*1
        int factorial = 1;
        for (int i = 1; i <= 5; i++) {
            factorial *= i;
        }
        System.out.println("5的阶乘:" + factorial);  // 120
    }
}

代码示例3:打印图形

public class ForDemo3 {
    public static void main(String[] args) {
        // 打印矩形
        System.out.println("矩形:");
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 10; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
        
        // 打印直角三角形
        System.out.println("\n直角三角形:");
        for (int i = 1; i <= 5; i++) {
            for (int j = 1; j <= i; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
        
        // 打印倒直角三角形
        System.out.println("\n倒直角三角形:");
        for (int i = 5; i >= 1; i--) {
            for (int j = 1; j <= i; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
        
        // 打印等腰三角形
        System.out.println("\n等腰三角形:");
        for (int i = 1; i <= 5; i++) {
            // 打印空格
            for (int j = 1; j <= 5 - i; j++) {
                System.out.print(" ");
            }
            // 打印星号
            for (int j = 1; j <= 2 * i - 1; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

代码示例4:九九乘法表

public class MultiplicationTable {
    public static void main(String[] args) {
        System.out.println("九九乘法表:");
        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= i; j++) {
                System.out.print(j + "×" + i + "=" + (i * j) + "\t");
            }
            System.out.println();
        }
    }
}

输出结果:

九九乘法表:
1×1=1	
1×2=2	2×2=4	
1×3=3	2×3=6	3×3=9	
1×4=4	2×4=8	3×4=12	4×4=16	
1×5=5	2×5=10	3×5=15	4×5=20	5×5=25	
1×6=6	2×6=12	3×6=18	4×6=24	5×6=30	6×6=36	
1×7=7	2×7=14	3×7=21	4×7=28	5×7=35	6×7=42	7×7=49	
1×8=8	2×8=16	3×8=24	4×8=32	5×8=40	6×8=48	7×8=56	8×8=64	
1×9=9	2×9=18	3×9=27	4×9=36	5×9=45	6×9=54	7×9=63	8×9=72	9×9=81	

代码示例5:查找质数

public class PrimeNumber {
    public static void main(String[] args) {
        System.out.println("100以内的质数:");
        int count = 0;
        
        for (int num = 2; num <= 100; num++) {
            boolean isPrime = true;
            
            // 判断num是否为质数
            for (int i = 2; i <= Math.sqrt(num); i++) {
                if (num % i == 0) {
                    isPrime = false;
                    break;
                }
            }
            
            if (isPrime) {
                System.out.print(num + " ");
                count++;
                if (count % 10 == 0) {
                    System.out.println();
                }
            }
        }
        
        System.out.println("\n共有" + count + "个质数");
    }
}

5.5 while循环

基本语法:

while (条件) {
    // 循环体
}

执行流程:

true

false

开始

条件判断

执行循环体

结束

代码示例1:基本使用

public class WhileDemo1 {
    public static void main(String[] args) {
        // 打印1到10
        int i = 1;
        while (i <= 10) {
            System.out.println(i);
            i++;
        }
        
        // 计算1到100的和
        int sum = 0;
        int num = 1;
        while (num <= 100) {
            sum += num;
            num++;
        }
        System.out.println("1到100的和:" + sum);
    }
}

代码示例2:用户输入验证

import java.util.Scanner;

public class WhileDemo2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int password = 123456;
        int input;
        int attempts = 0;
        int maxAttempts = 3;
        
        while (attempts < maxAttempts) {
            System.out.print("请输入密码:");
            input = scanner.nextInt();
            
            if (input == password) {
                System.out.println("密码正确,登录成功!");
                break;
            } else {
                attempts++;
                int remaining = maxAttempts - attempts;
                if (remaining > 0) {
                    System.out.println("密码错误,还有" + remaining + "次机会");
                } else {
                    System.out.println("密码错误次数过多,账户已锁定");
                }
            }
        }
        
        scanner.close();
    }
}

代码示例3:猜数字游戏

import java.util.Random;
import java.util.Scanner;

public class GuessNumber {
    public static void main(String[] args) {
        Random random = new Random();
        Scanner scanner = new Scanner(System.in);
        
        int targetNumber = random.nextInt(100) + 1;  // 1-100的随机数
        int guess;
        int attempts = 0;
        
        System.out.println("猜数字游戏开始!");
        System.out.println("我想了一个1到100之间的数字,你能猜到吗?");
        
        while (true) {
            System.out.print("请输入你的猜测:");
            guess = scanner.nextInt();
            attempts++;
            
            if (guess == targetNumber) {
                System.out.println("恭喜你!猜对了!");
                System.out.println("你一共猜了" + attempts + "次");
                break;
            } else if (guess < targetNumber) {
                System.out.println("太小了,再试试!");
            } else {
                System.out.println("太大了,再试试!");
            }
        }
        
        scanner.close();
    }
}

代码示例4:数字反转

public class ReverseNumber {
    public static void main(String[] args) {
        int num = 12345;
        int reversed = 0;
        
        System.out.println("原数字:" + num);
        
        while (num != 0) {
            int digit = num % 10;      // 获取最后一位
            reversed = reversed * 10 + digit;  // 添加到反转数字
            num = num / 10;            // 去掉最后一位
        }
        
        System.out.println("反转后:" + reversed);
    }
}

5.6 do-while循环

基本语法:

do {
    // 循环体
} while (条件);

与while的区别:

  • while:先判断条件,再执行循环体(可能一次都不执行)
  • do-while:先执行循环体,再判断条件(至少执行一次)

true

false

开始

执行循环体

条件判断

结束

代码示例1:基本使用

public class DoWhileDemo1 {
    public static void main(String[] args) {
        // do-while循环
        int i = 1;
        do {
            System.out.println(i);
            i++;
        } while (i <= 10);
        
        // 对比:while循环
        int j = 11;
        while (j <= 10) {
            System.out.println(j);  // 不会执行
            j++;
        }
        
        // do-while至少执行一次
        int k = 11;
        do {
            System.out.println(k);  // 会执行一次
            k++;
        } while (k <= 10);
    }
}

代码示例2:菜单系统

import java.util.Scanner;

public class MenuSystem {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int choice;
        
        do {
            System.out.println("\n===== 学生管理系统 =====");
            System.out.println("1. 添加学生");
            System.out.println("2. 删除学生");
            System.out.println("3. 查询学生");
            System.out.println("4. 修改学生");
            System.out.println("0. 退出系统");
            System.out.print("请选择操作:");
            
            choice = scanner.nextInt();
            
            switch (choice) {
                case 1:
                    System.out.println("执行添加学生操作...");
                    break;
                case 2:
                    System.out.println("执行删除学生操作...");
                    break;
                case 3:
                    System.out.println("执行查询学生操作...");
                    break;
                case 4:
                    System.out.println("执行修改学生操作...");
                    break;
                case 0:
                    System.out.println("感谢使用,再见!");
                    break;
                default:
                    System.out.println("无效的选择,请重新输入!");
                    break;
            }
        } while (choice != 0);
        
        scanner.close();
    }
}

5.7 break和continue语句

break:跳出循环

public class BreakDemo {
    public static void main(String[] args) {
        // 示例1:找到第一个能被7整除的数
        for (int i = 1; i <= 100; i++) {
            if (i % 7 == 0) {
                System.out.println("第一个能被7整除的数是:" + i);
                break;  // 找到后立即退出循环
            }
        }
        
        // 示例2:在嵌套循环中使用break
        System.out.println("\n在嵌套循环中使用break:");
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                if (j == 2) {
                    break;  // 只跳出内层循环
                }
                System.out.println("i=" + i + ", j=" + j);
            }
        }
        
        // 示例3:使用标签跳出外层循环
        System.out.println("\n使用标签跳出外层循环:");
        outer:
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                if (j == 2) {
                    break outer;  // 跳出外层循环
                }
                System.out.println("i=" + i + ", j=" + j);
            }
        }
    }
}

continue:跳过本次循环

public class ContinueDemo {
    public static void main(String[] args) {
        // 示例1:打印1到10的奇数
        System.out.println("1到10的奇数:");
        for (int i = 1; i <= 10; i++) {
            if (i % 2 == 0) {
                continue;  // 跳过偶数
            }
            System.out.print(i + " ");
        }
        
        // 示例2:计算1到100中不能被3整除的数的和
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 3 == 0) {
                continue;  // 跳过能被3整除的数
            }
            sum += i;
        }
        System.out.println("\n1到100中不能被3整除的数的和:" + sum);
        
        // 示例3:在嵌套循环中使用continue
        System.out.println("\n在嵌套循环中使用continue:");
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                if (j == 2) {
                    continue;  // 跳过j=2的情况
                }
                System.out.println("i=" + i + ", j=" + j);
            }
        }
    }
}

break vs continue:

语句 作用 使用场景
break 跳出整个循环 找到目标后不需要继续循环
continue 跳过本次循环,继续下一次 某些情况不需要处理,但循环要继续
public class BreakVsContinue {
    public static void main(String[] args) {
        // 使用break
        System.out.println("使用break:");
        for (int i = 1; i <= 10; i++) {
            if (i == 5) {
                break;  // 遇到5就停止
            }
            System.out.print(i + " ");
        }
        // 输出:1 2 3 4
        
        // 使用continue
        System.out.println("\n\n使用continue:");
        for (int i = 1; i <= 10; i++) {
            if (i == 5) {
                continue;  // 跳过5,继续后面的
            }
            System.out.print(i + " ");
        }
        // 输出:1 2 3 4 6 7 8 9 10
    }
}

5.8 循环的选择

for vs while vs do-while:

循环类型 适用场景 特点
for 循环次数确定 代码简洁,初始化、条件、更新在一行
while 循环次数不确定 先判断条件,可能一次都不执行
do-while 至少执行一次 先执行后判断,适合菜单系统
public class LoopChoice {
    public static void main(String[] args) {
        // 场景1:循环次数确定 - 使用for
        System.out.println("打印1到10:");
        for (int i = 1; i <= 10; i++) {
            System.out.print(i + " ");
        }
        
        // 场景2:循环次数不确定 - 使用while
        System.out.println("\n\n计算2的幂次,直到超过1000:");
        int power = 1;
        int exponent = 0;
        while (power <= 1000) {
            System.out.println("2^" + exponent + " = " + power);
            power *= 2;
            exponent++;
        }
        
        // 场景3:至少执行一次 - 使用do-while
        System.out.println("\n输入验证(至少提示一次):");
        int input;
        do {
            System.out.println("请输入1-10之间的数字");
            input = 5;  // 模拟用户输入
            break;  // 为了演示,这里直接退出
        } while (input < 1 || input > 10);
    }
}

循环性能优化技巧:

public class LoopOptimization {
    public static void main(String[] args) {
        int[] arr = new int[1000];
        
        // 技巧1:减少循环内的计算
        // ✗ 不好的写法
        for (int i = 0; i < arr.length; i++) {
            // arr.length在每次循环都会计算
        }
        
        // ✓ 好的写法
        int length = arr.length;
        for (int i = 0; i < length; i++) {
            // length只计算一次
        }
        
        // 技巧2:避免在循环中创建对象
        // ✗ 不好的写法
        for (int i = 0; i < 1000; i++) {
            String str = new String("hello");  // 每次都创建新对象
        }
        
        // ✓ 好的写法
        String str = "hello";
        for (int i = 0; i < 1000; i++) {
            // 使用同一个对象
        }
        
        // 技巧3:使用增强for循环(如果不需要索引)
        // ✗ 不够简洁
        for (int i = 0; i < arr.length; i++) {
            int value = arr[i];
            // 处理value
        }
        
        // ✓ 更简洁
        for (int value : arr) {
            // 处理value
        }
    }
}

六、数组

6.1 为什么需要数组?

问题场景:

// 如果要存储100个学生的成绩,难道要这样写吗?
int score1 = 85;
int score2 = 90;
int score3 = 78;
// ... 写100个变量?

使用数组的好处:

  • 用一个变量存储多个相同类型的数据
  • 通过索引快速访问任意元素
  • 方便进行批量操作

6.2 一维数组

数组的概念:

  • 数组是存储相同类型数据的集合
  • 数组的长度固定,创建后不能改变
  • 数组元素通过索引访问,索引从0开始

数组的声明和初始化:

public class ArrayDemo1 {
    public static void main(String[] args) {
        // 方式1:声明后再分配空间
        int[] arr1;           // 声明数组
        arr1 = new int[5];    // 分配空间,默认值为0
        
        // 方式2:声明并分配空间
        int[] arr2 = new int[5];
        
        // 方式3:声明并初始化
        int[] arr3 = {1, 2, 3, 4, 5};
        
        // 方式4:声明并初始化(完整写法)
        int[] arr4 = new int[]{1, 2, 3, 4, 5};
        
        // 注意:两种声明方式都可以
        int[] arr5 = new int[5];  // 推荐
        int arr6[] = new int[5];  // 不推荐
        
        // 访问数组元素
        System.out.println("arr3[0] = " + arr3[0]);  // 1
        System.out.println("arr3[1] = " + arr3[1]);  // 2
        
        // 修改数组元素
        arr3[0] = 10;
        System.out.println("修改后 arr3[0] = " + arr3[0]);  // 10
        
        // 获取数组长度
        System.out.println("数组长度:" + arr3.length);  // 5
    }
}

数组的内存结构:

栈内存                    堆内存
┌─────────┐              ┌─────────────────┐
│  arr    │──────────────│ [0] = 1         │
│ (引用)   │              │ [1] = 2         │
└─────────┘              │ [2] = 3         │
                         │ [3] = 4         │
                         │ [4] = 5         │
                         └─────────────────┘

代码示例1:学生成绩管理

public class StudentScores {
    public static void main(String[] args) {
        // 存储5个学生的成绩
        int[] scores = {85, 92, 78, 90, 88};
        
        // 计算总分
        int sum = 0;
        for (int i = 0; i < scores.length; i++) {
            sum += scores[i];
        }
        
        // 计算平均分
        double average = (double) sum / scores.length;
        
        // 找出最高分和最低分
        int max = scores[0];
        int min = scores[0];
        for (int i = 1; i < scores.length; i++) {
            if (scores[i] > max) {
                max = scores[i];
            }
            if (scores[i] < min) {
                min = scores[i];
            }
        }
        
        System.out.println("总分:" + sum);
        System.out.println("平均分:" + average);
        System.out.println("最高分:" + max);
        System.out.println("最低分:" + min);
    }
}

代码示例2:数组反转

public class ArrayReverse {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};
        
        System.out.println("原数组:");
        printArray(arr);
        
        // 方法1:使用临时数组
        int[] reversed = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            reversed[i] = arr[arr.length - 1 - i];
        }
        
        System.out.println("反转后(方法1):");
        printArray(reversed);
        
        // 方法2:原地反转
        for (int i = 0; i < arr.length / 2; i++) {
            int temp = arr[i];
            arr[i] = arr[arr.length - 1 - i];
            arr[arr.length - 1 - i] = temp;
        }
        
        System.out.println("反转后(方法2):");
        printArray(arr);
    }
    
    // 打印数组的方法
    public static void printArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}

代码示例3:数组复制

public class ArrayCopy {
    public static void main(String[] args) {
        int[] source = {1, 2, 3, 4, 5};
        
        // 方法1:使用循环复制
        int[] copy1 = new int[source.length];
        for (int i = 0; i < source.length; i++) {
            copy1[i] = source[i];
        }
        
        // 方法2:使用System.arraycopy()
        int[] copy2 = new int[source.length];
        System.arraycopy(source, 0, copy2, 0, source.length);
        
        // 方法3:使用Arrays.copyOf()
        int[] copy3 = java.util.Arrays.copyOf(source, source.length);
        
        // 方法4:使用clone()
        int[] copy4 = source.clone();
        
        // 注意:直接赋值不是复制,而是引用
        int[] notCopy = source;  // notCopy和source指向同一个数组
        notCopy[0] = 100;
        System.out.println("source[0] = " + source[0]);  // 100(被修改了)
        
        // 真正的复制
        copy1[0] = 200;
        System.out.println("source[0] = " + source[0]);  // 100(没有被修改)
    }
}

6.3 数组遍历

方式1:普通for循环

public class ArrayTraversal1 {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30, 40, 50};
        
        // 正向遍历
        System.out.println("正向遍历:");
        for (int i = 0; i < arr.length; i++) {
            System.out.println("arr[" + i + "] = " + arr[i]);
        }
        
        // 反向遍历
        System.out.println("\n反向遍历:");
        for (int i = arr.length - 1; i >= 0; i--) {
            System.out.println("arr[" + i + "] = " + arr[i]);
        }
    }
}

方式2:增强for循环(foreach)

public class ArrayTraversal2 {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30, 40, 50};
        
        // 增强for循环
        System.out.println("增强for循环:");
        for (int value : arr) {
            System.out.println(value);
        }
        
        // 注意:增强for循环不能修改数组元素
        for (int value : arr) {
            value = value * 2;  // 这不会修改数组
        }
        System.out.println("arr[0] = " + arr[0]);  // 还是10
        
        // 如果要修改,必须使用普通for循环
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr[i] * 2;  // 这会修改数组
        }
        System.out.println("arr[0] = " + arr[0]);  // 变成20
    }
}

6.4 数组排序

冒泡排序:

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        
        System.out.println("排序前:");
        printArray(arr);
        
        bubbleSort(arr);
        
        System.out.println("排序后:");
        printArray(arr);
    }
    
    /**
     * 冒泡排序
     * 原理:相邻元素两两比较,大的往后移
     * 时间复杂度:O(n²)
     */
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        
        // 外层循环:控制排序轮数
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false;  // 优化:记录是否发生交换
            
            // 内层循环:进行相邻元素比较
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换元素
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    swapped = true;
                }
            }
            
            // 如果这一轮没有发生交换,说明已经有序
            if (!swapped) {
                break;
            }
        }
    }
    
    public static void printArray(int[] arr) {
        for (int value : arr) {
            System.out.print(value + " ");
        }
        System.out.println();
    }
}

选择排序:

public class SelectionSort {
    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        
        System.out.println("排序前:");
        printArray(arr);
        
        selectionSort(arr);
        
        System.out.println("排序后:");
        printArray(arr);
    }
    
    /**
     * 选择排序
     * 原理:每次选择最小的元素放到前面
     * 时间复杂度:O(n²)
     */
    public static void selectionSort(int[] arr) {
        int n = arr.length;
        
        for (int i = 0; i < n - 1; i++) {
            // 找到最小元素的索引
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            
            // 交换元素
            if (minIndex != i) {
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }
    
    public static void printArray(int[] arr) {
        for (int value : arr) {
            System.out.print(value + " ");
        }
        System.out.println();
    }
}

使用Arrays工具类排序:

import java.util.Arrays;

public class ArraysSort {
    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        
        System.out.println("排序前:");
        System.out.println(Arrays.toString(arr));
        
        // 使用Arrays.sort()排序(快速排序,时间复杂度O(n log n))
        Arrays.sort(arr);
        
        System.out.println("排序后:");
        System.out.println(Arrays.toString(arr));
        
        // 部分排序:只排序索引1到4的元素
        int[] arr2 = {64, 34, 25, 12, 22, 11, 90};
        Arrays.sort(arr2, 1, 5);  // 排序arr2[1]到arr2[4]
        System.out.println("部分排序:");
        System.out.println(Arrays.toString(arr2));
    }
}

6.5 数组查找

线性查找:

public class LinearSearch {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30, 40, 50};
        int target = 30;
        
        int index = linearSearch(arr, target);
        
        if (index != -1) {
            System.out.println("找到了,索引为:" + index);
        } else {
            System.out.println("没找到");
        }
    }
    
    /**
     * 线性查找
     * 时间复杂度:O(n)
     */
    public static int linearSearch(int[] arr, int target) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) {
                return i;
            }
        }
        return -1;  // 没找到返回-1
    }
}

二分查找:

public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30, 40, 50, 60, 70, 80, 90};  // 必须是有序数组
        int target = 50;
        
        int index = binarySearch(arr, target);
        
        if (index != -1) {
            System.out.println("找到了,索引为:" + index);
        } else {
            System.out.println("没找到");
        }
        
        // 使用Arrays.binarySearch()
        int index2 = java.util.Arrays.binarySearch(arr, target);
        System.out.println("使用Arrays.binarySearch():" + index2);
    }
    
    /**
     * 二分查找
     * 前提:数组必须有序
     * 时间复杂度:O(log n)
     */
    public static int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;
        
        while (left <= right) {
            int mid = left + (right - left) / 2;  // 防止溢出
            
            if (arr[mid] == target) {
                return mid;  // 找到了
            } else if (arr[mid] < target) {
                left = mid + 1;  // 在右半部分
            } else {
                right = mid - 1;  // 在左半部分
            }
        }
        
        return -1;  // 没找到
    }
}

6.6 二维数组

二维数组的概念:

  • 二维数组是数组的数组
  • 可以理解为表格或矩阵
  • 通过两个索引访问元素:arr[行][列]

二维数组的声明和初始化:

public class TwoDimensionalArray1 {
    public static void main(String[] args) {
        // 方式1:声明并分配空间
        int[][] arr1 = new int[3][4];  // 3行4列
        
        // 方式2:声明并初始化
        int[][] arr2 = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12}
        };
        
        // 方式3:不规则数组
        int[][] arr3 = new int[3][];  // 只指定行数
        arr3[0] = new int[2];  // 第一行2列
        arr3[1] = new int[3];  // 第二行3列
        arr3[2] = new int[4];  // 第三行4列
        
        // 访问元素
        System.out.println("arr2[0][0] = " + arr2[0][0]);  // 1
        System.out.println("arr2[1][2] = " + arr2[1][2]);  // 7
        
        // 修改元素
        arr2[0][0] = 100;
        System.out.println("修改后 arr2[0][0] = " + arr2[0][0]);  // 100
        
        // 获取行数和列数
        System.out.println("行数:" + arr2.length);        // 3
        System.out.println("第一行列数:" + arr2[0].length);  // 4
    }
}

二维数组的遍历:

public class TwoDimensionalArray2 {
    public static void main(String[] args) {
        int[][] arr = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12}
        };
        
        // 方式1:使用嵌套for循环
        System.out.println("方式1:嵌套for循环");
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + "\t");
            }
            System.out.println();
        }
        
        // 方式2:使用增强for循环
        System.out.println("\n方式2:增强for循环");
        for (int[] row : arr) {
            for (int value : row) {
                System.out.print(value + "\t");
            }
            System.out.println();
        }
    }
}

代码示例:学生成绩表

public class StudentScoreTable {
    public static void main(String[] args) {
        // 3个学生,4门课程的成绩
        int[][] scores = {
            {85, 90, 78, 92},  // 学生1的成绩
            {88, 76, 95, 89},  // 学生2的成绩
            {92, 88, 85, 90}   // 学生3的成绩
        };
        
        String[] students = {"张三", "李四", "王五"};
        String[] subjects = {"语文", "数学", "英语", "物理"};
        
        // 打印成绩表
        System.out.println("学生成绩表:");
        System.out.print("姓名\t");
        for (String subject : subjects) {
            System.out.print(subject + "\t");
        }
        System.out.println("总分\t平均分");
        
        // 计算每个学生的总分和平均分
        for (int i = 0; i < scores.length; i++) {
            System.out.print(students[i] + "\t");
            int sum = 0;
            for (int j = 0; j < scores[i].length; j++) {
                System.out.print(scores[i][j] + "\t");
                sum += scores[i][j];
            }
            double average = (double) sum / scores[i].length;
            System.out.printf("%d\t%.2f\n", sum, average);
        }
        
        // 计算每门课程的平均分
        System.out.println("\n各科平均分:");
        for (int j = 0; j < subjects.length; j++) {
            int sum = 0;
            for (int i = 0; i < scores.length; i++) {
                sum += scores[i][j];
            }
            double average = (double) sum / scores.length;
            System.out.printf("%s:%.2f\n", subjects[j], average);
        }
    }
}

代码示例:矩阵转置

public class MatrixTranspose {
    public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
        
        System.out.println("原矩阵:");
        printMatrix(matrix);
        
        int[][] transposed = transpose(matrix);
        
        System.out.println("\n转置后:");
        printMatrix(transposed);
    }
    
    /**
     * 矩阵转置
     * 将行变成列,列变成行
     */
    public static int[][] transpose(int[][] matrix) {
        int rows = matrix.length;
        int cols = matrix[0].length;
        
        int[][] result = new int[cols][rows];
        
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                result[j][i] = matrix[i][j];
            }
        }
        
        return result;
    }
    
    public static void printMatrix(int[][] matrix) {
        for (int[] row : matrix) {
            for (int value : row) {
                System.out.print(value + "\t");
            }
            System.out.println();
        }
    }
}

6.7 数组常见问题

问题1:数组越界

public class ArrayIndexOutOfBounds {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};
        
        // 正确访问
        System.out.println(arr[0]);  // 1
        System.out.println(arr[4]);  // 5
        
        // 错误访问
        try {
            System.out.println(arr[5]);  // 越界!抛出ArrayIndexOutOfBoundsException
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界:" + e.getMessage());
        }
        
        // 正确的做法:先检查索引
        int index = 5;
        if (index >= 0 && index < arr.length) {
            System.out.println(arr[index]);
        } else {
            System.out.println("索引越界");
        }
    }
}

问题2:空指针异常

public class NullPointerException {
    public static void main(String[] args) {
        int[] arr = null;
        
        // 错误:访问null数组
        try {
            System.out.println(arr.length);  // 空指针异常!
        } catch (java.lang.NullPointerException e) {
            System.out.println("空指针异常:" + e.getMessage());
        }
        
        // 正确的做法:先检查是否为null
        if (arr != null) {
            System.out.println(arr.length);
        } else {
            System.out.println("数组为null");
        }
    }
}

问题3:数组复制陷阱

public class ArrayCopyPitfall {
    public static void main(String[] args) {
        int[] arr1 = {1, 2, 3, 4, 5};
        
        // 错误:这不是复制,而是引用
        int[] arr2 = arr1;
        arr2[0] = 100;
        System.out.println("arr1[0] = " + arr1[0]);  // 100(被修改了)
        
        // 正确:真正的复制
        int[] arr3 = arr1.clone();
        arr3[0] = 200;
        System.out.println("arr1[0] = " + arr1[0]);  // 100(没有被修改)
        
        // 二维数组的浅复制问题
        int[][] matrix1 = {{1, 2}, {3, 4}};
        int[][] matrix2 = matrix1.clone();  // 浅复制
        matrix2[0][0] = 100;
        System.out.println("matrix1[0][0] = " + matrix1[0][0]);  // 100(被修改了)
        
        // 二维数组的深复制
        int[][] matrix3 = new int[matrix1.length][];
        for (int i = 0; i < matrix1.length; i++) {
            matrix3[i] = matrix1[i].clone();
        }
        matrix3[0][0] = 200;
        System.out.println("matrix1[0][0] = " + matrix1[0][0]);  // 100(没有被修改)
    }
}

七、字符串

7.1 为什么需要字符串?

实际场景:

  • 用户登录:需要处理用户名和密码
  • 数据展示:需要格式化输出信息
  • 文件操作:需要处理文件路径和内容
  • 网络通信:需要处理URL和请求参数

7.2 String类基础

String的特点:

  1. String是引用类型,不是基本类型
  2. String对象是不可变的(immutable)
  3. String对象存储在字符串常量池中

String的创建:

public class StringDemo1 {
    public static void main(String[] args) {
        // 方式1:字面量创建(推荐)
        String str1 = "Hello";
        
        // 方式2:使用new关键字
        String str2 = new String("Hello");
        
        // 方式3:使用字符数组
        char[] chars = {'H', 'e', 'l', 'l', 'o'};
        String str3 = new String(chars);
        
        // 方式4:使用字节数组
        byte[] bytes = {72, 101, 108, 108, 111};
        String str4 = new String(bytes);
        
        System.out.println(str1);  // Hello
        System.out.println(str2);  // Hello
        System.out.println(str3);  // Hello
        System.out.println(str4);  // Hello
        
        // 字面量 vs new的区别
        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(内容相同)
    }
}

String的内存结构:

字符串常量池                堆内存
┌─────────────┐           ┌─────────────┐
│  "Hello"    │←──────────│  s1         │
└─────────────┘           └─────────────┘
      ↑                   ┌─────────────┐
      └───────────────────│  s2         │
                          └─────────────┘
                          ┌─────────────┐
                          │  s3         │──→ new String("Hello")
                          └─────────────┘

7.3 String常用方法

长度和判空:

public class StringMethods1 {
    public static void main(String[] args) {
        String str = "Hello, Java!";
        
        // 获取长度
        System.out.println("长度:" + str.length());  // 12
        
        // 判断是否为空
        String empty = "";
        String nullStr = null;
        
        System.out.println("empty.isEmpty(): " + empty.isEmpty());  // true
        System.out.println("str.isEmpty(): " + str.isEmpty());      // false
        
        // 注意:null字符串不能调用方法
        // System.out.println(nullStr.isEmpty());  // 空指针异常!
        
        // 正确的判空方式
        if (nullStr != null && !nullStr.isEmpty()) {
            System.out.println("字符串不为空");
        } else {
            System.out.println("字符串为空或null");
        }
    }
}

字符访问:

public class StringMethods2 {
    public static void main(String[] args) {
        String str = "Hello";
        
        // 获取指定位置的字符
        char ch = str.charAt(0);
        System.out.println("第一个字符:" + ch);  // H
        
        // 遍历字符串
        System.out.println("遍历字符串:");
        for (int i = 0; i < str.length(); i++) {
            System.out.println(str.charAt(i));
        }
        
        // 转换为字符数组
        char[] chars = str.toCharArray();
        System.out.println("字符数组:");
        for (char c : chars) {
            System.out.print(c + " ");
        }
    }
}

字符串比较:

public class StringMethods3 {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "Hello";
        String str3 = "hello";
        String str4 = new String("Hello");
        
        // ==比较:比较引用地址
        System.out.println("str1 == str2: " + (str1 == str2));    // true
        System.out.println("str1 == str4: " + (str1 == str4));    // false
        
        // equals():比较内容
        System.out.println("str1.equals(str2): " + str1.equals(str2));  // true
        System.out.println("str1.equals(str3): " + str1.equals(str3));  // false
        System.out.println("str1.equals(str4): " + str1.equals(str4));  // true
        
        // equalsIgnoreCase():忽略大小写比较
        System.out.println("str1.equalsIgnoreCase(str3): " + str1.equalsIgnoreCase(str3));  // true
        
        // compareTo():字典序比较
        System.out.println("str1.compareTo(str2): " + str1.compareTo(str2));  // 0(相等)
        System.out.println("str1.compareTo(str3): " + str1.compareTo(str3));  // -32(str1小于str3)
        
        // startsWith()和endsWith()
        String url = "https://www.example.com";
        System.out.println("以https开头:" + url.startsWith("https"));  // true
        System.out.println("以.com结尾:" + url.endsWith(".com"));      // true
    }
}

字符串查找:

public class StringMethods4 {
    public static void main(String[] args) {
        String str = "Hello, Java! Java is great!";
        
        // indexOf():查找子串第一次出现的位置
        int index1 = str.indexOf("Java");
        System.out.println("Java第一次出现的位置:" + index1);  // 7
        
        // indexOf(String, int):从指定位置开始查找
        int index2 = str.indexOf("Java", 10);
        System.out.println("从位置10开始,Java出现的位置:" + index2);  // 13
        
        // lastIndexOf():查找子串最后一次出现的位置
        int index3 = str.lastIndexOf("Java");
        System.out.println("Java最后一次出现的位置:" + index3);  // 13
        
        // contains():判断是否包含子串
        boolean contains = str.contains("Java");
        System.out.println("包含Java:" + contains);  // true
        
        // 查找不存在的子串
        int index4 = str.indexOf("Python");
        System.out.println("Python的位置:" + index4);  // -1(不存在)
    }
}

字符串截取:

public class StringMethods5 {
    public static void main(String[] args) {
        String str = "Hello, Java!";
        
        // substring(int beginIndex):从指定位置截取到末尾
        String sub1 = str.substring(7);
        System.out.println("从位置7截取:" + sub1);  // Java!
        
        // substring(int beginIndex, int endIndex):截取指定范围
        String sub2 = str.substring(7, 11);
        System.out.println("截取7到11:" + sub2);  // Java
        
        // 实际应用:提取文件扩展名
        String filename = "document.pdf";
        int dotIndex = filename.lastIndexOf(".");
        String extension = filename.substring(dotIndex + 1);
        System.out.println("文件扩展名:" + extension);  // pdf
        
        // 实际应用:提取域名
        String url = "https://www.example.com/path";
        int start = url.indexOf("://") + 3;
        int end = url.indexOf("/", start);
        String domain = url.substring(start, end);
        System.out.println("域名:" + domain);  // www.example.com
    }
}

字符串替换:

public class StringMethods6 {
    public static void main(String[] args) {
        String str = "Hello, Java! Java is great!";
        
        // replace():替换所有匹配的字符或子串
        String replaced1 = str.replace('a', 'A');
        System.out.println("替换a为A:" + replaced1);
        
        String replaced2 = str.replace("Java", "Python");
        System.out.println("替换Java为Python:" + replaced2);
        
        // replaceFirst():只替换第一个匹配的子串
        String replaced3 = str.replaceFirst("Java", "Python");
        System.out.println("替换第一个Java:" + replaced3);
        
        // replaceAll():使用正则表达式替换
        String str2 = "abc123def456";
        String replaced4 = str2.replaceAll("\\d+", "#");
        System.out.println("替换所有数字:" + replaced4);  // abc#def#
        
        // 实际应用:敏感词过滤
        String content = "这是一条包含敏感词的内容";
        String filtered = content.replace("敏感词", "***");
        System.out.println("过滤后:" + filtered);
    }
}

字符串分割:

public class StringMethods7 {
    public static void main(String[] args) {
        // split():按指定分隔符分割字符串
        String str1 = "apple,banana,orange";
        String[] fruits = str1.split(",");
        System.out.println("水果列表:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        
        // 分割多个空格
        String str2 = "Hello    Java    World";
        String[] words = str2.split("\\s+");  // \s+表示一个或多个空格
        System.out.println("\n单词列表:");
        for (String word : words) {
            System.out.println(word);
        }
        
        // 限制分割次数
        String str3 = "a,b,c,d,e";
        String[] parts = str3.split(",", 3);  // 最多分割成3部分
        System.out.println("\n限制分割次数:");
        for (String part : parts) {
            System.out.println(part);
        }
        // 输出:a, b, c,d,e
        
        // 实际应用:解析CSV数据
        String csv = "张三,25,北京";
        String[] data = csv.split(",");
        System.out.println("\n姓名:" + data[0]);
        System.out.println("年龄:" + data[1]);
        System.out.println("城市:" + data[2]);
    }
}

字符串拼接:

public class StringMethods8 {
    public static void main(String[] args) {
        // 方式1:使用+运算符
        String str1 = "Hello";
        String str2 = "Java";
        String result1 = str1 + ", " + str2 + "!";
        System.out.println(result1);  // Hello, Java!
        
        // 方式2:使用concat()
        String result2 = str1.concat(", ").concat(str2).concat("!");
        System.out.println(result2);  // Hello, Java!
        
        // 方式3:使用String.join()
        String result3 = String.join(", ", "apple", "banana", "orange");
        System.out.println(result3);  // apple, banana, orange
        
        // 方式4:使用StringBuilder(推荐,性能最好)
        StringBuilder sb = new StringBuilder();
        sb.append("Hello");
        sb.append(", ");
        sb.append("Java");
        sb.append("!");
        String result4 = sb.toString();
        System.out.println(result4);  // Hello, Java!
        
        // 性能对比:循环拼接字符串
        long start1 = System.currentTimeMillis();
        String s1 = "";
        for (int i = 0; i < 10000; i++) {
            s1 += i;  // 不推荐!每次都创建新对象
        }
        long end1 = System.currentTimeMillis();
        System.out.println("使用+拼接耗时:" + (end1 - start1) + "ms");
        
        long start2 = System.currentTimeMillis();
        StringBuilder s2 = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            s2.append(i);  // 推荐!不创建新对象
        }
        String result5 = s2.toString();
        long end2 = System.currentTimeMillis();
        System.out.println("使用StringBuilder耗时:" + (end2 - start2) + "ms");
    }
}

字符串大小写转换和去空格:

public class StringMethods9 {
    public static void main(String[] args) {
        String str = "  Hello, Java!  ";
        
        // 转大写
        String upper = str.toUpperCase();
        System.out.println("转大写:[" + upper + "]");
        
        // 转小写
        String lower = str.toLowerCase();
        System.out.println("转小写:[" + lower + "]");
        
        // 去除首尾空格
        String trimmed = str.trim();
        System.out.println("去除空格:[" + trimmed + "]");
        
        // 去除所有空格
        String noSpace = str.replace(" ", "");
        System.out.println("去除所有空格:[" + noSpace + "]");
        
        // 实际应用:用户输入处理
        String username = "  Admin  ";
        username = username.trim().toLowerCase();
        System.out.println("处理后的用户名:[" + username + "]");
    }
}

7.4 StringBuilder和StringBuffer

为什么需要StringBuilder?

public class StringBuilderDemo1 {
    public static void main(String[] args) {
        // String是不可变的,每次修改都会创建新对象
        String str = "Hello";
        str = str + " Java";  // 创建了新对象
        str = str + "!";      // 又创建了新对象
        
        // StringBuilder是可变的,不会创建新对象
        StringBuilder sb = new StringBuilder("Hello");
        sb.append(" Java");   // 在原对象上修改
        sb.append("!");       // 在原对象上修改
        String result = sb.toString();
        
        System.out.println(result);  // Hello Java!
    }
}

StringBuilder常用方法:

public class StringBuilderDemo2 {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        
        // append():追加内容
        sb.append("Hello");
        sb.append(" ");
        sb.append("Java");
        System.out.println(sb);  // Hello Java
        
        // insert():插入内容
        sb.insert(5, ",");
        System.out.println(sb);  // Hello, Java
        
        // delete():删除内容
        sb.delete(5, 6);  // 删除逗号
        System.out.println(sb);  // Hello Java
        
        // replace():替换内容
        sb.replace(6, 10, "World");
        System.out.println(sb);  // Hello World
        
        // reverse():反转字符串
        sb.reverse();
        System.out.println(sb);  // dlroW olleH
        
        // 链式调用
        StringBuilder sb2 = new StringBuilder();
        String result = sb2.append("Hello")
                          .append(" ")
                          .append("Java")
                          .append("!")
                          .toString();
        System.out.println(result);  // Hello Java!
    }
}

StringBuilder vs StringBuffer:

特性 StringBuilder StringBuffer
线程安全
性能
使用场景 单线程 多线程
public class StringBuilderVsStringBuffer {
    public static void main(String[] args) {
        // StringBuilder:线程不安全,性能更好
        StringBuilder sb = new StringBuilder();
        sb.append("Hello");
        
        // StringBuffer:线程安全,性能稍差
        StringBuffer sbf = new StringBuffer();
        sbf.append("Hello");
        
        // 推荐:在单线程环境使用StringBuilder
        // 只有在多线程环境才使用StringBuffer
    }
}

7.5 字符串实战案例

案例1:统计字符串中各类字符的个数

public class StringCase1 {
    public static void main(String[] args) {
        String str = "Hello123Java456!@#";
        
        int letters = 0;  // 字母
        int digits = 0;   // 数字
        int others = 0;   // 其他字符
        
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if (Character.isLetter(ch)) {
                letters++;
            } else if (Character.isDigit(ch)) {
                digits++;
            } else {
                others++;
            }
        }
        
        System.out.println("字母个数:" + letters);
        System.out.println("数字个数:" + digits);
        System.out.println("其他字符个数:" + others);
    }
}

案例2:判断回文字符串

public class StringCase2 {
    public static void main(String[] args) {
        String str1 = "level";
        String str2 = "hello";
        
        System.out.println(str1 + "是回文:" + isPalindrome(str1));
        System.out.println(str2 + "是回文:" + isPalindrome(str2));
    }
    
    /**
     * 判断是否为回文字符串
     * 回文:正着读和反着读一样
     */
    public static boolean isPalindrome(String str) {
        int left = 0;
        int right = str.length() - 1;
        
        while (left < right) {
            if (str.charAt(left) != str.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        
        return true;
    }
}

案例3:字符串压缩

public class StringCase3 {
    public static void main(String[] args) {
        String str = "aaabbccccaa";
        String compressed = compress(str);
        System.out.println("原字符串:" + str);
        System.out.println("压缩后:" + compressed);  // a3b2c4a2
    }
    
    /**
     * 字符串压缩
     * 例如:aaabbccccaa -> a3b2c4a2
     */
    public static String compress(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        
        StringBuilder sb = new StringBuilder();
        int count = 1;
        
        for (int i = 1; i < str.length(); i++) {
            if (str.charAt(i) == str.charAt(i - 1)) {
                count++;
            } else {
                sb.append(str.charAt(i - 1));
                sb.append(count);
                count = 1;
            }
        }
        
        // 处理最后一组字符
        sb.append(str.charAt(str.length() - 1));
        sb.append(count);
        
        return sb.toString();
    }
}

案例4:单词首字母大写

public class StringCase4 {
    public static void main(String[] args) {
        String str = "hello java world";
        String result = capitalizeWords(str);
        System.out.println("原字符串:" + str);
        System.out.println("转换后:" + result);  // Hello Java World
    }
    
    /**
     * 将每个单词的首字母大写
     */
    public static String capitalizeWords(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        
        String[] words = str.split(" ");
        StringBuilder sb = new StringBuilder();
        
        for (int i = 0; i < words.length; i++) {
            if (words[i].length() > 0) {
                // 首字母大写 + 其余字母小写
                String capitalized = words[i].substring(0, 1).toUpperCase() 
                                   + words[i].substring(1).toLowerCase();
                sb.append(capitalized);
                
                if (i < words.length - 1) {
                    sb.append(" ");
                }
            }
        }
        
        return sb.toString();
    }
}

案例5:验证邮箱格式

public class StringCase5 {
    public static void main(String[] args) {
        String email1 = "user@example.com";
        String email2 = "invalid-email";
        
        System.out.println(email1 + "是否有效:" + isValidEmail(email1));
        System.out.println(email2 + "是否有效:" + isValidEmail(email2));
    }
    
    /**
     * 简单的邮箱格式验证
     */
    public static boolean isValidEmail(String email) {
        if (email == null || email.isEmpty()) {
            return false;
        }
        
        // 必须包含@符号
        if (!email.contains("@")) {
            return false;
        }
        
        // @符号不能在开头或结尾
        int atIndex = email.indexOf("@");
        if (atIndex == 0 || atIndex == email.length() - 1) {
            return false;
        }
        
        // @符号后必须有.
        int dotIndex = email.lastIndexOf(".");
        if (dotIndex <= atIndex || dotIndex == email.length() - 1) {
            return false;
        }
        
        return true;
    }
}
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐