01-Java开发环境与基础语法
01-Java开发环境与基础语法
学习目标
- 掌握JDK的安装与环境变量配置
- 熟练使用IDEA开发工具进行Java开发
- 理解Java程序的基本结构和执行流程
- 掌握Java基础语法(变量、数据类型、运算符)
- 熟练使用控制流程语句(if、switch、for、while)
- 掌握数组和字符串的基本操作
- 能够编写简单的Java控制台程序
知识结构思维导图
一、为什么需要学习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这么流行?
-
跨平台性
- 一次编写,到处运行(Write Once, Run Anywhere)
- 通过JVM实现跨平台
- 支持Windows、Linux、Mac等操作系统
-
面向对象
- 更符合人类思维方式
- 代码复用性强
- 易于维护和扩展
-
丰富的生态
- 海量的开源框架和库
- Spring、MyBatis、Netty等优秀框架
- 活跃的社区支持
-
企业级应用
- 稳定可靠
- 性能优秀
- 安全性高
-
就业机会多
- 市场需求大
- 薪资待遇好
- 职业发展空间大
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官网下载
- 访问:https://www.oracle.com/java/technologies/downloads/
- 选择Java 8版本
- 下载Windows x64版本的安装包(jdk-8uXXX-windows-x64.exe)
方式2:使用OpenJDK
- 访问:https://adoptium.net/
- 选择JDK 8
- 下载Windows x64版本
2.3.2 安装JDK
-
双击安装包
- 运行下载的.exe文件
- 点击"下一步"
-
选择安装路径
建议路径:D:\Java\jdk1.8.0_XXX 不建议:C:\Program Files\Java\...(路径有空格) -
完成安装
- 记住安装路径,后面配置环境变量需要用到
- 点击"完成"
2.3.3 配置环境变量
为什么要配置环境变量?
- 让系统能在任何位置找到java和javac命令
- 方便在命令行中使用Java工具
配置步骤:
-
打开环境变量设置
右键"此电脑" → 属性 → 高级系统设置 → 环境变量 -
新建JAVA_HOME变量
- 点击"系统变量"下的"新建"
- 变量名:
JAVA_HOME - 变量值:
D:\Java\jdk1.8.0_XXX(你的JDK安装路径) - 点击"确定"
-
配置Path变量
- 在"系统变量"中找到
Path变量 - 点击"编辑"
- 点击"新建"
- 添加:
%JAVA_HOME%\bin - 点击"确定"
- 在"系统变量"中找到
-
新建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的优势:
- 智能的代码提示和补全
- 强大的重构功能
- 内置的版本控制集成
- 丰富的插件生态
- 优秀的调试功能
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安装步骤
-
运行安装程序
- 双击下载的.exe文件
- 点击"Next"
-
选择安装路径
建议路径:D:\Program Files\JetBrains\IntelliJ IDEA -
选择安装选项
- ✓ Create Desktop Shortcut(创建桌面快捷方式)
- ✓ Update PATH variable(添加到环境变量)
- ✓ Update context menu(添加右键菜单)
- ✓ Create Associations(关联.java文件)
-
完成安装
- 点击"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 创建项目
-
启动IDEA
- 点击"New Project"
-
配置项目
Name: HelloJava Location: D:\JavaProjects\HelloJava Language: Java Build system: IntelliJ JDK: 1.8 -
创建项目结构
HelloJava/ ├── .idea/ # IDEA配置文件 ├── src/ # 源代码目录 └── HelloJava.iml # 项目配置文件
3.5.2 创建Java类
-
右键src目录
- New → Java Class
-
输入类名
- Name: HelloWorld
- 点击OK
-
生成的文件
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程序执行流程
详细流程:
-
编写源代码
- 文件名:HelloWorld.java
- 内容:Java源代码
-
编译源代码
javac HelloWorld.java- 编译器检查语法错误
- 生成字节码文件:HelloWorld.class
-
运行程序
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 标识符和关键字
标识符命名规则:
- 只能包含字母、数字、下划线(_)和美元符号($)
- 不能以数字开头
- 不能使用Java关键字
- 区分大小写
// ✓ 合法的标识符
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 (表达式) {
case 值1:
// 代码块1
break;
case 值2:
// 代码块2
break;
case 值3:
// 代码块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 (初始化; 条件判断; 更新) {
// 循环体
}
执行流程:
代码示例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 (条件) {
// 循环体
}
执行流程:
代码示例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:先执行循环体,再判断条件(至少执行一次)
代码示例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的特点:
- String是引用类型,不是基本类型
- String对象是不可变的(immutable)
- 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;
}
}
更多推荐




所有评论(0)