Java学习笔记
约 40374 字大约 135 分钟
2025-01-20
Java安装和配置环境变量,请参考以下博客:
https://blog.csdn.net/l1447320229/article/details/111938255
Java IDEA的安装和使用请参考以下博客:
https://blog.csdn.net/syc000666/article/details/125904935
或
https://blog.csdn.net/QWERTYwqj/article/details/140858569
1- 注释和关键字
1.1 Java的注释
注释是程序员用来解释代码或增加说明的文字,编译器会忽略这些注释。Java支持三种类型的注释:
单行注释:
- 语法:使用
//
,后面的所有内容都被视为注释。 - 示例:
// 这是一个单行注释 int a = 5; // 这是变量a
- 语法:使用
多行注释:
- 语法:使用
/*
开始,*/
结束。可以跨越多行。 - 示例:
/* * 这是一个多行注释 * 可以包含多行文字 */ int b = 10;
- 语法:使用
文档注释:
- 语法:使用
/**
开始,*/
结束。通常用于生成文档。 - 示例:
/** * 这是一个文档注释 * @param x 输入值 * @return 返回值 */ public int square(int x) { return x * x; }
- 语法:使用
1.2 Java的关键字
Java中的关键字是具有特定意义的保留字,不能用作变量名、方法名或类名。Java有50个关键字,以下是一些主要的关键字分类和示例:
数据类型关键字:
int
,float
,double
,char
,boolean
等。- 示例:
int age = 30; double price = 19.99;
控制流关键字:
if
,else
,switch
,case
,default
,for
,while
,do
,break
,continue
等。- 示例:
if (age > 18) { System.out.println("成年人"); }
访问控制关键字:
public
,private
,protected
。- 示例:
public class MyClass { private int value; }
异常处理关键字:
try
,catch
,finally
,throw
,throws
,assert
。- 示例:
try { int result = 10 / 0; } catch (ArithmeticException e) { System.out.println("除以零错误"); }
类和对象相关关键字:
class
,interface
,extends
,implements
,new
,this
,super
。- 示例:
class Animal { void sound() { System.out.println("动物声音"); } }
其他关键字:
static
,final
,volatile
,synchronized
,native
,transient
,strictfp
等。- 示例:
static int count = 0; // 静态变量 final int MAX = 100; // 常量
2- 字面量
2.1 字面量概述(掌握)
字面量是程序中直接表示固定值的符号。Java中的字面量可以用来表示基本数据类型的值,如整型、浮点型、字符型和布尔型等。字面量的特点是它们在代码中是不可变的。
2.2 整数字面量(掌握)
整数字面量用于表示整数值,Java支持多种进制:
2.2.1 十进制
- 表示方式:直接书写数字。
- 示例:
int decimal = 100; // 十进制
2.2.2 八进制
- 表示方式:以
0
开头,后面跟着0-7的数字。 - 示例:
int octal = 0123; // 等于83
2.2.3 十六进制
- 表示方式:以
0x
或0X
开头,后面跟着0-9和A-F(或a-f)表示的数字。 - 示例:
int hex = 0x1A; // 等于26
2.2.4 长整型
- 表示方式:在数字后加
L
或l
。 - 示例:
long bigNumber = 12345678901L;
2.3 浮点数字面量(掌握)
浮点数字面量用于表示带小数的数值,分为float
和double
两种类型。
2.3.1 float
类型
- 表示方式:在数字后加
f
或F
。 - 示例:
float pi = 3.14f; // 使用f后缀
2.3.2 double
类型
- 表示方式:可以直接书写数字,不需要后缀。
- 示例:
double exp = 2.5e3; // 科学计数法,表示2500.0
2.4 字符字面量(掌握)
字符字面量用于表示单个字符,用单引号包围。
2.4.1 单个字符
- 表示方式:如
'A'
、'b'
等。 - 示例:
char letter = 'A'; // 单个字符
2.4.2 转义字符
- 表示方式:用反斜杠
\
来表示特殊字符,如换行符、制表符等。 - 示例:
char newline = '\n'; // 换行符 char tab = '\t'; // 制表符
2.5 字符串字面量(掌握)
字符串字面量用于表示字符序列,用双引号包围。
表示方式:如
"Hello, World!"
。示例:
String greeting = "Hello, World!";
特点:字符串是不可变的,即一旦创建,字符串的内容不能被改变。
2.6 布尔字面量(掌握)
布尔字面量用于表示真或假的值,只有两个可能的值:true
和false
。
- 示例:
boolean isActive = true;
2.7 空字面量(掌握)
空字面量用于表示一个没有指向任何对象的引用。使用null
来表示。
- 示例:
String name = null; // 表示name不指向任何对象
2.8 字面量的使用注意事项(了解)
- 类型匹配:字面量的类型必须与变量的类型相匹配,否则会导致编译错误。
- 类型转换:对于某些字面量,可能需要显式转换,例如将
int
转换为float
。 - 性能考虑:在性能敏感的情况下,字符串字面量的创建和使用要谨慎,避免不必要的内存消耗。
3-变量基本用法和使用方式
1. 变量概述
变量是用于存储数据的命名内存位置。每个变量都有一个类型,决定了它可以存储什么样的数据。
2. 变量的声明
2.1 声明语法
基本格式:
数据类型 变量名;
示例:
int age; // 声明一个整型变量age String name; // 声明一个字符串变量name
3. 变量的赋值
赋值是将数据存储到变量中的过程。赋值使用等号=
。
3.1 赋值语法
基本格式:
变量名 = 值;
示例:
age = 25; // 将25赋值给age name = "Alice"; // 将"Alice"赋值给name
3.2 声明与赋值结合
可以在声明变量的同时进行赋值。
- 示例:
int age = 25; // 声明并初始化age String name = "Alice"; // 声明并初始化name
4. 变量的类型
Java有两种主要类型的变量:基本数据类型和引用数据类型。
4.1 基本数据类型
Java提供八种基本数据类型:
整型:
int
: 32位整数- 示例:
int count = 10; // 整数
浮点型:
float
: 单精度浮点数(后缀f
)double
: 双精度浮点数- 示例:
float price = 19.99f; // 单精度浮点数 double weight = 65.5; // 双精度浮点数
字符型:
char
: 单个字符(用单引号包围)- 示例:
char initial = 'A'; // 字符
布尔型:
boolean
: 只有true
和false
- 示例:
boolean isAvailable = true; // 布尔值
4.2 引用数据类型
引用数据类型用于指向对象,常见的如字符串、数组等。
- 示例:
String message = "Hello, World!"; // 字符串是一个引用类型
5. 变量的作用域
变量的作用域决定了它的可见性和生存周期。
5.1 局部变量
局部变量是在方法或代码块内声明的,只能在该方法或代码块中使用。
- 示例:
void myMethod() { int localVar = 5; // 局部变量 System.out.println(localVar); // 只能在此方法内使用 }
6. 变量的命名规则
在Java中,变量命名遵循以下规则:
- 有效字符:可以包含字母、数字、下划线
_
和美元符号$
,但不能以数字开头。 - 大小写敏感:变量名区分大小写,如
age
和Age
是不同的变量。 - 命名约定:
- 使用有意义的名字,描述变量的用途。
- 变量名通常使用小写字母开头,多个单词之间用驼峰命名法(如
firstName
)。
7. 变量的使用示例
以下是一个简单的Java程序,展示如何声明、赋值和使用变量:
public class Main {
public static void main(String[] args) {
// 声明和初始化变量
int age = 30; // 整型变量
String name = "Alice"; // 字符串变量
// 使用变量
System.out.println("Name: " + name); // 输出姓名
System.out.println("Age: " + age); // 输出年龄
}
}
4- 变量相关的练习
1. 整型变量
题目:声明一个整型变量number1
,赋值为100,并输出它的值。
public class Main {
public static void main(String[] args) {
int number1 = 100;
System.out.println("Number1: " + number1);
}
}
2. 浮点型变量
题目:声明一个浮点型变量price
,赋值为19.99,并输出它的值。
public class Main {
public static void main(String[] args) {
float price = 19.99f;
System.out.println("Price: " + price);
}
}
3. 字符型变量
题目:声明一个字符型变量grade
,赋值为'A'
,并输出它的值。
public class Main {
public static void main(String[] args) {
char grade = 'A';
System.out.println("Grade: " + grade);
}
}
4. 布尔型变量
题目:声明一个布尔型变量isAvailable
,赋值为true
,并输出它的值。
public class Main {
public static void main(String[] args) {
boolean isAvailable = true;
System.out.println("Is Available: " + isAvailable);
}
}
5. 字符串变量
题目:声明一个字符串变量city
,赋值为"Beijing"
,并输出它的值。
public class Main {
public static void main(String[] args) {
String city = "Beijing";
System.out.println("City: " + city);
}
}
6. 整型变量
题目:声明一个整型变量year
,赋值为2023,并输出它的值。
public class Main {
public static void main(String[] args) {
int year = 2023;
System.out.println("Year: " + year);
}
}
7. 浮点型变量
题目:声明一个浮点型变量height
,赋值为5.9,并输出它的值。
public class Main {
public static void main(String[] args) {
float height = 5.9f;
System.out.println("Height: " + height);
}
}
8. 整型变量
题目:声明一个整型变量score
,赋值为85,并输出它的值。
public class Main {
public static void main(String[] args) {
int score = 85;
System.out.println("Score: " + score);
}
}
9. 字符型变量
题目:声明一个字符型变量initial
,赋值为'B'
,并输出它的值。
public class Main {
public static void main(String[] args) {
char initial = 'B';
System.out.println("Initial: " + initial);
}
}
10. 布尔型变量
题目:声明一个布尔型变量isStudent
,赋值为false
,并输出它的值。
public class Main {
public static void main(String[] args) {
boolean isStudent = false;
System.out.println("Is Student: " + isStudent);
}
}
11. 字符串变量
题目:声明一个字符串变量country
,赋值为"China"
,并输出它的值。
public class Main {
public static void main(String[] args) {
String country = "China";
System.out.println("Country: " + country);
}
}
12. 整型变量
题目:声明一个整型变量temperature
,赋值为25,并输出它的值。
public class Main {
public static void main(String[] args) {
int temperature = 25;
System.out.println("Temperature: " + temperature);
}
}
13. 浮点型变量
题目:声明一个浮点型变量weight
,赋值为70.5,并输出它的值。
public class Main {
public static void main(String[] args) {
float weight = 70.5f;
System.out.println("Weight: " + weight);
}
}
14. 整型变量
题目:声明一个整型变量count
,赋值为15,并输出它的值。
public class Main {
public static void main(String[] args) {
int count = 15;
System.out.println("Count: " + count);
}
}
15. 字符型变量
题目:声明一个字符型变量symbol
,赋值为'@'
,并输出它的值。
public class Main {
public static void main(String[] args) {
char symbol = '@';
System.out.println("Symbol: " + symbol);
}
}
16. 布尔型变量
题目:声明一个布尔型变量hasPet
,赋值为true
,并输出它的值。
public class Main {
public static void main(String[] args) {
boolean hasPet = true;
System.out.println("Has Pet: " + hasPet);
}
}
17. 字符串变量
题目:声明一个字符串变量hobby
,赋值为"Reading"
,并输出它的值。
public class Main {
public static void main(String[] args) {
String hobby = "Reading";
System.out.println("Hobby: " + hobby);
}
}
18. 整型变量
题目:声明一个整型变量balance
,赋值为500,并输出它的值。
public class Main {
public static void main(String[] args) {
int balance = 500;
System.out.println("Balance: " + balance);
}
}
19. 浮点型变量
题目:声明一个浮点型变量distance
,赋值为150.5,并输出它的值。
public class Main {
public static void main(String[] args) {
float distance = 150.5f;
System.out.println("Distance: " + distance);
}
}
20. 整型变量
题目:声明一个整型变量age
,赋值为25,并输出它的值。
public class Main {
public static void main(String[] args) {
int age = 25;
System.out.println("Age: " + age);
}
}
5- 进制相关
好的,下面是关于二进制、十进制和十六进制的详细讲解,包括它们的定义、特点,以及它们之间的转换方法。
1. 进制概述
1.1. 二进制(Binary)
- 定义:二进制是以2为基数的数制,仅使用两个数字:0和1。
- 特点:
- 每一位(bit)只能是0或1。
- 计算机内部使用二进制进行数据处理和存储。
示例:二进制数1011
表示的十进制数计算如下:
- 从右到左,权值分别是:2^0, 2^1, 2^2, 2^3
1011
= 1×2^3 + 0×2^2 + 1×2^1 + 1×2^0 = 8 + 0 + 2 + 1 = 11
1.2. 十进制(Decimal)
- 定义:十进制是以10为基数的数制,使用数字0到9。
- 特点:
- 我们日常生活中使用的数字系统。
- 每一位的权值是10的幂。
示例:十进制数345
的计算如下:
- 权值分别是:10^0, 10^1, 10^2
345
= 3×10^2 + 4×10^1 + 5×10^0 = 300 + 40 + 5 = 345
1.3. 十六进制(Hexadecimal)
- 定义:十六进制是以16为基数的数制,使用数字0到9和字母A到F(其中A=10, B=11, C=12, D=13, E=14, F=15)。
- 特点:
- 便于表示较大的二进制数,因为每个十六进制数位可以表示4个二进制位(bit)。
- 常用于计算机编程和数字电路设计。
示例:十六进制数2F
的计算如下:
- 权值分别是:16^0, 16^1
2F
= 2×16^1 + 15×16^0 = 32 + 15 = 47(十进制)
2. 进制之间的转换
2.1. 二进制与十进制的转换
二进制转十进制:
- 从右到左写出二进制数的位数及其对应的2的幂。
- 计算所有位上数字与其权值的乘积之和。
示例:将
1101
转换为十进制:- 1×2^3 + 1×2^2 + 0×2^1 + 1×2^0 = 8 + 4 + 0 + 1 = 13
十进制转二进制:
- 不断将十进制数除以2,记录余数。
- 直到商为0,将余数逆序排列。
示例:将
13
转换为二进制:- 13 ÷ 2 = 6,余数1
- 6 ÷ 2 = 3,余数0
- 3 ÷ 2 = 1,余数1
- 1 ÷ 2 = 0,余数1
- 逆序排列余数,得到
1101
2.2. 二进制与十六进制的转换
二进制转十六进制:
- 从右到左每四位一组,不足四位时左边补零。
- 将每组二进制数转换为相应的十六进制数。
示例:将
11011011
转换为十六进制:- 分组:
1101 1011
- 转换:
D B
- 结果为
DB
十六进制转二进制:
- 将每个十六进制数字转换为四位二进制数。
示例:将
2F
转换为二进制:2
->0010
F
->1111
- 结果为
00101111
2.3. 十进制与十六进制的转换
十进制转十六进制:
- 不断将十进制数除以16,记录余数。
- 直到商为0,将余数逆序排列。
示例:将
47
转换为十六进制:- 47 ÷ 16 = 2,余数15 (F)
- 2 ÷ 16 = 0,余数2
- 结果为
2F
十六进制转十进制:
- 将每个十六进制数字乘以16的幂。
示例:将
2F
转换为十进制:- 2×16^1 + 15×16^0 = 32 + 15 = 47
6- Java数据类型
1. 数据类型概述(掌握)
在Java中,数据类型主要分为两大类:
- 基本数据类型(Primitive Data Types)
- 引用数据类型(Reference Data Types)
2. 基本数据类型(掌握)
Java提供了8种基本数据类型,主要用于存储简单的值。
2.1. 整型数据类型(掌握)
byte(了解)
- 大小:1字节(8位)
- 取值范围:-128到127
- 示例:
byte b = 100;
short(了解)
- 大小:2字节(16位)
- 取值范围:-32,768到32,767
- 示例:
short s = 10000;
int(掌握)
- 大小:4字节(32位)
- 取值范围:-2,147,483,648到2,147,483,647
- 示例:
int i = 100000;
long(了解)
- 大小:8字节(64位)
- 取值范围:-9,223,372,036,854,775,808到9,223,372,036,854,775,807
- 示例:
long l = 100000L; // L表示长整型
2.2. 浮点型数据类型(掌握)
float(了解)
- 大小:4字节(32位)
- 取值范围:大约±3.40282347E+38(有效位数:6-7位十进制数)
- 示例:
float f = 3.14f; // f表示浮点型
double(掌握)
- 大小:8字节(64位)
- 取值范围:大约±1.79769313486231570E+308(有效位数:15位十进制数)
- 示例:
double d = 3.141592653589793;
2.3. 字符型数据类型(掌握)
- char(掌握)
- 大小:2字节(16位)
- 取值范围:0到65,535(Unicode字符)
- 示例:
char c = 'A';
2.4. 布尔型数据类型(掌握)
- boolean(掌握)
- 大小:不固定(但通常为1字节)
- 取值范围:
true
或false
- 示例:
boolean isTrue = true;
3. 引用数据类型(掌握)
引用数据类型用于存储对象的引用,包括类、接口、数组等。
3.1. 类类型(掌握)
- 示例:
String str = "Hello, World!";
3.2. 数组类型(掌握)
- 示例:
int[] numbers = {1, 2, 3, 4, 5};
3.3. 接口类型(了解)
- 示例:
List<String> list = new ArrayList<>();
4. 数据类型的特点(了解)
基本数据类型:
- 存储简单的数据值。
- 直接在栈内存中分配空间。
- 具有固定的大小和范围。
引用数据类型:
- 存储对象的引用,实际数据存储在堆内存中。
- 可以使用
null
表示没有引用任何对象。 - 不同的对象可以有不同的大小。
5. 自动装箱与拆箱(了解)
Java提供了自动装箱(autoboxing)和拆箱(unboxing)功能,允许基本数据类型与对应的包装类之间的自动转换。
- 示例:
Integer obj = 10; // 自动装箱,将int转为Integer int num = obj; // 拆箱,将Integer转为int
7- 标识符
1. 标识符概述(掌握)
标识符是Java程序中用于标识变量、方法、类、接口等元素的名称。它们是代码的基本组成部分,理解标识符的使用和命名规则对编写清晰的代码至关重要。
2. 标识符的规则(掌握)
2.1. 允许的字符
- 字母:可以使用大写字母(A-Z)和小写字母(a-z)。
- 数字:可以包含数字(0-9),但不能以数字开头。
- 特殊符号:可以使用下划线(_)和美元符号($),但不推荐在标识符中使用它们作为开头。
2.2. 位置限制
- 开头字符:标识符必须以字母、下划线或美元符号开头,不能以数字开头。
- 后续字符:后续字符可以是字母、数字、下划线或美元符号。
2.3. 长度限制
- 长度:Java标识符的长度没有固定限制,但过长的标识符会影响可读性。通常,保持在合理长度内即可。
2.4. 大小写敏感
- Java是区分大小写的语言。例如,
myVar
和MyVar
是两个不同的标识符。开发者需要注意大小写的使用,以避免混淆。
2.5. 关键字限制
- 关键字:标识符不能与Java的关键字相同,例如
int
、class
、public
等。使用关键字作为标识符会导致编译错误。
3. 标识符的命名规则(掌握)
3.1. 描述性名称
- 有意义的名称:标识符应尽量具有描述性,以便于其他开发者理解代码的功能。例如,使用
totalAmount
而不是ta
。
3.2. 命名约定
类名:使用帕斯卡命名法(PascalCase),每个单词的首字母大写。例如:
Student
,EmployeeDetails
。方法名和变量名:使用驼峰命名法(camelCase),第一个单词的小写,其余单词首字母大写。例如:
calculateTotal
,firstName
。常量名:使用全大写字母,并用下划线分隔单词。例如:
MAX_SIZE
,PI_VALUE
。常量在代码中通常是不可变的。
4. 标识符示例(了解)
4.1. 合法标识符
int myVariable; // 合法,符合命名规则
String $name; // 合法,使用了美元符号
double _value; // 合法,以下划线开头
int age1; // 合法,以字母开头
4.2. 非法标识符
int 2ndValue; // 非法,不能以数字开头
int my-variable; // 非法,不能包含横杠
int class; // 非法,使用了关键字
5. 标识符的作用(了解)
标识符的作用在于:
- 区分程序元素:标识符用于区分不同的变量、方法和类,使代码更易于理解。
- 提高可读性:合理的命名可以使代码更易于维护和阅读,其他开发者能迅速理解变量和方法的用途。
- 避免命名冲突:通过使用不同的标识符,避免在同一作用域内出现命名冲突,减少潜在的错误。
6. 注意事项(了解)
- 尽量避免使用简写:除非非常常见,否则应避免使用简写形式,以提高代码的可读性。
- 遵循团队约定:如果在团队中工作,遵循团队的命名约定和规范,以确保代码的一致性。
- 避免使用保留字:在写标识符时,确保不使用保留的关键字。
8- 键盘录入
1. 键盘录入概述(掌握)
键盘录入是指从用户的键盘获取输入数据。在Java中,常用的方式是通过Scanner
类来实现。Scanner
类是Java标准库中用于读取输入的工具,能够处理不同类型的数据。
2. 引入Scanner类(掌握)
在使用Scanner
类之前,需要先导入java.util.Scanner
包。
import java.util.Scanner;
3. 创建Scanner对象(掌握)
创建Scanner
对象的常用方式是通过System.in
,这是Java中标准输入流的代表。通过Scanner
对象,可以读取用户输入的数据。
Scanner scanner = new Scanner(System.in);
4. 读取用户输入(掌握)
Scanner
类提供了多种方法来读取不同类型的输入:
4.1. 读取字符串(了解)
- 使用
nextLine()
方法可以读取一整行的输入,包括空格。
String inputString = scanner.nextLine();
4.2. 读取单词(了解)
- 使用
next()
方法可以读取一个单词(以空格为分隔)。
String inputWord = scanner.next();
4.3. 读取整数(掌握)
- 使用
nextInt()
方法读取整数类型的输入。
int inputInt = scanner.nextInt();
4.4. 读取浮点数(掌握)
- 使用
nextDouble()
方法读取双精度浮点数。
double inputDouble = scanner.nextDouble();
4.5. 读取布尔值(了解)
- 使用
nextBoolean()
方法读取布尔类型的输入(true
或false
)。
boolean inputBoolean = scanner.nextBoolean();
5. 关闭Scanner(掌握)
使用完Scanner
对象后,应该调用close()
方法以释放资源。关闭后,无法再读取输入。
scanner.close();
6. 键盘录入示例(掌握)
下面是一个完整的示例,演示如何使用Scanner
类进行键盘录入。
import java.util.Scanner;
public class KeyboardInputExample {
public static void main(String[] args) {
// 创建Scanner对象
Scanner scanner = new Scanner(System.in);
// 读取字符串
System.out.print("请输入你的名字: ");
String name = scanner.nextLine();
// 读取整数
System.out.print("请输入你的年龄: ");
int age = scanner.nextInt();
// 读取浮点数
System.out.print("请输入你的身高(米): ");
double height = scanner.nextDouble();
// 输出结果
System.out.println("名字: " + name);
System.out.println("年龄: " + age);
System.out.println("身高: " + height);
// 关闭Scanner
scanner.close();
}
}
7. 注意事项(了解)
- 输入类型匹配:确保用户输入的数据类型与读取时的类型匹配,否则会抛出
InputMismatchException
异常。例如,若用户输入字母而读取整数,将导致错误。 - 使用nextLine()后读取其他类型:在读取整型或浮点型数据后,如果接下来需要读取字符串,需在读取后调用
nextLine()
以清除输入缓冲区中的换行符。
9- 键盘输入案例
示例 1:用户信息录入
import java.util.Scanner;
public class UserInfo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 录入用户姓名
System.out.print("请输入你的姓名: ");
String name = scanner.nextLine();
// 录入用户年龄
System.out.print("请输入你的年龄: ");
int age = scanner.nextInt();
// 录入用户身高
System.out.print("请输入你的身高(米): ");
double height = scanner.nextDouble();
// 输出用户信息
System.out.println("用户信息:");
System.out.println("姓名: " + name);
System.out.println("年龄: " + age);
System.out.println("身高: " + height);
scanner.close();
}
}
示例 2:BMI计算
import java.util.Scanner;
public class BMICalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 录入用户体重
System.out.print("请输入你的体重(千克): ");
double weight = scanner.nextDouble();
// 录入用户身高
System.out.print("请输入你的身高(米): ");
double height = scanner.nextDouble();
// 计算BMI
double bmi = weight / (height * height);
// 输出BMI结果
System.out.printf("你的BMI为: %.2f\n", bmi);
// 判断BMI分类
if (bmi < 18.5) {
System.out.println("你属于体重过轻。");
} else if (bmi < 24.9) {
System.out.println("你属于正常体重。");
} else if (bmi < 29.9) {
System.out.println("你属于超重。");
} else {
System.out.println("你属于肥胖。");
}
scanner.close();
}
}
示例 3:简单计算器
import java.util.Scanner;
public class SimpleCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 录入第一个数字
System.out.print("请输入第一个数字: ");
double num1 = scanner.nextDouble();
// 录入操作符
System.out.print("请输入操作符 (+, -, *, /): ");
char operator = scanner.next().charAt(0);
// 录入第二个数字
System.out.print("请输入第二个数字: ");
double num2 = scanner.nextDouble();
// 计算结果
double result = 0;
if (operator == '+') {
result = num1 + num2;
} else if (operator == '-') {
result = num1 - num2;
} else if (operator == '*') {
result = num1 * num2;
} else if (operator == '/') {
if (num2 != 0) {
result = num1 / num2;
} else {
System.out.println("错误: 除数不能为零。");
scanner.close();
return;
}
} else {
System.out.println("错误: 不支持的操作符。");
scanner.close();
return;
}
// 输出结果
System.out.printf("结果: %.2f\n", result);
scanner.close();
}
}
示例 4:学生成绩录入与计算平均分
import java.util.Scanner;
public class GradeCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 录入学生1成绩
System.out.print("请输入第一个学生的成绩: ");
double score1 = scanner.nextDouble();
// 录入学生2成绩
System.out.print("请输入第二个学生的成绩: ");
double score2 = scanner.nextDouble();
// 录入学生3成绩
System.out.print("请输入第三个学生的成绩: ");
double score3 = scanner.nextDouble();
// 计算总分与平均分
double totalScore = score1 + score2 + score3;
double averageScore = totalScore / 3;
// 输出平均分
System.out.printf("学生的平均分为: %.2f\n", averageScore);
scanner.close();
}
}
示例 5:电话号码格式化
import java.util.Scanner;
public class PhoneNumberFormatter {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 录入电话号码
System.out.print("请输入你的电话号码(10位数字): ");
String phoneNumber = scanner.nextLine();
// 检查输入格式
if (phoneNumber.length() != 10 || !phoneNumber.matches("\\d+")) {
System.out.println("错误: 电话号码格式不正确,请输入10位数字。");
} else {
// 格式化电话号码
String formattedNumber = String.format("(%s) %s-%s",
phoneNumber.substring(0, 3),
phoneNumber.substring(3, 6),
phoneNumber.substring(6));
// 输出格式化后的电话号码
System.out.println("格式化后的电话号码: " + formattedNumber);
}
scanner.close();
}
}
10- 运算符
1. 算术运算符(掌握)
算术运算符用于进行基本的数学运算。以下是常用的算术运算符及其说明:
运算符 | 描述 | 示例 |
---|---|---|
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取余 | a % b |
代码示例
public class ArithmeticOperators {
public static void main(String[] args) {
int a = 10;
int b = 3;
int sum = a + b; // 加法
int difference = a - b; // 减法
int product = a * b; // 乘法
int quotient = a / b; // 除法
int remainder = a % b; // 取余
System.out.println("加法: " + sum); // 13
System.out.println("减法: " + difference); // 7
System.out.println("乘法: " + product); // 30
System.out.println("除法: " + quotient); // 3
System.out.println("取余: " + remainder); // 1
// 整数除法向下取整示例
System.out.println("整数除法示例 (5 / 2): " + (5 / 2)); // 2
}
}
2. 关系运算符(掌握)
关系运算符用于比较两个值,并返回布尔类型的结果(true
或false
)。以下是常用的关系运算符及其说明:
运算符 | 描述 | 示例 |
---|---|---|
== | 等于 | a == b |
!= | 不等于 | a != b |
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
代码示例
public class RelationalOperators {
public static void main(String[] args) {
int a = 5;
int b = 10;
boolean isEqual = (a == b); // 等于
boolean isNotEqual = (a != b); // 不等于
boolean isGreater = (a > b); // 大于
boolean isLess = (a < b); // 小于
boolean isGreaterOrEqual = (a >= b); // 大于等于
boolean isLessOrEqual = (a <= b); // 小于等于
System.out.println("a == b: " + isEqual); // false
System.out.println("a != b: " + isNotEqual); // true
System.out.println("a > b: " + isGreater); // false
System.out.println("a < b: " + isLess); // true
System.out.println("a >= b: " + isGreaterOrEqual); // false
System.out.println("a <= b: " + isLessOrEqual); // true
}
}
3. 逻辑运算符(掌握)
逻辑运算符用于连接布尔表达式,返回布尔值。以下是常用的逻辑运算符及其说明:
运算符 | 描述 | 示例 |
---|---|---|
&& | 逻辑与 | a && b |
` | ` | |
! | 逻辑非 | !a |
代码示例
public class LogicalOperators {
public static void main(String[] args) {
boolean x = true;
boolean y = false;
boolean andResult = x && y; // 逻辑与
boolean orResult = x || y; // 逻辑或
boolean notX = !x; // 逻辑非
System.out.println("x && y: " + andResult); // false
System.out.println("x || y: " + orResult); // true
System.out.println("!x: " + notX); // false
}
}
4. 位运算符(了解)
位运算符用于对整数的二进制位进行操作。以下是常用的位运算符及其说明:
运算符 | 描述 | 示例 |
---|---|---|
& | 按位与 | a & b |
` | ` | 按位或 |
^ | 按位异或 | a ^ b |
~ | 按位取反 | ~a |
<< | 左移 | a << 2 |
>> | 右移 | a >> 2 |
>>> | 无符号右移 | a >>> 2 |
代码示例
public class BitwiseOperators {
public static void main(String[] args) {
int a = 5; // 二进制 0101
int b = 3; // 二进制 0011
int andResult = a & b; // 按位与
int orResult = a | b; // 按位或
int xorResult = a ^ b; // 按位异或
int notResult = ~a; // 按位取反
int leftShift = a << 1; // 左移
int rightShift = a >> 1; // 右移
System.out.println("a & b: " + andResult); // 1 (0001)
System.out.println("a | b: " + orResult); // 7 (0111)
System.out.println("a ^ b: " + xorResult); // 6 (0110)
System.out.println("~a: " + notResult); // -6 (取反)
System.out.println("a << 1: " + leftShift); // 10 (1010)
System.out.println("a >> 1: " + rightShift); // 2 (0010)
}
}
5. 赋值运算符(掌握)
赋值运算符用于将值赋给变量。以下是常用的赋值运算符及其说明:
运算符 | 描述 | 示例 |
---|---|---|
= | 赋值 | a = 5 |
+= | 加法赋值 | a += 3 |
-= | 减法赋值 | a -= 2 |
*= | 乘法赋值 | a *= 4 |
/= | 除法赋值 | a /= 2 |
%= | 取余赋值 | a %= 3 |
代码示例
public class AssignmentOperators {
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 %= 5; // 等同于 a = a % 5
System.out.println("a %= 5: "
+ a); // 1
}
}
6. 三元运算符(了解)
三元运算符用于根据条件选择值。它是一个简洁的条件语句。
代码示例
public class TernaryOperator {
public static void main(String[] args) {
int a = 5;
int b = 10;
// 找出较大的数
int max = (a > b) ? a : b;
System.out.println("较大的数是: " + max); // 10
}
}
7. instanceof运算符(了解)
instanceof
运算符用于检查对象是否是特定类的实例。
代码示例
public class InstanceofOperator {
public static void main(String[] args) {
String str = "Hello, World!";
if (str instanceof String) {
System.out.println("str是一个String类型的实例");
} else {
System.out.println("str不是String类型的实例");
}
}
}
8. 运算符优先级(了解)
了解运算符优先级有助于避免逻辑错误。
代码示例
public class OperatorPrecedence {
public static void main(String[] args) {
int a = 5;
int b = 10;
int c = 15;
// 计算表达式
int result = a + b * c; // 由于乘法优先级高,先计算 b * c
System.out.println("结果: " + result); // 155
}
}
11- 运算符的相关练习
1. 计算两个整数的和
题目:输入两个整数,计算它们的和。
解题思路:使用加法运算符+
。
代码示例
import java.util.Scanner;
public class Sum {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入第一个整数: ");
int a = scanner.nextInt();
System.out.print("输入第二个整数: ");
int b = scanner.nextInt();
int sum = a + b; // 使用加法运算符
System.out.println("两数之和: " + sum);
}
}
2. 判断两个数的大小
题目:输入两个整数,判断哪个数更大。
解题思路:使用关系运算符>
和<
。
代码示例
import java.util.Scanner;
public class CompareNumbers {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入第一个整数: ");
int a = scanner.nextInt();
System.out.print("输入第二个整数: ");
int b = scanner.nextInt();
if (a > b) {
System.out.println(a + " 是较大的数");
} else if (a < b) {
System.out.println(b + " 是较大的数");
} else {
System.out.println("两数相等");
}
}
}
3. 计算平均值
题目:输入三个数,计算它们的平均值。
解题思路:使用加法运算符+
和除法运算符/
。
代码示例
import java.util.Scanner;
public class Average {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入第一个数: ");
int a = scanner.nextInt();
System.out.print("输入第二个数: ");
int b = scanner.nextInt();
System.out.print("输入第三个数: ");
int c = scanner.nextInt();
double average = (a + b + c) / 3.0; // 计算平均值
System.out.println("平均值: " + average);
}
}
4. 判断奇偶性
题目:输入一个整数,判断它是奇数还是偶数。
解题思路:使用取余运算符%
。
代码示例
import java.util.Scanner;
public class OddEven {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入一个整数: ");
int a = scanner.nextInt();
if (a % 2 == 0) {
System.out.println(a + " 是偶数");
} else {
System.out.println(a + " 是奇数");
}
}
}
5. 计算取余
题目:输入两个整数,计算第一个数除以第二个数的余数。
解题思路:使用取余运算符%
。
代码示例
import java.util.Scanner;
public class Remainder {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入第一个整数: ");
int a = scanner.nextInt();
System.out.print("输入第二个整数: ");
int b = scanner.nextInt();
int remainder = a % b; // 计算余数
System.out.println("余数: " + remainder);
}
}
6. 计算数的绝对值
题目:输入一个整数,计算其绝对值。
解题思路:使用条件语句和关系运算符。
代码示例
import java.util.Scanner;
public class AbsoluteValue {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入一个整数: ");
int a = scanner.nextInt();
int absoluteValue = (a < 0) ? -a : a; // 使用三元运算符
System.out.println("绝对值: " + absoluteValue);
}
}
7. 交换两个数的值
题目:输入两个整数,交换它们的值。
解题思路:使用临时变量。
代码示例
import java.util.Scanner;
public class SwapNumbers {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入第一个整数: ");
int a = scanner.nextInt();
System.out.print("输入第二个整数: ");
int b = scanner.nextInt();
// 交换值
int temp = a;
a = b;
b = temp;
System.out.println("交换后: a = " + a + ", b = " + b);
}
}
8. 计算矩形的面积
题目:输入矩形的长和宽,计算其面积。
解题思路:使用乘法运算符*
。
代码示例
import java.util.Scanner;
public class RectangleArea {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入矩形的长: ");
int length = scanner.nextInt();
System.out.print("输入矩形的宽: ");
int width = scanner.nextInt();
int area = length * width; // 计算面积
System.out.println("矩形的面积: " + area);
}
}
9. 计算两个数的最大值
题目:输入两个整数,计算它们的最大值。
解题思路:使用条件语句和关系运算符。
代码示例
import java.util.Scanner;
public class MaxValue {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入第一个整数: ");
int a = scanner.nextInt();
System.out.print("输入第二个整数: ");
int b = scanner.nextInt();
int max = (a > b) ? a : b; // 使用三元运算符
System.out.println("最大值: " + max);
}
}
10. 计算数的平方
题目:输入一个整数,计算它的平方。
解题思路:使用乘法运算符*
。
代码示例
import java.util.Scanner;
public class Square {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("输入一个整数: ");
int a = scanner.nextInt();
int square = a * a; // 计算平方
System.out.println(a + " 的平方: " + square);
}
}
12- 隐式转换和强制转换
1. 隐式转换(掌握)
定义
隐式转换是指在不需要程序员手动干预的情况下,Java自动将一种数据类型转换为另一种数据类型。通常发生在较小的数据类型转换为较大的数据类型时。
特点
- 安全性:不会导致数据丢失或信息损失。
- 自动化:Java编译器会在需要时自动进行转换。
转换规则
隐式转换遵循以下规则:
- byte → short → int → long → float → double
- char → int
示例
public class ImplicitConversionExample {
public static void main(String[] args) {
byte byteValue = 10; // byte类型
short shortValue = byteValue; // byte自动转换为short
int intValue = shortValue; // short自动转换为int
long longValue = intValue; // int自动转换为long
float floatValue = longValue; // long自动转换为float
double doubleValue = floatValue; // float自动转换为double
System.out.println("Byte value: " + byteValue); // 输出: 10
System.out.println("Short value: " + shortValue); // 输出: 10
System.out.println("Int value: " + intValue); // 输出: 10
System.out.println("Long value: " + longValue); // 输出: 10
System.out.println("Float value: " + floatValue); // 输出: 10.0
System.out.println("Double value: " + doubleValue); // 输出: 10.0
}
}
2. 强制转换(掌握)
定义
强制转换是将一种数据类型显式转换为另一种数据类型。由于可能会导致数据丢失,因此在进行强制转换时,程序员需要使用括号指定目标类型。
特点
- 可能导致数据丢失:例如,将
double
转换为int
时,可能会丢失小数部分。 - 显式声明:程序员需要手动进行转换。
转换规则
强制转换一般用于较高精度数据类型向较低精度数据类型的转换,如:
- double → float → long → int → short → byte
- int → char
示例
public class ExplicitConversionExample {
public static void main(String[] args) {
double doubleValue = 9.78; // 浮点数
int intValue = (int) doubleValue; // 强制转换,浮点数转为整数
System.out.println("Double value: " + doubleValue); // 输出: 9.78
System.out.println("Int value: " + intValue); // 输出: 9
// 另一例:int到byte的强制转换
int largeValue = 130;
byte byteValue = (byte) largeValue; // 强制转换
System.out.println("Original int: " + largeValue); // 输出: 130
System.out.println("Converted byte: " + byteValue); // 输出: -126
}
}
3. 数据丢失示例(了解)
强制转换可能导致数据丢失。下面是一个例子,展示了从double
到int
的转换会丢失小数部分。
public class DataLossExample {
public static void main(String[] args) {
double originalValue = 5.99;
int convertedValue = (int) originalValue; // 小数部分丢失
System.out.println("Original value: " + originalValue); // 输出: 5.99
System.out.println("Converted value: " + convertedValue); // 输出: 5
}
}
4. 具体注意事项(了解)
- 精度丢失:在从
double
到int
的转换中,任何小数部分都会丢失,确保对数据的理解。 - 范围问题:强制转换可能导致数据超出目标类型的范围。例如,将一个超出
byte
范围的int
转换为byte
,可能导致错误的结果。
public class RangeExample {
public static void main(String[] args) {
int value = 300; // 超出byte范围
byte byteValue = (byte) value; // 强制转换
System.out.println("Original int: " + value); // 输出: 300
System.out.println("Converted byte: " + byteValue); // 输出: 44
}
}
13- 字符串和字符串的+操作
1. 字符串概述(掌握)
1.1 定义
字符串是Java中用于表示文本数据的对象。Java中的字符串是不可变的,即一旦创建,字符串的内容就不能被修改。字符串的类型是String
,它位于java.lang
包中。
1.2 特点
- 不可变性:字符串一旦创建,内容不能改变。
- 字符串池:Java使用字符串池来优化存储,相同的字符串会被存储在同一内存地址。
1.3 创建字符串
字符串可以通过以下方式创建:
使用字符串字面量:
String str1 = "Hello, World!";
使用
new
关键字:String str2 = new String("Hello, World!");
2. 字符串的拼接(掌握)
2.1 使用 +
操作符
在Java中,可以使用+
操作符来拼接两个字符串。这种方式简单易用,适合小规模的字符串连接。
2.2 示例
public class StringConcatenation {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "World";
// 使用 + 操作符进行拼接
String result = str1 + ", " + str2 + "!";
System.out.println(result); // 输出: Hello, World!
}
}
2.3 性能注意事项
- 效率问题:每次使用
+
操作符拼接字符串时,都会创建一个新的字符串对象。对于大量拼接操作,性能较差。 - 推荐使用
StringBuilder
:对于多次拼接,推荐使用StringBuilder
,它是可变的,并且性能更好。
3. 使用 StringBuilder
进行字符串拼接(了解)
3.1 定义
StringBuilder
是一个可变的字符序列,可以高效地进行字符串的拼接和修改操作。它位于java.lang
包中。
3.2 创建 StringBuilder
StringBuilder sb = new StringBuilder();
3.3 示例
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// 使用 append 方法进行拼接
sb.append("Hello");
sb.append(", ");
sb.append("World");
sb.append("!");
System.out.println(sb.toString()); // 输出: Hello, World!
}
}
3.4 性能比较
当需要拼接大量字符串时,StringBuilder
的性能优于使用+
操作符:
public class PerformanceTest {
public static void main(String[] args) {
long startTime, endTime;
// 使用 + 进行拼接
startTime = System.currentTimeMillis();
String str = "";
for (int i = 0; i < 10000; i++) {
str += "Hello";
}
endTime = System.currentTimeMillis();
System.out.println("Using + took: " + (endTime - startTime) + " ms");
// 使用 StringBuilder 进行拼接
startTime = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append("Hello");
}
endTime = System.currentTimeMillis();
System.out.println("Using StringBuilder took: " + (endTime - startTime) + " ms");
}
}
14- 自增自减运算符
1. 自增自减运算符(掌握)
自增自减运算符用于对变量进行增加或减少操作,主要有以下两种形式:
- 自增运算符(
++
) - 自减运算符(
--
)
1.1 自增运算符(++)
自增运算符用于将变量的值增加1。可以分为两种使用方式:
- 前缀自增(
++x
):先将变量的值增加1,然后返回增加后的值。 - 后缀自增(
x++
):先返回变量的当前值,然后将变量的值增加1。
示例
public class IncrementExample {
public static void main(String[] args) {
int x = 5;
// 前缀自增
int y = ++x; // x 先加 1,然后 y = 6
System.out.println("前缀自增: x = " + x + ", y = " + y); // 输出: x = 6, y = 6
// 后缀自增
int z = x++; // z = 6,然后 x 加 1
System.out.println("后缀自增: x = " + x + ", z = " + z); // 输出: x = 7, z = 6
}
}
1.2 自减运算符 (--)
自减运算符用于将变量的值减少1,使用方式同样分为前缀和后缀:
- 前缀自减(
--x
):先将变量的值减少1,然后返回减少后的值。 - 后缀自减(
x--
):先返回变量的当前值,然后将变量的值减少1。
示例
public class DecrementExample {
public static void main(String[] args) {
int x = 5;
// 前缀自减
int y = --x; // x 先减 1,然后 y = 4
System.out.println("前缀自减: x = " + x + ", y = " + y); // 输出: x = 4, y = 4
// 后缀自减
int z = x--; // z = 4,然后 x 减 1
System.out.println("后缀自减: x = " + x + ", z = " + z); // 输出: x = 3, z = 4
}
}
2. 注意事项(了解)
运算顺序:自增自减运算符的优先级高于大多数其他运算符。使用时需注意运算顺序,确保程序逻辑的正确性。
与其他操作的结合:自增自减运算符常与其他算术运算符结合使用,确保理解其运算顺序。
示例
public class CombinedExample {
public static void main(String[] args) {
int a = 5;
int b = 10;
// 结合其他运算符
int result = a++ + --b; // a++ 返回 5,然后 a 变为 6;--b 返回 9
System.out.println("结果: " + result); // 输出: 结果: 14
System.out.println("a: " + a + ", b: " + b); // 输出: a: 6, b: 9
}
}
15- 赋值运算符
1. 赋值运算符概述(掌握)
赋值运算符用于将右侧表达式的值赋给左侧变量。在Java中,最常用的赋值运算符是=
。除了基本的赋值运算符外,Java还提供了多种复合赋值运算符,简化了一些常见的操作。
2. 基本赋值运算符(掌握)
2.1 等号 =
=
是最基本的赋值运算符,用于将右侧表达式的值赋给左侧变量。
示例
public class AssignmentExample {
public static void main(String[] args) {
int x = 10; // 将10赋值给x
System.out.println("x = " + x); // 输出: x = 10
}
}
3. 复合赋值运算符(掌握)
复合赋值运算符结合了赋值和其他运算符,可以简化代码。
3.1 加法赋值运算符 +=
将右侧的值加到左侧变量上,并将结果赋值给左侧变量。
示例
public class AddAssignmentExample {
public static void main(String[] args) {
int x = 5;
x += 3; // 等同于 x = x + 3
System.out.println("x = " + x); // 输出: x = 8
}
}
3.2 减法赋值运算符 -=
将右侧的值从左侧变量中减去,并将结果赋值给左侧变量。
示例
public class SubtractAssignmentExample {
public static void main(String[] args) {
int x = 10;
x -= 4; // 等同于 x = x - 4
System.out.println("x = " + x); // 输出: x = 6
}
}
3.3 乘法赋值运算符 *=
将左侧变量与右侧值相乘,并将结果赋值给左侧变量。
示例
public class MultiplyAssignmentExample {
public static void main(String[] args) {
int x = 5;
x *= 2; // 等同于 x = x * 2
System.out.println("x = " + x); // 输出: x = 10
}
}
3.4 除法赋值运算符 /=
将左侧变量除以右侧值,并将结果赋值给左侧变量。
示例
public class DivideAssignmentExample {
public static void main(String[] args) {
int x = 20;
x /= 4; // 等同于 x = x / 4
System.out.println("x = " + x); // 输出: x = 5
}
}
3.5 取余赋值运算符 %=
将左侧变量对右侧值取余,并将结果赋值给左侧变量。
示例
public class ModulusAssignmentExample {
public static void main(String[] args) {
int x = 10;
x %= 3; // 等同于 x = x % 3
System.out.println("x = " + x); // 输出: x = 1
}
}
4. 其他赋值运算符(了解)
除了上述复合赋值运算符,还有一些其他的赋值运算符,但相对不常用,主要包括位运算符的复合赋值:
- 按位与赋值运算符
&=
- 按位或赋值运算符
|=
- 按位异或赋值运算符
^=
- 左移赋值运算符
<<=
- 右移赋值运算符
>>=
- 无符号右移赋值运算符
>>>=
示例
public class BitwiseAssignmentExample {
public static void main(String[] args) {
int x = 5; // 二进制: 0101
x &= 3; // 等同于 x = x & 3 (二进制: 0011)
System.out.println("x = " + x); // 输出: x = 1 (二进制: 0001)
}
}
16- 关系运算符
1. 关系运算符概述(掌握)
关系运算符用于比较两个操作数的值,并返回一个布尔值(true
或 false
)。在Java中,关系运算符主要用于控制流语句(如if
和while
)中的条件判断。
2. 常见的关系运算符(掌握)
2.1 等于运算符 ==
用于判断两个操作数是否相等。
示例
public class EqualityExample {
public static void main(String[] args) {
int a = 5;
int b = 5;
boolean result = (a == b); // true
System.out.println("a 等于 b: " + result); // 输出: a 等于 b: true
}
}
2.2 不等于运算符 !=
用于判断两个操作数是否不相等。
示例
public class InequalityExample {
public static void main(String[] args) {
int a = 5;
int b = 10;
boolean result = (a != b); // true
System.out.println("a 不等于 b: " + result); // 输出: a 不等于 b: true
}
}
2.3 大于运算符 >
用于判断左侧操作数是否大于右侧操作数。
示例
public class GreaterThanExample {
public static void main(String[] args) {
int a = 10;
int b = 5;
boolean result = (a > b); // true
System.out.println("a 大于 b: " + result); // 输出: a 大于 b: true
}
}
2.4 小于运算符 <
用于判断左侧操作数是否小于右侧操作数。
示例
public class LessThanExample {
public static void main(String[] args) {
int a = 5;
int b = 10;
boolean result = (a < b); // true
System.out.println("a 小于 b: " + result); // 输出: a 小于 b: true
}
}
2.5 大于等于运算符 >=
用于判断左侧操作数是否大于或等于右侧操作数。
示例
public class GreaterOrEqualExample {
public static void main(String[] args) {
int a = 5;
int b = 5;
boolean result = (a >= b); // true
System.out.println("a 大于或等于 b: " + result); // 输出: a 大于或等于 b: true
}
}
2.6 小于等于运算符 <=
用于判断左侧操作数是否小于或等于右侧操作数。
示例
public class LessOrEqualExample {
public static void main(String[] args) {
int a = 5;
int b = 10;
boolean result = (a <= b); // true
System.out.println("a 小于或等于 b: " + result); // 输出: a 小于或等于 b: true
}
}
3. 注意事项(了解)
对象比较:对于对象类型的变量,使用
==
运算符比较的是引用(内存地址),而非对象内容。要比较内容,应该使用equals()
方法。示例
public class ObjectComparison { public static void main(String[] args) { String str1 = new String("Hello"); String str2 = new String("Hello"); boolean result = (str1 == str2); // false boolean resultEquals = str1.equals(str2); // true System.out.println("引用比较: " + result); // 输出: 引用比较: false System.out.println("内容比较: " + resultEquals); // 输出: 内容比较: true } }
类型兼容性:关系运算符可以用于基本数据类型和相同类型的对象。确保操作数类型相容,否则会出现编译错误。
17- 逻辑运算符
1. 逻辑运算符概述(掌握)
逻辑运算符用于处理布尔值,通常用于控制流语句(如if
和while
)中的条件判断。Java中主要有三种逻辑运算符:
- 逻辑与(
&&
) - 逻辑或(
||
) - 逻辑非(
!
)
2. 逻辑运算符详解(掌握)
2.1 逻辑与运算符 &&
逻辑与运算符用于判断两个条件是否同时为真。只有当两个操作数都为true
时,结果才为true
;否则为false
。
示例
public class AndOperatorExample {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean result = a && b; // false
System.out.println("a 和 b 的逻辑与: " + result); // 输出: a 和 b 的逻辑与: false
}
}
2.2 逻辑或运算符 ||
逻辑或运算符用于判断至少一个条件是否为真。只要有一个操作数为true
,结果就为true
;只有当两个操作数都为false
时,结果才为false
。
示例
public class OrOperatorExample {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean result = a || b; // true
System.out.println("a 和 b 的逻辑或: " + result); // 输出: a 和 b 的逻辑或: true
}
}
2.3 逻辑非运算符 !
逻辑非运算符用于反转一个布尔值。如果操作数为true
,结果为false
;如果操作数为false
,结果为true
。
示例
public class NotOperatorExample {
public static void main(String[] args) {
boolean a = true;
boolean result = !a; // false
System.out.println("a 的逻辑非: " + result); // 输出: a 的逻辑非: false
}
}
3. 逻辑运算符的应用(掌握)
逻辑运算符通常用于复杂条件的组合,可以用于if
语句、while
循环等场景。
示例
public class LogicOperatorApplication {
public static void main(String[] args) {
int age = 20;
boolean hasLicense = true;
// 使用逻辑运算符进行条件判断
if (age >= 18 && hasLicense) {
System.out.println("可以开车。");
} else {
System.out.println("不可以开车。");
}
}
}
4. 短路特性(掌握)
逻辑与(&&
)和逻辑或(||
)运算符具有短路特性:
- 对于
&&
运算符,如果第一个操作数为false
,则不再评估第二个操作数,因为无论第二个条件如何,结果都将是false
。 - 对于
||
运算符,如果第一个操作数为true
,则不再评估第二个操作数,因为无论第二个条件如何,结果都将是true
。
示例
public class ShortCircuitExample {
public static void main(String[] args) {
int x = 5;
// 短路特性示例
boolean result = (x > 10) && (++x > 10); // ++x 不会被执行
System.out.println("result: " + result); // 输出: result: false
System.out.println("x: " + x); // 输出: x: 5
result = (x < 10) || (++x < 10); // ++x 会被执行
System.out.println("result: " + result); // 输出: result: true
System.out.println("x: " + x); // 输出: x: 6
}
}
18- 三元运算符
1. 三元运算符概述(掌握)
三元运算符,也称为条件运算符,是Java中唯一的三目运算符。它的基本语法形式是:
条件 ? 表达式1 : 表达式2
- 如果条件为
true
,则计算并返回表达式1
的值。 - 如果条件为
false
,则计算并返回表达式2
的值。
2. 三元运算符的使用(掌握)
三元运算符常用于简化条件判断,可以在赋值或表达式中直接使用。
2.1 示例
public class TernaryOperatorExample {
public static void main(String[] args) {
int a = 10;
int b = 20;
// 使用三元运算符比较 a 和 b
int max = (a > b) ? a : b; // 如果 a > b, max = a; 否则 max = b
System.out.println("最大值: " + max); // 输出: 最大值: 20
}
}
3. 复杂的三元运算符(了解)
三元运算符可以嵌套使用,处理更复杂的条件判断,但要注意可读性。
3.1 示例
public class NestedTernaryExample {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 15;
// 嵌套三元运算符
int max = (a > b) ? a : (b > c ? b : c);
System.out.println("最大值: " + max); // 输出: 最大值: 20
}
}
4. 注意事项(了解)
可读性:虽然三元运算符可以减少代码行数,但过度使用嵌套会降低代码的可读性,建议适度使用。
类型一致性:三元运算符的两种返回值必须是兼容的,或能够进行隐式转换。
19- 运算符优先级
1. 运算符优先级概述(掌握)
运算符优先级决定了在一个表达式中,哪些运算会先被执行。理解运算符优先级有助于避免意外的结果,并确保表达式按预期计算。Java中的运算符优先级由高到低,可以分为多个等级。
2. 常见运算符及其优先级(掌握)
以下是Java中一些常见运算符及其优先级,按优先级从高到低排列:
优先级 | 运算符 | 描述 |
---|---|---|
1 | () | 括号,强制优先执行 |
2 | ++ , -- | 自增、自减运算符(前缀) |
3 | ++ , -- | 自增、自减运算符(后缀) |
4 | - (一元), + (一元) | 一元减法和加法 |
5 | * , / , % | 乘法、除法和取余 |
6 | + , - | 加法和减法 |
7 | << , >> , >>> | 位移运算符 |
8 | < , > , <= , >= | 关系运算符 |
9 | == , != | 相等和不等运算符 |
10 | & | 按位与 |
11 | ^ | 按位异或 |
12 | ` | ` |
13 | && | 逻辑与 |
14 | ` | |
15 | ? : | 三元运算符 |
16 | = | 赋值运算符 |
17 | += , -= , *= , /= , %= , &= , ` | =, ^=` |
3. 运算符优先级示例(掌握)
理解运算符优先级可以帮助我们正确计算表达式。以下是一些示例:
3.1 示例1
public class OperatorPriorityExample {
public static void main(String[] args) {
int a = 5;
int b = 10;
int c = 15;
// 表达式: a + b * c
int result = a + b * c; // 先计算 b * c
System.out.println("结果: " + result); // 输出: 结果: 155
}
}
3.2 示例2
public class ParenthesesExample {
public static void main(String[] args) {
int a = 5;
int b = 10;
// 表达式: (a + b) * 2
int result = (a + b) * 2; // 括号内的先计算
System.out.println("结果: " + result); // 输出: 结果: 30
}
}
4. 注意事项(了解)
使用括号:在复杂的表达式中,为了提高可读性和避免优先级引起的错误,建议使用括号明确表达式的计算顺序。
调试:在调试代码时,注意运算符优先级,可以使用调试工具或打印中间结果来确认运算顺序。
20- 流程控制--顺序结构
1. 顺序结构概述(掌握)
顺序结构是程序控制的一种基本结构,在这种结构中,程序的执行按照代码的书写顺序逐行进行。顺序结构是所有程序控制结构的基础,所有的Java程序至少都有一个顺序执行的部分。
2. 顺序结构的特点(掌握)
- 线性执行:程序中的语句从上到下逐行执行,没有跳转。
- 简单易懂:对于初学者来说,顺序结构是最容易理解的结构,因为它不涉及复杂的逻辑。
- 无条件分支:没有条件判断和循环,代码的执行路径是固定的。
3. 顺序结构示例(掌握)
下面是一个简单的Java程序示例,演示了顺序结构的使用。
3.1 示例1:简单的计算
public class SequentialStructureExample {
public static void main(String[] args) {
// 定义变量
int a = 10;
int b = 20;
// 计算和
int sum = a + b;
// 输出结果
System.out.println("a 和 b 的和是: " + sum); // 输出: a 和 b 的和是: 30
}
}
在这个示例中,程序按顺序执行以下步骤:
- 定义变量
a
和b
并赋值。 - 计算
a
和b
的和并存储在sum
中。 - 输出
sum
的值。
3.2 示例2:输入输出
下面的示例展示了如何使用顺序结构进行用户输入和输出。
import java.util.Scanner;
public class InputOutputExample {
public static void main(String[] args) {
// 创建Scanner对象以获取用户输入
Scanner scanner = new Scanner(System.in);
// 提示用户输入
System.out.print("请输入一个整数: ");
int number = scanner.nextInt();
// 输出结果
System.out.println("您输入的整数是: " + number); // 输出用户输入的整数
// 关闭Scanner
scanner.close();
}
}
在这个示例中,程序的执行顺序为:
- 创建
Scanner
对象以获取用户输入。 - 提示用户输入一个整数。
- 读取用户输入的整数并存储在变量
number
中。 - 输出用户输入的整数。
4. 顺序结构的应用(掌握)
顺序结构通常用于以下场景:
- 初始化数据:在程序开始时对变量进行初始化。
- 计算结果:进行简单的计算并输出结果。
- 记录信息:逐步获取用户输入并记录信息。
21- 流程控制--分支结构
1. 分支结构概述(掌握)
分支结构是程序控制的一种结构,用于根据条件的真假来决定执行不同的代码块。Java中的分支结构主要包括if
语句、if-else
语句和switch
语句。分支结构使得程序能够在运行时做出不同的决策。
2. 分支结构类型(掌握)
2.1 if
语句
if
语句用于在条件为真时执行特定的代码块。
示例
public class IfStatementExample {
public static void main(String[] args) {
int score = 85;
if (score >= 60) {
System.out.println("考试通过。");
}
}
}
在这个示例中,只有当score
大于等于60时,才会输出“考试通过”。
2.2 if-else
语句
if-else
语句允许在条件为真时执行一个代码块,而在条件为假时执行另一个代码块。
示例
public class IfElseStatementExample {
public static void main(String[] args) {
int score = 55;
if (score >= 60) {
System.out.println("考试通过。");
} else {
System.out.println("考试未通过。");
}
}
}
在这个示例中,当score
小于60时,会输出“考试未通过”。
2.3 if-else if-else
语句
用于多个条件判断的情况,可以使用多个if-else if
来处理。
示例
public class IfElseIfStatementExample {
public static void main(String[] args) {
int score = 75;
if (score >= 90) {
System.out.println("成绩等级: A");
} else if (score >= 80) {
System.out.println("成绩等级: B");
} else if (score >= 70) {
System.out.println("成绩等级: C");
} else {
System.out.println("成绩等级: D");
}
}
}
在这个示例中,根据score
的值输出不同的成绩等级。
2.4 switch
语句
switch
语句用于多个值的条件判断,通常用于处理离散值(如整数、字符和字符串)。
示例
public class SwitchStatementExample {
public static void main(String[] args) {
int day = 3;
switch (day) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
default:
System.out.println("未知的星期");
}
}
}
在这个示例中,day
的值为3,所以输出“星期三”。
3. 分支结构的应用(掌握)
分支结构在以下场景中非常有用:
- 条件验证:根据用户输入或程序状态判断并执行不同的操作。
- 状态管理:根据不同的状态值选择不同的处理方式。
- 菜单选择:实现简单的菜单选择功能。
4. 注意事项(掌握)
- 使用
break
语句:在switch
语句中,break
用于跳出语句块,避免“fall through”现象,即继续执行后续的case
。 - 嵌套结构:可以在分支结构中嵌套其他分支结构,但要注意代码的可读性。
22- 顺序和分支综合练习
1. 计算学生成绩
import java.util.Scanner;
public class StudentGrade {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入学生成绩: ");
int score = scanner.nextInt();
String grade;
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else if (score >= 70) {
grade = "C";
} else if (score >= 60) {
grade = "D";
} else {
grade = "F";
}
System.out.println("学生成绩等级: " + grade);
scanner.close();
}
}
2. 偶数或奇数判断
import java.util.Scanner;
public class EvenOdd {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个整数: ");
int number = scanner.nextInt();
if (number % 2 == 0) {
System.out.println(number + " 是偶数。");
} else {
System.out.println(number + " 是奇数。");
}
scanner.close();
}
}
3. 年龄分类
import java.util.Scanner;
public class AgeCategory {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入年龄: ");
int age = scanner.nextInt();
String category;
if (age < 13) {
category = "儿童";
} else if (age < 20) {
category = "青少年";
} else if (age < 60) {
category = "成年人";
} else {
category = "老年人";
}
System.out.println("年龄类别: " + category);
scanner.close();
}
}
4. 根据天气给出穿衣建议
import java.util.Scanner;
public class ClothingSuggestion {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入气温(摄氏度): ");
int temperature = scanner.nextInt();
if (temperature < 0) {
System.out.println("建议穿厚衣服。");
} else if (temperature < 20) {
System.out.println("建议穿轻便外套。");
} else {
System.out.println("可以穿短袖。");
}
scanner.close();
}
}
5. 打印星期几
import java.util.Scanner;
public class DayOfWeek {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个数字(1-7): ");
int day = scanner.nextInt();
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 = "无效输入";
}
System.out.println("您输入的是: " + dayName);
scanner.close();
}
}
6. 判断成绩合格与否
import java.util.Scanner;
public class PassFail {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入成绩: ");
int score = scanner.nextInt();
if (score >= 60) {
System.out.println("考试通过。");
} else {
System.out.println("考试未通过。");
}
scanner.close();
}
}
7. 计算正方形和圆的面积
import java.util.Scanner;
public class AreaCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("选择形状(1: 正方形, 2: 圆): ");
int choice = scanner.nextInt();
if (choice == 1) {
System.out.print("请输入边长: ");
double side = scanner.nextDouble();
double area = side * side;
System.out.println("正方形面积: " + area);
} else if (choice == 2) {
System.out.print("请输入半径: ");
double radius = scanner.nextDouble();
double area = Math.PI * radius * radius;
System.out.println("圆面积: " + area);
} else {
System.out.println("无效选择。");
}
scanner.close();
}
}
8. 基于性别和年龄的票价
import java.util.Scanner;
public class TicketPrice {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入性别(M/F): ");
char gender = scanner.next().charAt(0);
System.out.print("请输入年龄: ");
int age = scanner.nextInt();
double price;
if (age < 18) {
price = 10; // 儿童票
} else if (age >= 60) {
price = 5; // 老年票
} else {
price = 20; // 成人票
}
System.out.println("票价: " + price + " 元");
scanner.close();
}
}
9. 计算并输出整数的绝对值
import java.util.Scanner;
public class AbsoluteValue {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个整数: ");
int number = scanner.nextInt();
int absoluteValue;
if (number < 0) {
absoluteValue = -number;
} else {
absoluteValue = number;
}
System.out.println("绝对值: " + absoluteValue);
scanner.close();
}
}
10. 评分系统(A、B、C、D、F)
import java.util.Scanner;
public class GradingSystem {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入成绩: ");
int score = scanner.nextInt();
String grade;
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else if (score >= 70) {
grade = "C";
} else if (score >= 60) {
grade = "D";
} else {
grade = "F";
}
System.out.println("成绩等级: " + grade);
scanner.close();
}
}
23- 流程控制--循环结构
1. 循环结构概述(掌握)
循环结构是一种控制结构,用于重复执行一段代码,直到满足特定条件为止。Java中的循环主要有三种类型:for
循环、while
循环和do-while
循环。这些结构在处理重复性任务时极其重要,能够提高代码的可读性和效率。
2. 循环结构类型(掌握)
2.1 for
循环
for
循环用于已知次数的重复,其语法结构如下:
for (初始化; 条件; 更新) {
// 循环体
}
- 初始化:定义循环控制变量并初始化。
- 条件:在每次循环开始前判断,如果条件为真,则执行循环体;如果为假,则退出循环。
- 更新:每次循环结束后执行的操作,通常用于更新循环控制变量。
示例
public class ForLoopExample {
public static void main(String[] args) {
// 打印1到5的数字
for (int i = 1; i <= 5; i++) {
System.out.println("当前值: " + i);
}
}
}
在这个示例中,for
循环从1循环到5,逐次打印出当前的值。每次循环i
加1,直到i
大于5时退出循环。
2.2 while
循环
while
循环用于在条件为真时重复执行,其语法如下:
while (条件) {
// 循环体
}
- 条件:在每次循环开始前检查。如果条件为真,则执行循环体;如果为假,则退出循环。
示例
public class WhileLoopExample {
public static void main(String[] args) {
int i = 1;
// 当i小于等于5时执行循环
while (i <= 5) {
System.out.println("当前值: " + i);
i++; // 更新计数器
}
}
}
在这个示例中,while
循环的条件是i <= 5
,每次循环i
加1,直到i
大于5为止。
2.3 do-while
循环
do-while
循环与while
循环类似,但它保证循环体至少执行一次。其语法如下:
do {
// 循环体
} while (条件);
- 循环体:首先执行一次,然后检查条件。如果条件为真,则继续执行,否则退出。
示例
public class DoWhileLoopExample {
public static void main(String[] args) {
int i = 1;
do {
System.out.println("当前值: " + i);
i++;
} while (i <= 5);
}
}
在这个示例中,do-while
循环首先打印i
的值,然后判断i
是否小于等于5。
3. 循环控制语句(掌握)
3.1 break
语句
break
语句用于立即退出循环。在循环体内遇到break
时,循环将停止执行。
示例
public class BreakExample {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // 当i等于5时退出循环
}
System.out.println("当前值: " + i);
}
}
}
在这个示例中,当i
等于5时,循环会立即停止,不会打印5以后的值。
3.2 continue
语句
continue
语句用于跳过当前循环的剩余部分,直接进入下一次循环。
示例
public class ContinueExample {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
continue; // 跳过5
}
System.out.println("当前值: " + i);
}
}
}
在这个示例中,当i
等于5时,continue
语句会跳过当前循环的输出,直接进入下一个迭代。
4. 嵌套循环(了解)
在一个循环内部可以包含另一个循环,这被称为嵌套循环。它常用于处理多维数组或复杂的重复逻辑。
示例
public class NestedLoopExample {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 2; j++) {
System.out.println("i: " + i + ", j: " + j);
}
}
}
}
在这个示例中,外层循环控制i
的值,内层循环控制j
的值,输出结果将显示i
和j
的组合。
5. 循环结构的应用(掌握)
循环结构在编程中的应用非常广泛,例如:
- 遍历数组:通过循环访问数组中的每个元素。
- 处理用户输入:根据条件重复获取用户输入,例如,直到用户输入有效值为止。
- 生成序列:生成数值序列或字符序列,如斐波那契数列。
- 数据统计:计算总和、平均值、最大值、最小值等。
24- 流程控制综合案例
以下是几个关于流程控制的综合案例,每个案例包括题目、解题思路、代码以及详细的代码解释。
案例 1:猜数字游戏
题目
编写一个程序,让用户猜一个随机生成的1到100之间的数字,直到猜对为止。
解题思路
- 使用
Random
类生成一个随机数字。 - 提示用户输入一个数字并进行比较。
- 根据用户的输入给出反馈(猜大了或猜小了)。
- 使用循环控制,直到用户猜对为止。
代码
import java.util.Random;
import java.util.Scanner;
public class GuessNumberGame {
public static void main(String[] args) {
Random random = new Random();
int numberToGuess = random.nextInt(100) + 1;
int userGuess = 0;
Scanner scanner = new Scanner(System.in);
int attempts = 0;
System.out.println("欢迎来到猜数字游戏!请输入1到100之间的数字:");
while (userGuess != numberToGuess) {
userGuess = scanner.nextInt();
attempts++;
if (userGuess < numberToGuess) {
System.out.println("太小了!再试一次:");
} else if (userGuess > numberToGuess) {
System.out.println("太大了!再试一次:");
} else {
System.out.println("恭喜你,猜对了!你总共尝试了 " + attempts + " 次。");
}
}
scanner.close();
}
}
代码解释
Random
类生成一个1到100之间的随机数字。Scanner
类用于接收用户输入。while
循环持续获取用户输入,直到猜对为止。- 在每次猜测后,程序会提示用户是猜小了还是猜大了,并计数尝试次数。
案例 2:计算平均成绩
题目
编写一个程序,输入多个学生的成绩,并计算出他们的平均成绩。
解题思路
- 提示用户输入学生人数。
- 使用循环获取每个学生的成绩并累加。
- 计算总成绩与人数的比值,输出平均成绩。
代码
import java.util.Scanner;
public class AverageScoreCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入学生人数: ");
int numberOfStudents = scanner.nextInt();
double totalScore = 0;
for (int i = 1; i <= numberOfStudents; i++) {
System.out.print("请输入第 " + i + " 个学生的成绩: ");
double score = scanner.nextDouble();
totalScore += score;
}
double averageScore = totalScore / numberOfStudents;
System.out.println("学生的平均成绩是: " + averageScore);
scanner.close();
}
}
代码解释
Scanner
类用于获取用户输入的学生人数和成绩。for
循环迭代学生人数,依次获取每个学生的成绩并累加到totalScore
。- 最后,计算平均成绩并打印结果。
案例 3:温度转换器
题目
编写一个程序,允许用户将摄氏度转换为华氏度或将华氏度转换为摄氏度。
解题思路
- 提示用户选择转换方向。
- 根据用户选择,获取相应的温度输入。
- 进行计算并输出结果。
代码
import java.util.Scanner;
public class TemperatureConverter {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请选择转换类型(1: 摄氏度转华氏度,2: 华氏度转摄氏度):");
int choice = scanner.nextInt();
if (choice == 1) {
System.out.print("请输入摄氏度: ");
double celsius = scanner.nextDouble();
double fahrenheit = (celsius * 9/5) + 32;
System.out.println(celsius + "°C = " + fahrenheit + "°F");
} else if (choice == 2) {
System.out.print("请输入华氏度: ");
double fahrenheit = scanner.nextDouble();
double celsius = (fahrenheit - 32) * 5/9;
System.out.println(fahrenheit + "°F = " + celsius + "°C");
} else {
System.out.println("无效选择。");
}
scanner.close();
}
}
代码解释
Scanner
类用于接收用户的选择和温度输入。- 使用
if-else
结构根据用户选择执行不同的转换计算。 - 输出转换后的温度值,并处理无效输入情况。
案例 4:求阶乘
题目
编写一个程序,计算一个整数的阶乘,直到用户输入0为止。
解题思路
- 使用循环接收用户输入的整数。
- 计算该整数的阶乘,输出结果。
- 如果输入为0,程序退出。
代码
import java.util.Scanner;
public class FactorialCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int number;
while (true) {
System.out.print("请输入一个非负整数(输入0退出): ");
number = scanner.nextInt();
if (number == 0) {
break; // 退出循环
}
long factorial = 1;
for (int i = 1; i <= number; i++) {
factorial *= i; // 计算阶乘
}
System.out.println(number + " 的阶乘是: " + factorial);
}
System.out.println("程序结束。");
scanner.close();
}
}
代码解释
while
循环持续接受用户输入,直到输入0。for
循环计算输入数的阶乘,结果存储在factorial
中。- 输出计算结果,并在用户输入0时结束程序。
案例 5:简单计算器
题目
编写一个简单的计算器程序,支持加、减、乘、除四则运算。
解题思路
- 获取用户输入的两个数字和运算符。
- 使用
switch
语句根据运算符执行相应的运算。 - 输出计算结果。
代码
import java.util.Scanner;
public class SimpleCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入第一个数字: ");
double num1 = scanner.nextDouble();
System.out.print("请输入运算符 (+, -, *, /): ");
char operator = scanner.next().charAt(0);
System.out.print("请输入第二个数字: ");
double num2 = scanner.nextDouble();
double result;
switch (operator) {
case '+':
result = num1 + num2;
System.out.println("结果: " + result);
break;
case '-':
result = num1 - num2;
System.out.println("结果: " + result);
break;
case '*':
result = num1 * num2;
System.out.println("结果: " + result);
break;
case '/':
if (num2 != 0) {
result = num1 / num2;
System.out.println("结果: " + result);
} else {
System.out.println("错误:除数不能为零。");
}
break;
default:
System.out.println("无效运算符。");
break;
}
scanner.close();
}
}
代码解释
Scanner
类用于获取用户输入的两个数字和运算符。switch
语句根据运算符执行相应的计算,并处理除数为零的特殊情况。- 最后输出计算结果或错误提示。
案例 6:学生成绩评定
题目
编写一个程序,输入多个学生的成绩,输出每个成绩及其对应的评定(优秀、及格、不及格)。
解题思路
- 使用
while
循环获取多个成绩。 - 使用
if
判断每个成绩的评定标准。 - 输出成绩及评定。
代码
import java.util.Scanner;
public class GradeEvaluation {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int grade;
int count = 0;
while (true) {
System.out.print("请输入学生成绩(输入-1结束):");
grade = scanner.nextInt();
if (grade == -1) {
break; // 结束输入
}
count++;
if (grade >= 90) {
System.out.println("成绩: " + grade + " - 优秀");
} else if (grade >= 60) {
System.out.println("成绩: " + grade + " - 及格");
} else {
System.out.println("成绩: " + grade + " - 不及格");
}
}
System.out.println("共输入 " + count + " 个成绩。");
scanner.close();
}
}
代码解释
- 使用
while
循环不断接收成绩,直到用户输入-1。 - 使用
if-else
判断成绩的评定,并输出结果。 - 计数已输入的成绩数量。
案例 7:密码强度检测
题目
编写一个程序,要求用户输入密码,检测其强度(弱、中、强)。
解题思路
- 获取用户输入的密码。
- 判断密码的长度和包含的字符类型(字母、数字、特殊字符)。
- 输出密码的强度。
代码
import java.util.Scanner;
public class PasswordStrengthChecker {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入密码: ");
String password = scanner.nextLine();
int length = password.length();
boolean hasLetter = false, hasDigit = false, hasSpecial = false;
for (char ch : password.toCharArray()) {
if (Character.isLetter(ch)) {
hasLetter = true;
} else if (Character.isDigit(ch)) {
hasDigit = true;
} else {
hasSpecial = true;
}
}
if (length >= 8 && hasLetter && hasDigit && hasSpecial) {
System.out.println("密码强度: 强");
} else if (length >= 6 && (hasLetter || hasDigit)) {
System.out.println("密码强度: 中");
} else {
System.out.println("密码强度: 弱");
}
scanner.close();
}
}
代码解释
- 使用
for
循环遍历密码中的每个字符,检查字符类型。 - 根据条件判断密码强度,并输出结果。
案例 8:计算折扣后的价格
题目
编写一个程序,输入商品原价和折扣率,计算折扣后的价格。
解题思路
- 获取用户输入的原价和折扣率。
- 使用简单的算术运算计算折扣后价格。
- 输出计算结果。
代码
import java.util.Scanner;
public class DiscountCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入商品原价: ");
double originalPrice = scanner.nextDouble();
System.out.print("请输入折扣率(0-1之间): ");
double discountRate = scanner.nextDouble();
if (discountRate < 0 || discountRate > 1) {
System.out.println("无效的折扣率。");
} else {
double finalPrice = originalPrice * (1 - discountRate);
System.out.println("折扣后的价格: " + finalPrice);
}
scanner.close();
}
}
代码解释
- 检查输入的折扣率是否有效,然后计算并输出折扣后的价格。
案例 9:计算素数个数
题目
编写一个程序,计算从1到N中素数的个数。
解题思路
- 获取用户输入的N。
- 使用嵌套循环判断每个数字是否为素数。
- 计数并输出素数的个数。
代码
import java.util.Scanner;
public class CountPrimes {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个正整数N: ");
int N = scanner.nextInt();
int primeCount = 0;
for (int num = 2; num <= N; num++) {
boolean isPrime = true;
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
isPrime = false;
break; // 提前退出
}
}
if (isPrime) {
primeCount++;
}
}
System.out.println("1到" + N + "之间的素数个数是: " + primeCount);
scanner.close();
}
}
代码解释
- 外层
for
循环遍历每个数字,内层for
循环检查数字是否为素数。 - 统计并输出素数的总个数。
案例 10:九九乘法表
题目
编写一个程序,打印九九乘法表。
解题思路
- 使用嵌套循环,外层控制行,内层控制列。
- 输出每个乘法结果。
代码
public class MultiplicationTable {
public static void main(String[] args) {
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(); // 换行
}
}
}
代码解释
- 外层
for
循环控制行数,内层for
循环控制列数,输出乘法结果。 - 使用制表符
\t
调整格式,最后换行。
案例 11:找出数组中的最大值和最小值
题目
编写一个程序,找出用户输入的一组整数中的最大值和最小值。
解题思路
- 接收用户输入的整数个数和每个整数。
- 遍历数组,找出最大值和最小值。
- 输出结果。
代码
import java.util.Scanner;
public class MaxMinInArray {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入整数个数: ");
int n = scanner.nextInt();
int[] numbers = new int[n];
for (int i = 0; i < n; i++) {
System.out.print("请输入第 " + (i + 1) + " 个整数: ");
numbers[i] = scanner.nextInt();
}
int max = numbers[0];
int min = numbers[0];
for (int num : numbers) {
if (num > max) {
max = num;
}
if (num < min) {
min = num;
}
}
System.out.println("最大值: " + max + ", 最小值: " + min);
scanner.close();
}
}
代码解释
- 使用
for
循环接收用户输入的整数存入数组。 - 再次使用
for-each
循环找出最大值和最小值,最后输出结果。
案例 12:简单投票系统
题目
编写一个程序,模拟一个简单的投票系统,允许用户投票给候选人,并显示投票结果。
解题思路
- 使用数组存储候选人名称和他们的票数。
- 使用
while
循环接收用户的投票。 - 输出每个候选人的得票数。
代码
import java.util.Scanner;
public class VotingSystem {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] candidates = {"候选人A", "候选人B", "候选人C"};
int[] votes = new int[candidates.length];
while (true) {
System.out.println("请输入投票(0: A, 1: B, 2: C,-1结束投票):");
int vote = scanner.nextInt();
if (vote == -1) {
break; // 结束投票
}
if (vote >= 0 && vote < candidates.length) {
votes[vote]++; // 增加相应候选人的票数
} else {
System.out.println("无效的投票。");
}
}
System.out.println("投票结果:");
for (int i = 0; i < candidates.length; i++) {
System.out.println(candidates[i] + ": " + votes[i] + " 票");
}
scanner.close();
}
}
代码解释
- 使用
while
循环接收投票,直到用户输入-1。 - 增加相应候选人的票数并输出最终结果。
案例 13:判断年份是否为闰年
题目
编写一个程序,判断用户输入的年份是否为闰年。
解题思路
- 获取用户输入的年份。
- 使用
if
判断是否满足闰年的条件。 - 输出判断结果。
代码
import java.util.Scanner;
public class LeapYearCheck {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入年份: ");
int year = scanner.nextInt();
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
System.out.println(year + " 是闰年。");
} else {
System.out.println(year + " 不是闰年。");
}
scanner.close();
}
}
代码解释
- 通过
if
判断年份是否符合闰年的条件,输出结果。
案例 14:计算阶乘
题目
编写一个程序,计算用户输入的数字的阶乘。
解题思路
- 获取用户输入的非负整数。
- 使用循环计算阶乘。
- 输出结果。
代码
import java.util.Scanner;
public class FactorialCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个非负整数: ");
int number = scanner.nextInt();
long factorial = 1;
if (number < 0) {
System.out.println("无效输入,不能计算负数的阶乘。");
} else {
for (int i = 1; i <= number; i++) {
factorial *= i; // 计算阶乘
}
System.out.println(number + " 的阶乘是: " + factorial);
}
scanner.close();
}
}
代码解释
- 通过
for
循环计算输入数字的阶乘,输出结果。
案例 15:猜数字游戏
题目
编写一个程序,生成一个随机数,用户需要猜测这个数字,程序给出提示。
解题思路
- 生成一个1到100之间的随机数。
- 使用
while
循环接收用户的猜测并给出提示。 - 用户猜对后输出结果并结束。
代码
import java.util.Random;
import java.util.Scanner;
public class GuessingGame {
public static void main(String[] args) {
Random random = new Random();
int numberToGuess = random.nextInt(100) + 1; // 生成1到100之间的随机数
Scanner scanner = new Scanner(System.in);
int guess;
int attempts = 0;
System.out.println("猜一个1到100之间的数字。");
while (true) {
System.out.print("请输入你的猜测: ");
guess = scanner.nextInt();
attempts++;
if (guess < numberToGuess) {
System.out.println("太小了,再试一次。");
} else if (guess > numberToGuess) {
System.out.println("太大了,再试一次。");
} else {
System.out.println("恭喜你,猜对了!总共猜了 " + attempts + " 次。");
break; // 猜对了,结束循环
}
}
scanner.close();
}
}
代码解释
- 生成一个随机数,使用
while
循环接收用户的猜测。 - 根据用户的输入给予提示,并记录猜测次数。
25- Switch语句(详解)
Switch语句详解
1. 什么是Switch语句
Switch语句是一种控制结构,用于在多个可能的执行路径中选择一个。它根据一个表达式的值匹配不同的case
,并执行相应的代码块。
2. Switch语句的基本语法
switch (表达式) {
case 常量1:
// 执行代码块1
break;
case 常量2:
// 执行代码块2
break;
// 可以有任意数量的case语句
default:
// 执行代码块(可选)
}
- 表达式:可以是
int
、char
、String
等。 - case:每个case后面跟一个常量值。如果表达式的值与某个case的常量值匹配,执行该case下的代码。
- break:用于终止switch语句,防止执行后续的case。
- default:可选部分,如果没有匹配到任何case,则执行default中的代码。
3. Switch语句的特点
- 匹配类型:支持整型、字符型、字符串等类型,但不支持浮点数。
- 高效性:在处理多个条件时,Switch比多个if-else结构更高效。
- 可读性:使用明确的case标签,使得代码更易于理解。
4. 示例代码
import java.util.Scanner;
public class SwitchExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个数字(1-7)表示星期几: ");
int day = scanner.nextInt();
switch (day) {
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 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期天");
break;
default:
System.out.println("无效的输入,请输入1到7之间的数字。");
}
scanner.close();
}
}
5. 代码解释
- 用户输入一个数字,表示星期几。
- 根据输入的数字,Switch语句匹配相应的case,输出对应的星期。
- 如果输入的数字不在1到7之间,执行default部分,提示无效输入。
6. 注意事项
- 缺少break:如果在某个case后缺少break,程序会继续执行下一个case,导致意外结果(称为"fall-through")。
- 变量类型:从Java 7开始,Switch语句支持字符串类型。
- 常量要求:case后面的值必须是常量表达式,且必须与switch表达式的类型匹配。
7. 示例:字符串的Switch
public class StringSwitchExample {
public static void main(String[] args) {
String fruit = "苹果";
switch (fruit) {
case "苹果":
System.out.println("你选择了苹果");
break;
case "香蕉":
System.out.println("你选择了香蕉");
break;
case "橘子":
System.out.println("你选择了橘子");
break;
default:
System.out.println("未知水果");
}
}
}
8. Switch语句的嵌套使用
可以在一个switch语句中嵌套另一个switch语句,以处理复杂的条件。
public class NestedSwitchExample {
public static void main(String[] args) {
int option = 1;
char subOption = 'A';
switch (option) {
case 1:
System.out.println("选择了选项1");
switch (subOption) {
case 'A':
System.out.println("子选项A");
break;
case 'B':
System.out.println("子选项B");
break;
default:
System.out.println("未知子选项");
}
break;
case 2:
System.out.println("选择了选项2");
break;
default:
System.out.println("未知选项");
}
}
}
26- 数组
1. 数组的定义
数组是一种数据结构,用于存储多个相同类型的数据元素。它在内存中是连续存储的,允许通过索引快速访问元素。
1.1 数组的基本特点
- 固定大小:数组的大小在创建时确定,不能动态改变。
- 同类型元素:数组中的所有元素类型相同。
- 索引访问:数组元素通过索引访问,索引从0开始。
2. 数组的声明与初始化
2.1 数组的声明
数组的声明方式如下:
数据类型[] 数组名; // 推荐的声明方式
// 或者
数据类型 数组名[]; // 另一种声明方式
2.2 数组的静态初始化
静态初始化是在声明数组时直接赋值,示例:
int[] numbers = {1, 2, 3, 4, 5}; // 静态初始化
String[] fruits = {"苹果", "香蕉", "橘子"}; // 字符串数组的静态初始化
2.3 数组的动态初始化
动态初始化是在声明数组后使用new
关键字创建数组并指定大小:
int[] numbers = new int[5]; // 动态初始化,数组大小为5,元素默认值为0
String[] fruits = new String[3]; // 数组大小为3,元素默认值为null
2.4 完整示例
public class ArrayInitialization {
public static void main(String[] args) {
// 静态初始化
int[] staticArray = {10, 20, 30, 40};
// 动态初始化
double[] dynamicArray = new double[4];
dynamicArray[0] = 1.5;
dynamicArray[1] = 2.5;
// 打印数组内容
System.out.println("静态数组:");
for (int num : staticArray) {
System.out.print(num + " ");
}
System.out.println("\n动态数组:");
for (double num : dynamicArray) {
System.out.print(num + " ");
}
}
}
3. 数组元素的访问
3.1 访问数组元素
数组元素通过索引访问,示例:
int firstNumber = numbers[0]; // 访问第一个元素
numbers[1] = 10; // 修改第二个元素
3.2 获取数组的长度
数组的长度可以通过length
属性获得:
int length = numbers.length; // 获取数组的长度
3.3 完整示例
public class ArrayAccess {
public static void main(String[] args) {
int[] numbers = {5, 10, 15, 20};
// 访问数组元素
System.out.println("第一个元素:" + numbers[0]);
System.out.println("第二个元素:" + numbers[1]);
// 修改数组元素
numbers[1] = 30;
System.out.println("修改后的第二个元素:" + numbers[1]);
// 打印数组长度
System.out.println("数组长度:" + numbers.length);
}
}
4. 数组的遍历
4.1 使用for循环遍历
常用的遍历方式是使用for循环:
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]); // 打印每个元素
}
4.2 使用增强for循环遍历
Java提供了增强for循环(foreach),简化数组遍历:
for (int number : numbers) {
System.out.println(number); // 打印每个元素
}
4.3 完整示例
public class ArrayTraversal {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
// 使用for循环遍历
System.out.println("使用for循环遍历:");
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
// 使用增强for循环遍历
System.out.println("使用增强for循环遍历:");
for (int number : numbers) {
System.out.println(number);
}
}
}
5. 数组的内存图示
在内存中,数组是以连续的内存块存储的。下面是一个数组的示意图(假设数组大小为5):
+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 |
+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | // 数组元素
+---+---+---+---+---+
6. 数组的常见问题
6.1 数组越界
访问超出数组长度的索引会导致ArrayIndexOutOfBoundsException
异常:
int value = numbers[5]; // 数组长度为5,索引5越界
6.2 空指针异常
如果数组未初始化,访问元素时会导致NullPointerException
:
int[] uninitializedArray; // 数组未初始化
int value = uninitializedArray[0]; // 触发NullPointerException
6.3 完整示例
public class ArrayExceptions {
public static void main(String[] args) {
int[] numbers = new int[3];
// 数组越界示例
try {
System.out.println(numbers[3]); // 触发异常
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界: " + e.getMessage());
}
// 空指针异常示例
int[] uninitializedArray = null;
try {
System.out.println(uninitializedArray[0]); // 触发异常
} catch (NullPointerException e) {
System.out.println("空指针异常: " + e.getMessage());
}
}
}
7. 数组的常用操作
7.1 数组的复制
可以使用System.arraycopy()
方法复制数组:
int[] newArray = new int[numbers.length];
System.arraycopy(numbers, 0, newArray, 0, numbers.length); // 复制数组
7.2 数组的排序
可以使用Arrays.sort()
方法对数组进行排序:
import java.util.Arrays;
Arrays.sort(numbers); // 排序数组
7.3 数组的查找
可以使用线性查找或二分查找(要求数组已排序):
import java.util.Arrays;
int index = Arrays.binarySearch(numbers, 3); // 查找数字3的索引
7.4 数组的合并
可以手动合并两个数组,示例:
int[] array1 = {1, 2, 3};
int[] array2 = {4, 5, 6};
int[] mergedArray = new int[array1.length + array2.length];
System.arraycopy(array1, 0, mergedArray, 0, array1.length);
System.arraycopy(array2, 0, mergedArray, array1.length, array2.length);
7.5 完整示例
import java.util.Arrays;
public class ArrayOperations {
public static void main(String[] args) {
int[] numbers = {5, 3, 8, 1, 2};
// 复制数组
int[] copiedArray = new int[numbers.length];
System.arraycopy(numbers, 0, copiedArray, 0, numbers.length);
// 排序数组
Arrays.sort(numbers);
// 查找数组中元素
int index = Arrays.binarySearch(numbers, 3); // 查找数字3的索引
// 合并数组
int[] array1 = {1, 2, 3};
int[] array2 = {4, 5, 6};
int[] mergedArray = new int[array1.length + array2.length];
System.arraycopy(array1, 0, mergedArray, 0, array1.length);
System.arraycopy(array2, 0, mergedArray, array1.length, array2.length);
// 打印结果
System.out.println("原数组: " + Arrays.toString(numbers));
System.out.println("复制数组: " + Arrays.toString(copiedArray));
System.out.println("查找索引: " + index);
System.out.println("合并数组: " + Arrays.toString(mergedArray));
}
}
8. 多维数组
8.1 多维数组的定义
多维数组是数组的数组,常见的是二维数组:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8
, 9}
};
8.2 访问多维数组元素
访问方式与一维数组相似:
int value = matrix[1][2]; // 访问第二行第三列的元素,值为6
8.3 遍历多维数组
可以使用嵌套循环遍历多维数组:
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " "); // 打印每个元素
}
System.out.println(); // 换行
}
8.4 完整示例
public class MultiDimensionalArray {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 遍历二维数组
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println(); // 换行
}
}
}
9. 数组的优势与劣势
9.1 优势
- 高效访问:可以通过索引快速访问元素。
- 节省内存:存储同类型数据时更节省内存。
9.2 劣势
- 固定大小:创建后不能改变大小。
- 只能存同一类型:数组中的元素必须是相同类型。
27- 数组综合练习
1. 题目:数组求和
解题思路
创建一个整数数组,计算并输出数组中所有元素的和。
public class ArraySum {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5}; // 定义数组
int sum = 0; // 初始化和
// 遍历数组并计算和
for (int number : numbers) {
sum += number; // 累加每个元素
}
System.out.println("数组元素的和为:" + sum); // 输出结果
}
}
代码详解
- 定义数组
numbers
,包含5个整数。 - 使用增强for循环遍历数组,逐个累加元素到
sum
中。 - 最后输出
sum
的值。
2. 题目:查找最大元素
解题思路
在一个整数数组中查找并输出最大值。
public class MaxInArray {
public static void main(String[] args) {
int[] numbers = {10, 20, 5, 40, 15}; // 定义数组
int max = numbers[0]; // 假设第一个元素为最大值
// 遍历数组查找最大值
for (int number : numbers) {
if (number > max) {
max = number; // 更新最大值
}
}
System.out.println("数组中的最大值为:" + max); // 输出结果
}
}
代码详解
- 假设第一个元素为最大值。
- 遍历数组,使用
if
语句比较每个元素与max
,若更大则更新max
。 - 输出最大值。
3. 题目:数组反转
解题思路
反转一个数组的元素并输出结果。
public class ReverseArray {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5}; // 定义数组
int[] reversed = new int[numbers.length]; // 创建反转数组
// 反转数组
for (int i = 0; i < numbers.length; i++) {
reversed[i] = numbers[numbers.length - 1 - i]; // 反向赋值
}
// 打印反转后的数组
System.out.print("反转后的数组:");
for (int num : reversed) {
System.out.print(num + " ");
}
}
}
代码详解
- 创建一个与原数组大小相同的
reversed
数组。 - 使用
for
循环将原数组从后向前赋值给新数组。 - 最后遍历并打印反转后的数组。
4. 题目:统计元素出现次数
解题思路
统计一个数组中每个元素出现的次数并输出。
import java.util.HashMap;
public class CountElements {
public static void main(String[] args) {
int[] numbers = {1, 2, 2, 3, 1, 4, 3, 1}; // 定义数组
HashMap<Integer, Integer> countMap = new HashMap<>(); // 使用HashMap统计
// 统计每个元素的出现次数
for (int number : numbers) {
countMap.put(number, countMap.getOrDefault(number, 0) + 1); // 更新次数
}
// 输出每个元素及其次数
for (int key : countMap.keySet()) {
System.out.println(key + "出现次数:" + countMap.get(key));
}
}
}
代码详解
- 使用
HashMap
来存储元素及其出现次数。 - 遍历数组,更新每个元素的计数。
- 最后遍历
countMap
并输出结果。
5. 题目:数组排序
解题思路
对一个整数数组进行升序排序并输出结果。
import java.util.Arrays;
public class SortArray {
public static void main(String[] args) {
int[] numbers = {5, 3, 8, 1, 2}; // 定义数组
Arrays.sort(numbers); // 使用Arrays.sort()进行排序
// 输出排序后的数组
System.out.print("排序后的数组:");
for (int num : numbers) {
System.out.print(num + " ");
}
}
}
代码详解
- 使用
Arrays.sort()
方法对数组进行排序。 - 输出排序后的数组。
6. 题目:查找特定元素
解题思路
查找数组中是否包含某个特定元素,并输出结果。
public class SearchElement {
public static void main(String[] args) {
int[] numbers = {1, 3, 5, 7, 9}; // 定义数组
int target = 5; // 要查找的元素
boolean found = false; // 标志变量
// 遍历数组查找元素
for (int number : numbers) {
if (number == target) {
found = true; // 找到元素
break; // 退出循环
}
}
// 输出结果
if (found) {
System.out.println("元素" + target + "存在于数组中。");
} else {
System.out.println("元素" + target + "不存在于数组中。");
}
}
}
代码详解
- 定义目标元素
target
。 - 遍历数组,若找到目标则将
found
标志设为true
并退出循环。 - 根据
found
的值输出查找结果。
7. 题目:合并两个数组
解题思路
将两个数组合并为一个新数组并输出结果。
public class MergeArrays {
public static void main(String[] args) {
int[] array1 = {1, 2, 3}; // 定义第一个数组
int[] array2 = {4, 5, 6}; // 定义第二个数组
int[] mergedArray = new int[array1.length + array2.length]; // 创建合并数组
// 合并数组
System.arraycopy(array1, 0, mergedArray, 0, array1.length); // 复制第一个数组
System.arraycopy(array2, 0, mergedArray, array1.length, array2.length); // 复制第二个数组
// 输出合并后的数组
System.out.print("合并后的数组:");
for (int num : mergedArray) {
System.out.print(num + " ");
}
}
}
代码详解
- 创建一个新数组
mergedArray
,大小为两个数组之和。 - 使用
System.arraycopy()
方法将两个数组复制到新数组中。 - 最后遍历并输出合并后的数组。
8. 题目:计算数组的平均值
解题思路
计算并输出一个数组的平均值。
public class AverageOfArray {
public static void main(String[] args) {
double[] numbers = {2.5, 3.5, 4.0, 5.0}; // 定义数组
double sum = 0; // 初始化和
// 遍历数组计算和
for (double number : numbers) {
sum += number; // 累加每个元素
}
double average = sum / numbers.length; // 计算平均值
System.out.println("数组的平均值为:" + average); // 输出结果
}
}
代码详解
- 定义一个
double
类型数组numbers
。 - 遍历数组,计算元素的和
sum
。 - 计算平均值并输出。
9. 题目:查找重复元素
解题思路
查找数组中重复的元素并输出。
import java.util.HashSet;
public class FindDuplicates {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 2, 4, 1}; // 定义数组
HashSet<Integer> duplicates = new HashSet<>(); // 用于存储重复元素
HashSet<Integer> seen = new HashSet<>(); // 用于记录已见元素
// 查找重复元素
for (int number : numbers) {
if (!seen.add(number)) { // 如果添加失败,说明重复
duplicates.add(number); // 存储重复元素
}
}
// 输出重复元素
System.out.println("重复的元素有:" + duplicates);
}
}
代码详解
- 使用
HashSet
记录已经见过的元素和重复的元素。 - 在遍历时,尝试添加元素到
seen
中,若返回false
则表示是重复的
。
- 输出所有重复元素。
10. 题目:二维数组转置
解题思路
对一个二维数组进行转置操作并输出结果。
public class TransposeMatrix {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3},
{4, 5, 6}
}; // 定义二维数组
int[][] transposed = new int[matrix[0].length][matrix.length]; // 创建转置后的数组
// 转置操作
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
transposed[j][i] = matrix[i][j]; // 交换行列
}
}
// 输出转置后的数组
System.out.println("转置后的矩阵:");
for (int[] row : transposed) {
for (int value : row) {
System.out.print(value + " ");
}
System.out.println(); // 换行
}
}
}
代码详解
- 创建一个新的二维数组
transposed
,行和列互换。 - 嵌套循环遍历原数组并将元素放入转置数组中。
- 最后遍历输出转置后的矩阵。
28- 方法
1. 方法的定义
1.1 概念
方法是执行特定任务的代码块,通常封装了一组操作,能够接受输入并返回结果。方法可以提高代码的复用性和可读性。
1.2 方法的结构
[修饰符] 返回类型 方法名([参数类型 参数名1, 参数类型 参数名2, ...]) {
// 方法体
// return 语句(如果有返回值)
}
- 修饰符:控制访问权限,如
public
、private
、protected
等。 - 返回类型:方法返回值的类型,可以是基本类型或对象类型;如果没有返回值,使用
void
。 - 方法名:方法的名称,通常采用动词形式。
- 参数列表:方法可以接收的输入参数,多个参数用逗号分隔。
- 方法体:实际执行的代码,使用大括号包裹。
2. 方法的声明与定义
2.1 示例
public class Calculator {
// 加法方法
public int add(int a, int b) {
return a + b; // 返回和
}
// 乘法方法
public int multiply(int a, int b) {
return a * b; // 返回积
}
}
3. 方法的调用
3.1 调用实例
在main
方法中创建对象并调用其他方法。
public class Main {
public static void main(String[] args) {
Calculator calc = new Calculator(); // 创建Calculator对象
int sum = calc.add(5, 10); // 调用add方法
int product = calc.multiply(5, 10); // 调用multiply方法
System.out.println("和: " + sum);
System.out.println("积: " + product);
}
}
4. 方法的返回值
4.1 返回类型
每个方法都有一个返回类型,表示该方法执行后的返回值类型。使用return
语句返回值。
4.2 示例
public int subtract(int a, int b) {
return a - b; // 返回差
}
5. 方法的参数
5.1 参数传递
方法可以接收参数,分为基本数据类型和引用类型。
- 基本数据类型:值传递,传递的是数据的拷贝。
- 引用类型:传递的是对象的引用,可以影响原对象。
5.2 示例
public void changeValue(int num) {
num = 10; // 不会影响调用者的变量
}
public void changeArray(int[] arr) {
arr[0] = 10; // 会影响调用者的数组
}
6. 方法的重载
6.1 概念
在同一类中,可以定义多个同名的方法,只要它们的参数类型、数量或顺序不同。
6.2 示例
public class OverloadExample {
public int add(int a, int b) {
return a + b; // 整数相加
}
public double add(double a, double b) {
return a + b; // 浮点数相加
}
public int add(int a, int b, int c) {
return a + b + c; // 三个整数相加
}
}
7. 递归方法
7.1 概念
方法可以调用自身,这称为递归。递归需要一个基准条件以避免无限调用。
7.2 示例
public class Factorial {
public int factorial(int n) {
if (n == 0) {
return 1; // 基础情况
} else {
return n * factorial(n - 1); // 递归调用
}
}
}
8. 方法的访问修饰符
8.1 访问控制
- public:对所有类可见。
- private:仅对定义它的类可见。
- protected:对同一包中的类及其子类可见。
- 默认(包私有):没有修饰符,方法仅对同一包内的类可见。
9. 方法的静态与实例方法
9.1 静态方法
使用 static
关键字定义的方法属于类,可以不需要实例化对象直接调用。
9.2 示例
public class StaticExample {
public static int add(int a, int b) {
return a + b; // 静态方法
}
public static void main(String[] args) {
int sum = StaticExample.add(5, 10); // 直接调用静态方法
System.out.println("和: " + sum);
}
}
10. 方法的返回值类型
10.1 多重返回
可以通过返回不同类型的结果,例如使用对象作为返回值。
public class Person {
String name;
public Person(String name) {
this.name = name;
}
}
public Person createPerson(String name) {
return new Person(name); // 返回Person对象
}
11. 可变参数
11.1 概念
Java方法支持可变参数,使得方法可以接收可变数量的参数。
11.2 示例
public void printNumbers(int... numbers) {
for (int num : numbers) {
System.out.print(num + " ");
}
}
public static void main(String[] args) {
printNumbers(1, 2, 3, 4, 5); // 可以传入任意数量的参数
}
12. 方法的文档注释
12.1 Javadoc
可以使用/** ... */
文档注释为方法生成文档,帮助其他开发者理解方法的功能和用法。
12.2 示例
/**
* 计算两个数的和
* @param a 第一个数字
* @param b 第二个数字
* @return 两个数字的和
*/
public int add(int a, int b) {
return a + b;
}
13. 方法的异常处理
13.1 异常声明
方法可以使用 throws
声明可能抛出的异常,允许调用者处理这些异常。
13.2 示例
public int divide(int a, int b) throws ArithmeticException {
if (b == 0) {
throw new ArithmeticException("除数不能为零"); // 抛出异常
}
return a / b;
}
29- 方法综合练习
1. 计算数组的平均值
题目
编写一个方法,计算给定数组的平均值。
解题思路
遍历数组,计算所有元素的总和,然后除以元素的数量以得到平均值。
代码
public class AverageCalculator {
public double calculateAverage(int[] numbers) {
int sum = 0; // 初始化总和
for (int num : numbers) {
sum += num; // 累加每个元素
}
return (double) sum / numbers.length; // 计算并返回平均值
}
public static void main(String[] args) {
AverageCalculator calc = new AverageCalculator();
int[] nums = {10, 20, 30, 40, 50};
double average = calc.calculateAverage(nums);
System.out.println("平均值: " + average); // 输出平均值
}
}
2. 判断素数
题目
编写一个方法,判断一个数是否为素数。
解题思路
判断一个数是否只能被1和自身整除,如果能被其他数整除则不是素数。
代码
public class PrimeChecker {
public boolean isPrime(int number) {
if (number <= 1) return false; // 1及以下不是素数
for (int i = 2; i <= Math.sqrt(number); i++) {
if (number % i == 0) return false; // 找到因子则不是素数
}
return true; // 没有因子则是素数
}
public static void main(String[] args) {
PrimeChecker checker = new PrimeChecker();
int num = 29;
System.out.println(num + " 是素数吗? " + checker.isPrime(num)); // 输出结果
}
}
3. 反转字符串
题目
编写一个方法,将给定字符串反转。
解题思路
使用StringBuilder类的reverse()方法,或手动遍历字符串。
代码
public class StringReverser {
public String reverseString(String str) {
StringBuilder reversed = new StringBuilder(); // 创建StringBuilder对象
for (int i = str.length() - 1; i >= 0; i--) {
reversed.append(str.charAt(i)); // 逐个字符反转
}
return reversed.toString(); // 返回反转后的字符串
}
public static void main(String[] args) {
StringReverser reverser = new StringReverser();
String original = "Hello, World!";
String reversed = reverser.reverseString(original);
System.out.println("反转字符串: " + reversed); // 输出结果
}
}
4. 计算阶乘
题目
编写一个方法,计算给定数字的阶乘。
解题思路
使用递归方式计算阶乘,n! = n × (n-1)!。
代码
public class FactorialCalculator {
public int factorial(int n) {
if (n == 0) return 1; // 基础情况
return n * factorial(n - 1); // 递归调用
}
public static void main(String[] args) {
FactorialCalculator calc = new FactorialCalculator();
int number = 5;
int result = calc.factorial(number);
System.out.println(number + " 的阶乘是: " + result); // 输出结果
}
}
5. 查找数组中的最大值
题目
编写一个方法,查找给定数组中的最大值。
解题思路
遍历数组,比较每个元素,找到最大值。
代码
public class MaxFinder {
public int findMax(int[] numbers) {
int max = numbers[0]; // 假设第一个元素为最大值
for (int num : numbers) {
if (num > max) {
max = num; // 更新最大值
}
}
return max; // 返回最大值
}
public static void main(String[] args) {
MaxFinder finder = new MaxFinder();
int[] nums = {1, 3, 7, 0, 5};
int max = finder.findMax(nums);
System.out.println("数组中的最大值: " + max); // 输出结果
}
}
6. 统计字符出现次数
题目
编写一个方法,统计字符串中某个字符出现的次数。
解题思路
遍历字符串,使用计数器统计字符出现的次数。
代码
public class CharCounter {
public int countCharacter(String str, char ch) {
int count = 0; // 初始化计数器
for (char c : str.toCharArray()) {
if (c == ch) {
count++; // 增加计数
}
}
return count; // 返回计数结果
}
public static void main(String[] args) {
CharCounter counter = new CharCounter();
String text = "hello world";
char character = 'o';
int count = counter.countCharacter(text, character);
System.out.println(character + " 在字符串中出现的次数: " + count); // 输出结果
}
}
7. 合并两个数组
题目
编写一个方法,将两个数组合并为一个数组。
解题思路
创建一个新的数组,复制两个数组的元素到新数组中。
代码
public class ArrayMerger {
public int[] mergeArrays(int[] array1, int[] array2) {
int[] merged = new int[array1.length + array2.length]; // 创建新数组
int index = 0;
for (int num : array1) {
merged[index++] = num; // 复制第一个数组
}
for (int num : array2) {
merged[index++] = num; // 复制第二个数组
}
return merged; // 返回合并后的数组
}
public static void main(String[] args) {
ArrayMerger merger = new ArrayMerger();
int[] arr1 = {1, 2, 3};
int[] arr2 = {4, 5, 6};
int[] mergedArray = merger.mergeArrays(arr1, arr2);
System.out.print("合并后的数组: ");
for (int num : mergedArray) {
System.out.print(num + " "); // 输出合并后的数组
}
}
}
8. 字符串的字母排序
题目
编写一个方法,将字符串中的字母按字母顺序排序。
解题思路
将字符串转化为字符数组,使用排序算法对字符数组进行排序,然后转换回字符串。
代码
import java.util.Arrays;
public class StringSorter {
public String sortString(String str) {
char[] chars = str.toCharArray(); // 转换为字符数组
Arrays.sort(chars); // 排序字符数组
return new String(chars); // 返回排序后的字符串
}
public static void main(String[] args) {
StringSorter sorter = new StringSorter();
String original = "java";
String sorted = sorter.sortString(original);
System.out.println("排序后的字符串: " + sorted); // 输出结果
}
}
9. 计算Fibonacci数列
题目
编写一个方法,返回Fibonacci数列的第n项。
解题思路
使用递归或迭代的方法计算Fibonacci数列。
代码
public class FibonacciCalculator {
public int fibonacci(int n) {
if (n <= 1) return n; // 基础情况
return fibonacci(n - 1) + fibonacci(n - 2); // 递归计算
}
public static void main(String[] args) {
FibonacciCalculator calculator = new FibonacciCalculator();
int n = 6;
int result = calculator.fibonacci(n);
System.out.println("Fibonacci数列的第" + n + "项是: " + result); // 输出结果
}
}
10. 检查回文
题目
编写一个方法,检查给定字符串是否为回文。
解题思路
将字符串反转并与原字符串比较,如果相同则为回文。
代码
public class PalindromeChecker {
public boolean isPalindrome(String str) {
String reversed = new StringBuilder(str).reverse().toString(); // 反转字符串
return str.equals(reversed); // 比较原字符串与反转字符串
}
public static void main(String[] args) {
PalindromeChecker checker = new PalindromeChecker();
String word = "level";
boolean result = checker.isPalindrome(word);
System.out.println(word + " 是回文吗? " + result); // 输出结果
}
}
30- 面向对象
1. 面向对象概述
1.1 概念
面向对象编程是一种程序设计范式,它使用“对象”来封装数据和操作。OOP的核心思想是将软件设计为互相协作的对象,而不是单一的功能或过程。
2. 类与对象
2.1 类的定义
类是对象的蓝图或模板,定义了对象的属性(字段)和行为(方法)。
2.2 创建类的基本语法
public class ClassName {
// 属性(字段)
private int field;
// 方法
public void method() {
// 方法体
}
}
2.3 对象的创建
使用new
关键字来创建类的实例(对象)。
ClassName obj = new ClassName(); // 创建对象
2.4 示例
public class Car {
private String model; // 属性
public Car(String model) { // 构造方法
this.model = model;
}
public void displayModel() { // 方法
System.out.println("车型: " + model);
}
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car("Toyota"); // 创建对象
myCar.displayModel(); // 调用方法
}
}
3. 封装
3.1 概念
封装是将数据(属性)和操作数据的方法(行为)结合在一起,并隐藏内部实现的细节,保护对象的状态。
3.2 访问修饰符
- private:仅在类内部可见。
- public:对所有类可见。
- protected:对同一包及子类可见。
3.3 示例
public class Account {
private double balance; // 封装属性
public void deposit(double amount) { // 方法
if (amount > 0) {
balance += amount;
}
}
public double getBalance() { // 获取余额
return balance;
}
}
4. 继承
4.1 概念
继承是一种机制,允许一个类(子类)继承另一个类(父类)的属性和方法,促进代码复用。
4.2 语法
public class ParentClass {
// 父类的属性和方法
}
public class ChildClass extends ParentClass {
// 子类的属性和方法
}
4.3 示例
public class Animal {
public void sound() {
System.out.println("动物发声");
}
}
public class Dog extends Animal {
@Override
public void sound() { // 重写父类方法
System.out.println("狗叫: 汪汪");
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.sound(); // 调用重写的方法
}
}
5. 多态
5.1 概念
多态是同一操作在不同对象上的不同表现形式。它可以通过方法重载和方法重写来实现。
5.2 方法重载
在同一类中定义多个同名但参数不同的方法。
5.3 方法重写
子类重写父类的方法。
5.4 示例
public class Shape {
public void draw() {
System.out.println("绘制形状");
}
}
public class Circle extends Shape {
@Override
public void draw() { // 重写方法
System.out.println("绘制圆形");
}
}
public class Main {
public static void main(String[] args) {
Shape shape = new Circle(); // 父类引用指向子类对象
shape.draw(); // 调用子类的方法
}
}
6. 抽象
6.1 概念
抽象是隐藏复杂性,仅暴露必要的部分。抽象类不能实例化,只能由子类继承。
6.2 抽象类和抽象方法
使用abstract
关键字定义抽象类和抽象方法。
6.3 示例
abstract class Animal {
public abstract void sound(); // 抽象方法
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("猫叫: 喵喵");
}
}
public class Main {
public static void main(String[] args) {
Animal myCat = new Cat(); // 创建子类对象
myCat.sound(); // 调用重写的方法
}
}
7. 接口
7.1 概念
接口是一种特殊的抽象类,定义了一组方法,但没有具体实现。类通过实现接口来提供具体行为。
7.2 定义接口
使用interface
关键字定义接口。
7.3 示例
interface Animal {
void sound(); // 接口方法
}
class Cow implements Animal {
@Override
public void sound() {
System.out.println("牛叫: 哞哞");
}
}
public class Main {
public static void main(String[] args) {
Animal myCow = new Cow(); // 实现接口
myCow.sound(); // 调用方法
}
}
31- 面向对象-封装
1. 封装的概念
封装是面向对象编程(OOP)的一种特性,它将数据(属性)和对数据的操作(方法)组合成一个整体(类),并通过访问修饰符控制外部对这些数据的访问。封装的核心目的是保护对象的状态和实现细节,只暴露必要的接口给外部使用。
2. 封装的实现细节
2.1 属性(字段)定义
- 使用private修饰符定义类的属性,使得这些属性无法被外部类直接访问。
private int age; // 私有属性,外部无法直接访问
2.2 构造方法
- 构造方法用于初始化对象的属性。可以在构造方法中进行参数验证,确保对象的状态合法。
public Person(int age) {
if (age > 0) {
this.age = age; // 合法的年龄
} else {
this.age = 0; // 非法的年龄,设置为0
}
}
2.3 Getter和Setter方法
- Getter方法用于获取私有属性的值,返回属性的当前值。
public int getAge() {
return age; // 返回年龄
}
- Setter方法用于设置私有属性的值,可以在设置过程中进行额外的验证逻辑。
public void setAge(int age) {
if (age > 0) {
this.age = age; // 设置合法年龄
} else {
System.out.println("年龄无效");
}
}
3. 封装的优缺点
3.1 优点
- 数据保护:封装可以隐藏对象的内部状态,防止外部直接修改,从而保证数据的一致性和完整性。
- 控制访问:通过访问修饰符,可以精确控制哪些类可以访问对象的属性和方法。
- 易于维护:内部实现细节的改变不会影响使用该类的代码,便于维护和升级。
- 提高代码的可读性:封装使得代码结构更加清晰,方便理解和使用。
3.2 缺点
- 性能开销:由于需要额外的方法来访问和修改属性,可能会引入一些性能开销,但一般来说影响很小。
- 增加复杂性:对于简单的类,使用封装可能会让代码显得冗长和复杂。
4. 示例
下面是一个更详细的封装示例,展示了封装如何在实际应用中保护数据和控制访问。
public class BankAccount {
private double balance; // 私有属性,账户余额
// 构造方法,初始化余额
public BankAccount(double initialBalance) {
if (initialBalance >= 0) {
balance = initialBalance;
} else {
balance = 0; // 负余额设置为0
}
}
// Getter方法:获取当前余额
public double getBalance() {
return balance; // 返回余额
}
// Setter方法:存款
public void deposit(double amount) {
if (amount > 0) {
balance += amount; // 增加余额
} else {
System.out.println("存款金额无效");
}
}
// 方法:取款
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount; // 减少余额
} else {
System.out.println("取款失败:余额不足或无效金额");
}
}
// 方法:打印账户信息
public void printAccountInfo() {
System.out.println("当前余额: " + balance);
}
}
public class Main {
public static void main(String[] args) {
BankAccount myAccount = new BankAccount(1000); // 创建账户
myAccount.printAccountInfo(); // 输出当前余额
myAccount.deposit(500); // 存款
myAccount.printAccountInfo(); // 输出余额
myAccount.withdraw(200); // 取款
myAccount.printAccountInfo(); // 输出余额
myAccount.withdraw(1500); // 尝试取款超过余额
myAccount.deposit(-100); // 尝试存入无效金额
}
}
5. 示例解释
- 私有属性:
balance
是一个私有属性,外部无法直接访问,保证了账户余额的安全性。 - 构造方法:在创建对象时,构造方法验证初始余额是否合法。
- Getter和Setter:提供
getBalance()
和deposit(double amount)
方法,允许外部获取和更新余额,同时在更新时进行验证。 - 方法:
withdraw(double amount)
方法实现取款逻辑,确保取款金额不超过当前余额。
6. 封装的使用场景
- 用户管理:在用户类中封装用户的个人信息,保护敏感数据。
- 财务系统:在银行账户类中封装账户信息,防止外部程序直接修改余额。
- 配置管理:在配置类中封装应用程序配置,允许安全的访问和修改。
32- 权限访问控制
1. 访问修饰符概述
Java中的访问修饰符用于控制类、方法和变量的可见性。主要有四种修饰符:
- public:公共,任何类都可以访问。
- protected:受保护,子类和同一包中的其他类可以访问。
- private:私有,仅在定义它的类内部可访问。
- 默认(无修饰符):包私有,仅在同一包中的类可访问。
2. 详细说明及示例
2.1 public
- 可见性:任何其他类都可以访问。
public class PublicClass {
public int publicField; // 公共字段
public void publicMethod() { // 公共方法
System.out.println("这是公共方法");
}
}
使用示例:
public class Main {
public static void main(String[] args) {
PublicClass obj = new PublicClass();
obj.publicField = 10; // 访问公共字段
obj.publicMethod(); // 调用公共方法
}
}
2.2 protected
- 可见性:同一包中的其他类和任何子类都可以访问。
public class ProtectedClass {
protected int protectedField; // 受保护字段
protected void protectedMethod() { // 受保护方法
System.out.println("这是受保护的方法");
}
}
使用示例:
class SubClass extends ProtectedClass { // 子类
public void display() {
protectedField = 20; // 访问受保护字段
protectedMethod(); // 调用受保护方法
}
}
public class Main {
public static void main(String[] args) {
SubClass obj = new SubClass();
obj.display(); // 调用子类的方法
}
}
2.3 private
- 可见性:仅在定义它的类内部可访问,外部类无法访问。
public class PrivateClass {
private int privateField; // 私有字段
private void privateMethod() { // 私有方法
System.out.println("这是私有的方法");
}
public void accessPrivate() { // 公共方法访问私有成员
privateField = 30; // 访问私有字段
privateMethod(); // 调用私有方法
}
}
使用示例:
public class Main {
public static void main(String[] args) {
PrivateClass obj = new PrivateClass();
// obj.privateField = 40; // 不能访问,编译错误
obj.accessPrivate(); // 调用公共方法,间接访问私有成员
}
}
2.4 默认(无修饰符)
- 可见性:仅在同一包中的类可访问。
class DefaultClass { // 默认类
int defaultField; // 默认字段
void defaultMethod() { // 默认方法
System.out.println("这是默认的方法");
}
}
使用示例:
public class Main {
public static void main(String[] args) {
DefaultClass obj = new DefaultClass();
obj.defaultField = 50; // 访问默认字段
obj.defaultMethod(); // 调用默认方法
}
}
3. 访问修饰符之间的区别总结
修饰符 | 同一包 | 子类 | 其他包 | 可见性 |
---|---|---|---|---|
public | 是 | 是 | 是 | 任何地方可见 |
protected | 是 | 是 | 否 | 同包和子类可见 |
private | 否 | 否 | 否 | 仅限当前类可见 |
默认 | 是 | 否 | 否 | 仅限同包可见 |
33- 面向对象--继承
1. 继承的定义
继承是面向对象编程(OOP)中的一个基本概念,它允许一个类(称为子类或派生类)从另一个类(称为父类或基类)获取属性和方法。通过继承,子类可以重用父类的代码,同时可以增加自己独特的属性和方法。
2. 继承的类型
在Java中,继承主要有两种类型:
2.1 单继承
单继承指的是一个子类只能继承一个父类。Java中不支持多重继承,即一个类不能有多个直接父类。这是为了避免“菱形继承”问题,保证代码的清晰性和可维护性。
class Parent {
// 父类代码
}
class Child extends Parent {
// 子类代码
}
2.2 多层继承
多层继承指的是子类可以从父类继承,同时可以作为另一个类的父类,形成一个继承层次结构。
class Grandparent {
// 祖父类代码
}
class Parent extends Grandparent {
// 父类代码
}
class Child extends Parent {
// 子类代码
}
3. 继承的实现
在Java中,使用extends
关键字来实现继承。子类会自动继承父类的公共和受保护的成员,但不能继承父类的私有成员。
3.1 基本语法
class Parent {
int parentField; // 父类字段
void parentMethod() {
System.out.println("父类的方法");
}
}
class Child extends Parent {
int childField; // 子类字段
void childMethod() {
System.out.println("子类的方法");
}
}
4. 方法重写
4.1 方法重写的概念
方法重写是指子类对父类已有的方法进行重新定义,以提供特定的实现。在重写时,子类的方法必须与父类的方法签名相同(方法名、参数类型、参数个数)。
4.2 使用@Override
注解
使用@Override
注解可以让编译器帮助检查是否正确重写了父类的方法。如果重写方法的签名不匹配,编译器会报错。
class Parent {
void display() {
System.out.println("父类显示");
}
}
class Child extends Parent {
@Override
void display() {
System.out.println("子类显示");
}
}
5. 多态
多态是指同一个方法在不同对象上的不同实现。通过继承和方法重写,可以实现多态。多态有两种类型:
5.1 编译时多态(方法重载)
同一类中可以有多个同名但参数不同的方法,称为方法重载。
class MathUtil {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
5.2 运行时多态(方法重写)
通过父类引用指向子类对象,调用被重写的方法时,运行时将根据对象的实际类型决定调用哪个方法。
Parent obj = new Child();
obj.display(); // 调用的是子类的方法
6. 示例代码
以下是一个详细的示例,展示了继承、方法重写和多态的实现。
// 父类
class Animal {
void eat() {
System.out.println("动物在吃食物");
}
}
// 子类
class Dog extends Animal {
@Override
void eat() {
System.out.println("狗在吃狗粮");
}
void bark() {
System.out.println("狗在叫");
}
}
class Cat extends Animal {
@Override
void eat() {
System.out.println("猫在吃鱼");
}
void meow() {
System.out.println("猫在叫");
}
}
// 主类
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // 向上转型
Animal myCat = new Cat(); // 向上转型
myDog.eat(); // 输出: 狗在吃狗粮
myCat.eat(); // 输出: 猫在吃鱼
// 由于多态,不能直接调用子类特有方法
// myDog.bark(); // 错误,编译不通过
}
}
7. 注意事项
- 单继承限制:Java不支持多继承,但可以通过接口实现多重类型。
- 构造方法:子类构造方法默认调用父类的无参构造方法。如果父类没有无参构造,则必须在子类构造方法中显式调用父类构造方法。
- 方法重写规则:
- 子类重写父类方法时,访问权限不能更严格。
- 不能重写父类的
final
方法和static
方法。
- 成员变量的隐藏:子类可以定义与父类同名的字段,但这不是重写,而是隐藏。
8. 应用场景
- 代码复用:使用继承可以减少代码的重复,尤其在类之间有共通功能时。
- 层次结构建模:在建模现实世界中的对象时,继承可以帮助组织类之间的关系,如动物、车辆等。
- 实现多态:通过继承和方法重写,可以实现不同对象对同一消息的响应,增强程序的灵活性。
34-面向对象--多态
1. 多态的定义
多态是面向对象编程(OOP)中的一个核心概念,它指的是同一个操作(方法)在不同对象上可以表现出不同的行为。换句话说,多态允许对象以父类的类型进行引用,但在运行时调用的是子类的实现。
2. 多态的类型
Java中的多态主要有两种类型:
2.1 编译时多态(方法重载)
同一类中可以定义多个同名但参数列表不同的方法,这称为方法重载。编译器在编译时根据方法的参数类型和数量来决定调用哪个方法。
class MathUtil {
// 重载方法:不同参数类型
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}
2.2 运行时多态(方法重写)
运行时多态是通过父类引用指向子类对象,调用被重写的方法,具体调用哪个方法是在运行时决定的。
class Animal {
void makeSound() {
System.out.println("动物在发出声音");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("狗在叫");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("猫在喵");
}
}
3. 多态的实现
多态主要依赖于方法重写和向上转型(将子类对象赋值给父类引用)。以下是多态的实现步骤:
- 父类定义方法:在父类中定义一个方法。
- 子类重写方法:在子类中重写该方法。
- 父类引用指向子类对象:使用父类类型的引用指向子类对象。
- 调用重写方法:通过父类引用调用方法,运行时将根据对象的实际类型执行相应的方法。
4. 示例代码
4.1 多态基本示例
class Animal {
void makeSound() {
System.out.println("动物在发出声音");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("狗在叫");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("猫在喵");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // 向上转型
Animal myCat = new Cat(); // 向上转型
myDog.makeSound(); // 输出: 狗在叫
myCat.makeSound(); // 输出: 猫在喵
}
}
4.2 多态的应用场景
在实际应用中,多态常用于处理一组相关的对象时,可以通过父类引用来统一管理。
class Shape {
void draw() {
System.out.println("绘制形状");
}
}
class Circle extends Shape {
@Override
void draw() {
System.out.println("绘制圆形");
}
}
class Rectangle extends Shape {
@Override
void draw() {
System.out.println("绘制矩形");
}
}
public class DrawingApp {
public static void main(String[] args) {
Shape[] shapes = new Shape[2];
shapes[0] = new Circle(); // 向上转型
shapes[1] = new Rectangle(); // 向上转型
for (Shape shape : shapes) {
shape.draw(); // 根据实际类型调用相应的方法
}
}
}
5. 多态的优点
- 灵活性:通过多态,可以在运行时决定调用哪个方法,增强了程序的灵活性。
- 可维护性:可以通过父类统一管理子类,简化代码的维护和扩展。
- 解耦性:调用者不需要知道具体实现,只需知道接口或父类,降低了模块之间的耦合度。
6. 多态的注意事项
- 方法重写:子类必须重写父类的方法,且方法名、参数类型和返回值类型必须一致。
- 类型转换:向下转型(将父类引用转为子类引用)时,必须确保对象实际为子类类型,否则会抛出
ClassCastException
。
Animal animal = new Dog();
Dog dog = (Dog) animal; // 向下转型,安全
7. 多态的应用场景
- 图形处理:如上面示例,处理各种图形时,可以将不同图形对象存储在同一数组中,使用相同的接口进行操作。
- 事件处理:在GUI编程中,处理不同事件的回调方法可以使用多态。
- 插件系统:可以通过接口定义插件的标准,具体实现则通过多态进行管理。
35- 面向对象--抽象类
1. 抽象类的定义
抽象类是指包含一个或多个抽象方法(没有实现的方法)的类。抽象类不能被实例化,通常用作其他类的基类。它允许子类实现其方法,从而提供具体的功能。
2. 抽象类的特点
- 不能实例化:抽象类不能创建对象,只能被子类继承。
- 可以包含抽象方法和具体方法:抽象类可以包含没有实现的抽象方法,也可以包含已经实现的方法。
- 构造方法:抽象类可以有构造方法,子类可以通过调用父类构造方法来初始化父类的属性。
- 访问修饰符:抽象方法可以有不同的访问修饰符(如
public
、protected
、private
),但通常是public
或protected
。
3. 抽象类的语法
使用abstract
关键字定义抽象类和抽象方法。
abstract class Animal {
// 抽象方法
abstract void makeSound();
// 具体方法
void eat() {
System.out.println("动物在吃食物");
}
}
4. 抽象类的使用
4.1 定义抽象类
定义一个抽象类时,可以包含多个抽象方法和具体方法。
abstract class Shape {
// 抽象方法
abstract void draw();
// 具体方法
void display() {
System.out.println("这是一个形状");
}
}
4.2 继承抽象类
子类需要实现抽象类中的所有抽象方法,否则子类也必须声明为抽象类。
class Circle extends Shape {
@Override
void draw() {
System.out.println("绘制圆形");
}
}
class Rectangle extends Shape {
@Override
void draw() {
System.out.println("绘制矩形");
}
}
5. 示例代码
以下是一个完整的示例,展示了如何使用抽象类。
// 抽象类
abstract class Animal {
abstract void makeSound(); // 抽象方法
void eat() { // 具体方法
System.out.println("动物在吃食物");
}
}
// 子类
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("狗在叫");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("猫在喵");
}
}
// 主类
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // 向上转型
Animal myCat = new Cat(); // 向上转型
myDog.makeSound(); // 输出: 狗在叫
myCat.makeSound(); // 输出: 猫在喵
myDog.eat(); // 输出: 动物在吃食物
myCat.eat(); // 输出: 动物在吃食物
}
}
5.1 示例解释
- 抽象类Animal:定义了一个抽象方法
makeSound
和一个具体方法eat
。 - 子类Dog和Cat:分别实现了
makeSound
方法,提供各自的声音。 - Main类:创建了
Animal
类型的引用指向Dog
和Cat
对象,并调用相关方法。
6. 抽象类与接口的区别
特点 | 抽象类 | 接口 |
---|---|---|
关键字 | abstract | interface |
方法实现 | 可以有抽象方法和具体方法 | 只能有抽象方法(Java 8及以后的版本可以有默认和静态方法) |
构造方法 | 可以有构造方法 | 不能有构造方法 |
访问修饰符 | 可以有访问修饰符 | 默认是public |
继承关系 | 单继承 | 多重继承(一个类可以实现多个接口) |
7. 抽象类的使用场景
- 框架设计:抽象类适用于定义框架中的基本行为,允许子类实现特定的功能。
- 共享代码:在多个子类之间共享相同的代码实现,提高代码复用性。
- 统一接口:为一组相关类提供统一的接口,确保子类遵循相同的设计。
8. 注意事项
- 抽象类不能被实例化:尝试创建抽象类的对象将导致编译错误。
- 子类必须实现抽象方法:如果子类不实现所有的抽象方法,则子类也必须声明为抽象类。
- 可以有非抽象方法:抽象类可以包含非抽象方法,子类可以选择重写这些方法。
- 可以有字段:抽象类可以包含字段,子类可以访问和修改这些字段。
36- 面向对象--接口
1. 接口的定义
接口是Java中的一种引用数据类型,类似于类,但接口只能包含常量、方法的声明(没有方法体)和静态方法。接口定义了一组方法,但不提供具体的实现。类通过实现接口来提供这些方法的具体实现。
2. 接口的特点
- 方法声明:接口中的方法默认是
public
和abstract
,不需要显式声明。 - 常量:接口可以包含常量,默认是
public static final
。 - 多重继承:一个类可以实现多个接口,从而支持多重继承的特性。
- 无法实例化:接口不能被实例化,无法创建接口类型的对象。
- 默认和静态方法:从Java 8开始,接口可以包含默认方法和静态方法。
3. 接口的语法
定义接口时使用interface
关键字。
interface Animal {
// 常量
int LEGS = 4;
// 抽象方法
void makeSound();
void eat();
}
4. 接口的实现
4.1 实现接口
一个类通过实现接口来提供具体的方法实现。使用implements
关键字。
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("狗在叫");
}
@Override
public void eat() {
System.out.println("狗在吃狗粮");
}
}
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("猫在喵");
}
@Override
public void eat() {
System.out.println("猫在吃鱼");
}
}
5. 示例代码
以下是一个完整的示例,展示了如何使用接口。
// 接口定义
interface Animal {
void makeSound(); // 抽象方法
void eat(); // 抽象方法
}
// Dog类实现Animal接口
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("狗在叫");
}
@Override
public void eat() {
System.out.println("狗在吃狗粮");
}
}
// Cat类实现Animal接口
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("猫在喵");
}
@Override
public void eat() {
System.out.println("猫在吃鱼");
}
}
// 主类
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // 向上转型
Animal myCat = new Cat(); // 向上转型
myDog.makeSound(); // 输出: 狗在叫
myDog.eat(); // 输出: 狗在吃狗粮
myCat.makeSound(); // 输出: 猫在喵
myCat.eat(); // 输出: 猫在吃鱼
}
}
6. 接口的优点
- 多重继承:允许一个类实现多个接口,解决了Java不支持多重继承的问题。
- 统一接口:提供了一种标准化的方式来定义类的行为,增强了代码的可读性和可维护性。
- 松耦合:接口使得实现类和使用类之间的耦合度降低,可以通过接口引用来使用不同的实现。
7. 接口的使用场景
- 回调机制:在Java中常用于实现事件监听器,如Swing和JavaFX的事件处理。
- 插件系统:可以定义接口供不同的插件实现,从而实现可扩展的系统。
- 统一 API:用于定义标准 API,多个类可以实现同一接口,提供一致的行为。
8. 注意事项
- 必须实现所有方法:类在实现接口时必须实现接口中的所有抽象方法,除非该类本身是抽象类。
- 可以实现多个接口:一个类可以实现多个接口,接口之间使用逗号分隔。
class MultiAnimal implements Animal, AnotherInterface {
// 实现所有抽象方法
}
- 默认方法:从Java 8开始,接口可以定义默认方法,使用
default
关键字。
interface Animal {
default void sleep() {
System.out.println("动物在睡觉");
}
}
- 静态方法:接口也可以定义静态方法,这些方法不能被实现类重写。
interface Utility {
static void printMessage() {
System.out.println("静态方法");
}
}
9. 抽象类与接口的比较
特点 | 抽象类 | 接口 |
---|---|---|
关键字 | abstract | interface |
方法实现 | 可以有抽象方法和具体方法 | 只能有抽象方法(Java 8及以后的版本可以有默认和静态方法) |
构造方法 | 可以有构造方法 | 不能有构造方法 |
访问修饰符 | 可以有访问修饰符 | 默认是public |
继承关系 | 单继承 | 多重继承(一个类可以实现多个接口) |
37- 面向对象综合案例
案例 1:动物管理系统
题目
设计一个动物管理系统,其中包含不同类型的动物(如狗和猫),每种动物都有特定的行为和属性。实现动物的声音、进食方式和玩耍方式。
解题思路
- 抽象类:定义一个抽象类
Animal
,包含动物的通用属性和方法。 - 接口:定义一个接口
Pet
,用于描述宠物特有的行为,例如玩耍。 - 具体实现类:为每种动物(如
Dog
和Cat
)创建具体类,继承自Animal
,并实现Pet
接口。 - 多态:使用多态特性,通过父类引用指向子类对象,调用相应的方法。
代码
// 抽象类
abstract class Animal {
String name; // 动物的名称
int age; // 动物的年龄
// 构造函数
Animal(String name, int age) {
this.name = name;
this.age = age;
}
// 抽象方法,必须被子类实现
abstract void makeSound();
abstract void eat();
}
// 接口
interface Pet {
void play(); // 接口方法,用于描述玩耍行为
}
// Dog类
class Dog extends Animal implements Pet {
// Dog类构造函数
Dog(String name, int age) {
super(name, age);
}
@Override
void makeSound() {
System.out.println(name + " (狗) 在叫: 汪汪");
}
@Override
void eat() {
System.out.println(name + " (狗) 在吃狗粮");
}
@Override
public void play() {
System.out.println(name + " (狗) 在玩球");
}
}
// Cat类
class Cat extends Animal implements Pet {
// Cat类构造函数
Cat(String name, int age) {
super(name, age);
}
@Override
void makeSound() {
System.out.println(name + " (猫) 在喵: 喵喵");
}
@Override
void eat() {
System.out.println(name + " (猫) 在吃鱼");
}
@Override
public void play() {
System.out.println(name + " (猫) 在玩毛线球");
}
}
// 主类
public class AnimalManagement {
public static void main(String[] args) {
// 创建狗和猫对象
Animal myDog = new Dog("Buddy", 3);
Animal myCat = new Cat("Whiskers", 2);
// 通过多态调用方法
myDog.makeSound();
myDog.eat();
((Pet) myDog).play(); // 强制类型转换调用接口方法
myCat.makeSound();
myCat.eat();
((Pet) myCat).play(); // 强制类型转换调用接口方法
}
}
代码解释
Animal
是一个抽象类,包含动物的基本属性(如名称和年龄)和抽象方法(makeSound
和eat
)。Pet
接口定义了一个play
方法,用于描述宠物的行为。Dog
和Cat
类实现了Animal
类,并实现了Pet
接口,提供具体的行为实现。- 在
AnimalManagement
类中,通过多态的方式创建了不同的动物对象,并调用了它们的行为,展示了接口和抽象类的使用。
案例 2:图形绘制系统
题目
设计一个图形绘制系统,支持多种形状(如圆形和矩形)的绘制,要求使用多态和接口来处理不同形状的绘制行为。
解题思路
- 抽象类:定义一个抽象类
Shape
,包含绘制方法。 - 具体形状类:为每种形状(如
Circle
和Rectangle
)创建具体类,继承自Shape
。 - 多态:使用
Shape
类型的数组存储不同形状对象,通过循环遍历调用各自的绘制方法。
代码
// 抽象类
abstract class Shape {
abstract void draw(); // 抽象方法,绘制形状
}
// Circle类
class Circle extends Shape {
@Override
void draw() {
System.out.println("绘制圆形");
}
}
// Rectangle类
class Rectangle extends Shape {
@Override
void draw() {
System.out.println("绘制矩形");
}
}
// 主类
public class DrawingApp {
public static void main(String[] args) {
Shape[] shapes = { new Circle(), new Rectangle() }; // 创建形状数组
for (Shape shape : shapes) {
shape.draw(); // 动态绑定,调用各自的draw方法
}
}
}
代码解释
Shape
是一个抽象类,定义了一个抽象方法draw
,用于绘制形状。Circle
和Rectangle
类分别实现了draw
方法,提供具体的绘制行为。- 在
DrawingApp
类中,创建了一个Shape
数组存储不同形状对象,并使用增强的for
循环遍历调用draw
方法,展示多态的特性。
案例 3:车辆管理系统
题目
设计一个车辆管理系统,支持不同类型的车辆(如汽车和电动车),并展示其启动和充电行为。
解题思路
- 抽象类:定义一个抽象类
Vehicle
,包含车辆的基本属性和行为。 - 接口:定义一个接口
Electric
,描述电动车的充电行为。 - 具体实现类:创建不同车辆类(如
Car
和ElectricBike
)继承自Vehicle
,并实现Electric
接口。
代码
// 抽象类
abstract class Vehicle {
String model; // 车辆型号
Vehicle(String model) {
this.model = model; // 初始化型号
}
abstract void start(); // 抽象方法,启动车辆
}
// 接口
interface Electric {
void charge(); // 接口方法,充电
}
// Car类
class Car extends Vehicle {
Car(String model) {
super(model); // 调用父类构造函数
}
@Override
void start() {
System.out.println(model + " 汽车启动");
}
}
// ElectricBike类
class ElectricBike extends Vehicle implements Electric {
ElectricBike(String model) {
super(model); // 调用父类构造函数
}
@Override
void start() {
System.out.println(model + " 电动自行车启动");
}
@Override
public void charge() {
System.out.println(model + " 正在充电");
}
}
// 主类
public class VehicleManagement {
public static void main(String[] args) {
Vehicle myCar = new Car("奔驰"); // 创建汽车对象
Vehicle myBike = new ElectricBike("小米电动车"); // 创建电动车对象
myCar.start(); // 启动汽车
myBike.start(); // 启动电动车
((Electric) myBike).charge(); // 调用充电方法
}
}
代码解释
Vehicle
是一个抽象类,定义了model
属性和start
抽象方法。Electric
接口定义了charge
方法,描述电动车的充电行为。Car
和ElectricBike
类分别实现了start
方法,ElectricBike
实现了Electric
接口。- 在
VehicleManagement
类中,通过多态创建了不同类型的车辆对象,并调用相应的行为。
案例 4:在线支付系统
题目
设计一个在线支付系统,支持不同的支付方式(如信用卡和PayPal),通过接口定义支付行为。
解题思路
- 接口:定义一个接口
Payment
,描述支付行为。 - 具体实现类:创建不同的支付方式(如
CreditCard
和PayPal
)实现Payment
接口。 - 多态:使用
Payment
类型的变量指向不同的支付实现。
代码
// 接口
interface Payment {
void pay(double amount); // 接口方法,支付
}
// CreditCard类
class CreditCard implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用信用卡支付: " + amount + "元");
}
}
// PayPal类
class PayPal implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用PayPal支付: " + amount + "元");
}
}
// 主类
public class PaymentSystem {
public static void main(String[] args) {
Payment myPayment; // 定义Payment
类型的变量
myPayment = new CreditCard(); // 赋值为信用卡支付
myPayment.pay(100.0); // 使用信用卡支付
myPayment = new PayPal(); // 赋值为PayPal支付
myPayment.pay(150.0); // 使用PayPal支付
}
}
代码解释
Payment
接口定义了一个pay
方法,用于实现支付行为。CreditCard
和PayPal
类实现了Payment
接口,提供了各自的支付实现。- 在
PaymentSystem
类中,通过多态的方式创建支付对象,并调用pay
方法,展示了不同支付方式的灵活性。
案例 5:学生管理系统
题目
设计一个学生管理系统,支持本科生和研究生的管理,展示学习和毕业行为。
解题思路
- 抽象类:定义一个抽象类
Student
,描述学生的基本信息和行为。 - 接口:定义一个接口
Graduatable
,描述毕业生的行为。 - 具体实现类:创建本科生类
Undergraduate
和研究生类Graduate
,继承自Student
,实现Graduatable
接口。
代码
// 抽象类
abstract class Student {
String name; // 学生姓名
Student(String name) {
this.name = name; // 初始化姓名
}
abstract void study(); // 抽象方法,学习
}
// 接口
interface Graduatable {
void graduate(); // 接口方法,毕业
}
// Undergraduate类
class Undergraduate extends Student {
Undergraduate(String name) {
super(name); // 调用父类构造函数
}
@Override
void study() {
System.out.println(name + " 在学习本科课程");
}
}
// Graduate类
class Graduate extends Student implements Graduatable {
Graduate(String name) {
super(name); // 调用父类构造函数
}
@Override
void study() {
System.out.println(name + " 在研究生阶段学习");
}
@Override
public void graduate() {
System.out.println(name + " 已经毕业");
}
}
// 主类
public class StudentManagement {
public static void main(String[] args) {
Student undergrad = new Undergraduate("Alice"); // 创建本科生对象
Student grad = new Graduate("Bob"); // 创建研究生对象
undergrad.study(); // 调用学习方法
grad.study(); // 调用学习方法
((Graduatable) grad).graduate(); // 调用毕业方法
}
}
代码解释
Student
是一个抽象类,定义了name
属性和study
抽象方法。Graduatable
接口定义了graduate
方法,描述毕业生的行为。Undergraduate
和Graduate
类实现了相应的方法。- 在
StudentManagement
类中,通过多态创建不同类型的学生对象,并调用学习和毕业的行为。
38- 字符串String
1. 什么是字符串(String)
字符串是用于存储文本的数据类型。在Java中,字符串是一个对象,表示字符的序列。Java的String
类提供了多种方法来操作这些字符。
2. 字符串的特性
2.1 不可变性(Immutable)
- 在Java中,字符串对象是不可变的。一旦创建,字符串的内容不能被改变。如果对字符串进行任何操作(例如连接、截取),都会返回一个新的字符串对象,而不是修改原有字符串。
2.2 字符串池
- Java使用字符串池来提高内存的使用效率。当你创建字符串字面量时,JVM会首先检查字符串池中是否存在相同的字符串,如果存在,返回该字符串的引用,否则将该字符串放入池中。
3. 字符串的创建
3.1 字面量方式
String str1 = "Hello, World!";
- 使用双引号创建字符串字面量,存储在字符串池中。
3.2 使用new
关键字
String str2 = new String("Hello, World!");
- 使用
new
关键字创建字符串对象,会在堆内存中创建一个新的字符串对象,即使字符串池中已经存在相同的字符串。
4. 常用字符串方法
4.1 获取字符串长度
int length = str1.length();
- 返回字符串的字符数。
4.2 字符串连接
String str3 = str1 + " How are you?";
- 使用
+
运算符连接字符串。
4.3 截取字符串
String subStr = str1.substring(0, 5); // "Hello"
substring(int beginIndex, int endIndex)
方法返回指定范围内的子字符串。
4.4 查找字符或子字符串
int index = str1.indexOf("World"); // 7
indexOf(String str)
方法返回指定子字符串的首次出现位置。
4.5 字符串替换
String replaced = str1.replace("World", "Java"); // "Hello, Java!"
replace(String oldChar, String newChar)
方法返回一个新的字符串,替换所有出现的字符。
4.6 字符串转换
String upperCase = str1.toUpperCase(); // "HELLO, WORLD!"
toUpperCase()
和toLowerCase()
方法分别将字符串转换为大写和小写。
5. 字符串的比较
5.1 使用equals()
boolean isEqual = str1.equals(str2); // false
equals(Object obj)
方法比较字符串内容是否相同。
5.2 使用==
boolean isSameReference = (str1 == str2); // false
- 使用
==
比较两个字符串对象的引用是否相同。
5.3 忽略大小写比较
boolean isEqualIgnoreCase = str1.equalsIgnoreCase("hello, world!"); // true
equalsIgnoreCase(String anotherString)
方法比较两个字符串内容是否相同,忽略大小写。
6. 字符串的遍历
可以使用循环遍历字符串的每个字符:
for (int i = 0; i < str1.length(); i++) {
char c = str1.charAt(i); // 获取每个字符
System.out.print(c + " "); // 输出每个字符
}
7. 字符串的常见问题
7.1 字符串的拼接效率
- 在频繁拼接字符串时,建议使用
StringBuilder
或StringBuffer
,因为它们是可变的,能够提高性能。
8. 代码示例
下面是一个综合示例,展示字符串的各种操作:
public class StringExample {
public static void main(String[] args) {
String str1 = "Hello, World!";
String str2 = new String("Hello, World!");
// 获取长度
System.out.println("Length: " + str1.length());
// 字符串连接
String str3 = str1 + " How are you?";
System.out.println("Concatenated: " + str3);
// 截取字符串
String subStr = str1.substring(0, 5);
System.out.println("Substring: " + subStr);
// 查找
int index = str1.indexOf("World");
System.out.println("Index of 'World': " + index);
// 替换
String replaced = str1.replace("World", "Java");
System.out.println("Replaced: " + replaced);
// 转换大小写
System.out.println("Uppercase: " + str1.toUpperCase());
// 字符串比较
System.out.println("Equals: " + str1.equals(str2));
System.out.println("Reference Equals: " + (str1 == str2));
System.out.println("Ignore Case Equals: " + str1.equalsIgnoreCase("hello, world!"));
// 遍历字符串
System.out.print("Characters: ");
for (int i = 0; i < str1.length(); i++) {
System.out.print(str1.charAt(i) + " ");
}
}
}
39- 字符串综合练习
练习 1:反转字符串
题目
编写一个方法,反转给定的字符串。
解题思路
- 使用循环或
StringBuilder
来反转字符串。
代码
public class ReverseString {
public static String reverse(String str) {
StringBuilder reversed = new StringBuilder(str);
return reversed.reverse().toString();
}
public static void main(String[] args) {
String original = "Hello, World!";
String reversed = reverse(original);
System.out.println("Reversed: " + reversed);
}
}
代码解释
- 使用
StringBuilder
的reverse()
方法反转字符串。
练习 2:检查回文字符串
题目
编写一个方法,检查给定字符串是否为回文。
解题思路
- 将字符串反转并与原字符串比较。
代码
public class PalindromeCheck {
public static boolean isPalindrome(String str) {
String reversed = new StringBuilder(str).reverse().toString();
return str.equals(reversed);
}
public static void main(String[] args) {
String input = "madam";
System.out.println("Is Palindrome: " + isPalindrome(input));
}
}
代码解释
isPalindrome
方法通过比较原字符串和反转字符串来判断是否为回文。
练习 3:统计字符出现次数
题目
编写一个方法,统计字符串中每个字符出现的次数。
解题思路
- 使用
HashMap
存储字符及其出现次数。
代码
import java.util.HashMap;
public class CharacterCount {
public static void countCharacters(String str) {
HashMap<Character, Integer> charCount = new HashMap<>();
for (char c : str.toCharArray()) {
charCount.put(c, charCount.getOrDefault(c, 0) + 1);
}
System.out.println(charCount);
}
public static void main(String[] args) {
countCharacters("hello");
}
}
代码解释
- 遍历字符串并更新
HashMap
中的字符计数。
练习 4:查找字符串中的第一个不重复字符
题目
编写一个方法,找出字符串中第一个不重复的字符。
解题思路
- 使用
HashMap
统计字符出现次数,再查找第一个不重复字符。
代码
import java.util.HashMap;
public class FirstNonRepeatingCharacter {
public static char firstNonRepeating(String str) {
HashMap<Character, Integer> charCount = new HashMap<>();
for (char c : str.toCharArray()) {
charCount.put(c, charCount.getOrDefault(c, 0) + 1);
}
for (char c : str.toCharArray()) {
if (charCount.get(c) == 1) {
return c;
}
}
return '\0'; // 代表没有不重复字符
}
public static void main(String[] args) {
System.out.println("First Non-Repeating: " + firstNonRepeating("swiss"));
}
}
代码解释
- 第一次循环统计字符次数,第二次循环查找第一个出现次数为1的字符。
练习 5:字符串中的单词反转
题目
编写一个方法,反转字符串中的单词顺序。
解题思路
- 使用
split
方法分割单词,再使用循环拼接反转后的字符串。
代码
public class ReverseWords {
public static String reverseWords(String str) {
String[] words = str.split(" ");
StringBuilder reversed = new StringBuilder();
for (int i = words.length - 1; i >= 0; i--) {
reversed.append(words[i]).append(" ");
}
return reversed.toString().trim(); // 去掉最后一个空格
}
public static void main(String[] args) {
String input = "Hello World";
System.out.println("Reversed Words: " + reverseWords(input));
}
}
代码解释
- 将字符串分割为单词,并从后向前拼接形成新字符串。
练习 6:字符串中最长的子串
题目
编写一个方法,找到字符串中不重复字符的最长子串。
解题思路
- 使用滑动窗口算法跟踪当前不重复子串的字符。
代码
import java.util.HashSet;
public class LongestSubstring {
public static int lengthOfLongestSubstring(String s) {
HashSet<Character> charSet = new HashSet<>();
int left = 0, maxLength = 0;
for (int right = 0; right < s.length(); right++) {
while (charSet.contains(s.charAt(right))) {
charSet.remove(s.charAt(left++));
}
charSet.add(s.charAt(right));
maxLength = Math.max(maxLength, right - left + 1);
}
return maxLength;
}
public static void main(String[] args) {
System.out.println("Length of Longest Substring: " + lengthOfLongestSubstring("abcabcbb"));
}
}
代码解释
- 通过
HashSet
存储字符,更新左指针以保持不重复性。
练习 7:字符串的组合
题目
编写一个方法,找到字符串中所有可能的组合。
解题思路
- 使用递归生成所有组合。
代码
import java.util.ArrayList;
import java.util.List;
public class StringCombinations {
public static List<String> combine(String str) {
List<String> result = new ArrayList<>();
combineHelper("", str, result);
return result;
}
private static void combineHelper(String prefix, String remaining, List<String> result) {
if (!prefix.isEmpty()) {
result.add(prefix);
}
for (int i = 0; i < remaining.length(); i++) {
combineHelper(prefix + remaining.charAt(i), remaining.substring(i + 1), result);
}
}
public static void main(String[] args) {
System.out.println("Combinations: " + combine("abc"));
}
}
代码解释
- 使用递归方法生成所有组合,前缀不断扩展,剩余字符逐步减少。
练习 8:找出两个字符串的公共字符
题目
编写一个方法,找出两个字符串中的公共字符。
解题思路
- 使用集合找出公共字符。
代码
import java.util.HashSet;
public class CommonCharacters {
public static HashSet<Character> commonChars(String str1, String str2) {
HashSet<Character> set1 = new HashSet<>();
HashSet<Character> common = new HashSet<>();
for (char c : str1.toCharArray()) {
set1.add(c);
}
for (char c : str2.toCharArray()) {
if (set1.contains(c)) {
common.add(c);
}
}
return common;
}
public static void main(String[] args) {
System.out.println("Common Characters: " + commonChars("hello", "world"));
}
}
代码解释
- 第一个循环将字符存入集合,第二个循环检查是否存在于集合中。
练习 9:去除字符串中的重复字符
题目
编写一个方法,去除字符串中的重复字符。
解题思路
- 使用
LinkedHashSet
保持字符顺序。
代码
import java.util.LinkedHashSet;
public class RemoveDuplicates {
public static String removeDuplicates(String str) {
LinkedHashSet<Character> charSet = new LinkedHashSet<>();
for (char c : str.toCharArray()) {
charSet.add(c);
}
StringBuilder result = new StringBuilder();
for (char c : charSet) {
result.append(c);
}
return result.toString();
}
public static void main(String[] args) {
System.out.println("Without Duplicates: " + removeDuplicates("programming"));
}
}
代码解释
LinkedHashSet
用于保持字符的插入顺序并去除重复字符。
练习 10:计算字符串中的元音字母数量
题目
编写一个方法,计算给定字符串中的元音字母数量。
解题思路
- 遍历字符串,检查每个字符是否为元音字母。
代码
public class VowelCount {
public static int countVowels(String str) {
int count = 0;
for (char c : str.toLowerCase().toCharArray()) {
if ("aeiou".indexOf(c) != -1) {
count++;
}
}
return count;
}
public static void main(String[]
args) {
System.out.println("Vowel Count: " + countVowels("Hello World"));
}
}
代码解释
- 使用
indexOf
检查字符是否在元音字母列表中,以计算数量。
40- ArrayList
1. 什么是ArrayList
ArrayList
是Java集合框架中一个重要的类,它实现了List
接口,允许存储动态大小的元素集合。ArrayList
内部使用数组来存储元素,具有可变大小的特性。
2. ArrayList
的特性
- 动态大小:
ArrayList
的大小可以根据需要动态调整,而不需要手动定义固定大小。 - 有序:元素的插入顺序被保持,用户可以根据索引来访问元素。
- 允许重复:可以在同一个
ArrayList
中存储多个相同的元素。 - 随机访问:支持通过索引快速访问元素,效率高。
3. 创建ArrayList
3.1 默认构造函数
ArrayList<String> list = new ArrayList<>();
- 创建一个空的
ArrayList
,初始容量为10。
3.2 指定初始容量
ArrayList<Integer> list = new ArrayList<>(10);
- 创建一个初始容量为10的
ArrayList
,如果添加超过10个元素,会自动扩容。
4. ArrayList
的常用方法
方法 | 描述 |
---|---|
add(E e) | 在列表末尾添加元素。 |
add(int index, E element) | 在指定位置插入元素。 |
remove(int index) | 移除指定位置的元素。 |
remove(Object o) | 移除第一次出现的指定元素。 |
get(int index) | 获取指定位置的元素。 |
set(int index, E element) | 替换指定位置的元素。 |
size() | 返回ArrayList 中的元素数量。 |
clear() | 移除所有元素。 |
contains(Object o) | 检查是否包含指定元素。 |
indexOf(Object o) | 返回第一次出现的指定元素的索引。 |
isEmpty() | 检查ArrayList 是否为空。 |
toArray() | 将ArrayList 转换为数组。 |
5. 常用方法详细示例
5.1 添加元素
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");
System.out.println("Fruits: " + fruits);
- 使用
add()
方法在列表末尾添加元素。
5.2 在指定位置插入元素
fruits.add(1, "Orange"); // 在索引1插入"Orange"
System.out.println("After Insertion: " + fruits);
- 使用
add(int index, E element)
方法在指定索引插入元素。
5.3 移除元素
fruits.remove("Banana"); // 根据元素值移除
System.out.println("After Removing Banana: " + fruits);
fruits.remove(0); // 根据索引移除
System.out.println("After Removing First Element: " + fruits);
- 使用
remove()
方法可以根据元素值或索引移除元素。
5.4 获取元素
String firstFruit = fruits.get(0);
System.out.println("First Fruit: " + firstFruit);
- 使用
get(int index)
方法获取指定索引的元素。
5.5 替换元素
fruits.set(0, "Kiwi"); // 将索引0的元素替换为"Kiwi"
System.out.println("After Replacement: " + fruits);
- 使用
set(int index, E element)
方法替换指定索引的元素。
5.6 查询大小
int size = fruits.size();
System.out.println("Number of Fruits: " + size);
- 使用
size()
方法获取当前元素数量。
5.7 清空列表
fruits.clear();
System.out.println("After Clearing: " + fruits);
- 使用
clear()
方法清除所有元素。
6. 遍历ArrayList
6.1 使用增强型for循环
for (String fruit : fruits) {
System.out.println(fruit);
}
- 使用增强型for循环遍历元素。
6.2 使用普通for循环
for (int i = 0; i < fruits.size(); i++) {
System.out.println(fruits.get(i));
}
- 使用普通for循环和
get()
方法按索引访问元素。
7. 性能特点
- 访问速度:由于内部使用数组,随机访问速度快,时间复杂度为O(1)。
- 插入和删除速度:在列表中间插入或删除元素时,其他元素需要移动,时间复杂度为O(n)。
- 内存管理:
ArrayList
在容量不足时会自动扩容,通常是当前大小的1.5倍,可能导致内存浪费。
8. 实际应用场景
- 适合频繁访问元素的场景,如数据检索。
- 用于存储动态数据集合,如用户输入的数据列表。
9. 练习
练习 1:合并两个ArrayList
编写一个方法,合并两个ArrayList
并返回新的ArrayList
。
import java.util.ArrayList;
public class MergeArrayLists {
public static ArrayList<String> merge(ArrayList<String> list1, ArrayList<String> list2) {
ArrayList<String> mergedList = new ArrayList<>(list1);
mergedList.addAll(list2);
return mergedList;
}
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("Apple");
list1.add("Banana");
ArrayList<String> list2 = new ArrayList<>();
list2.add("Cherry");
list2.add("Date");
ArrayList<String> result = merge(list1, list2);
System.out.println("Merged List: " + result);
}
}
练习 2:查找重复元素
编写一个方法,找出ArrayList
中所有重复的元素。
import java.util.ArrayList;
import java.util.HashSet;
public class FindDuplicates {
public static ArrayList<String> findDuplicates(ArrayList<String> list) {
HashSet<String> seen = new HashSet<>();
HashSet<String> duplicates = new HashSet<>();
for (String s : list) {
if (!seen.add(s)) {
duplicates.add(s);
}
}
return new ArrayList<>(duplicates);
}
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("apple");
list.add("orange");
list.add("banana");
System.out.println("Duplicates: " + findDuplicates(list));
}
}
练习 3:排序ArrayList
编写一个方法,对ArrayList
中的元素进行排序。
import java.util.ArrayList;
import java.util.Collections;
public class SortArrayList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Banana");
list.add("Apple");
list.add("Cherry");
Collections.sort(list);
System.out.println("Sorted List: " + list);
}
}
练习 4:过滤元素
编写一个方法,过滤出ArrayList
中所有长度大于3的字符串。
import java.util.ArrayList;
public class FilterElements {
public static ArrayList<String> filterShortStrings(ArrayList<String> list) {
ArrayList<String> result = new ArrayList<>();
for (String s : list) {
if (s.length() > 3) {
result.add(s);
}
}
return result;
}
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Hi");
list.add("Hello");
list.add("Java");
list.add("World");
System.out.println("Filtered List: " + filterShortStrings(list));
}
}
练习 5:反转ArrayList
编写一个方法,反转ArrayList
中的元素顺序。
import java.util.ArrayList;
import java.util.Collections;
public class ReverseArrayList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("One");
list.add("Two");
list.add("Three");
Collections.reverse(list);
System.out.println("Reversed List: " + list);
}
}
41- 正则表达式
1. 正则表达式简介
正则表达式(Regular Expression,简称Regex)是一种用来描述字符串匹配模式的工具,可以用于字符串搜索、验证、提取和替换等操作。
2. 正则表达式的基本构成
正则表达式由普通字符和特殊字符组成:
2.1 普通字符
- 字母、数字和其他特殊字符直接匹配自身,例如:
a
、1
、#
。
2.2 特殊字符
符号 | 描述 | 示例 |
---|---|---|
. | 匹配任意单个字符 | a.b 匹配aab 、a1b 等 |
* | 匹配前一个字符0次或多次 | a* 匹配"" 、"a" 、"aaa" |
+ | 匹配前一个字符1次或多次 | a+ 匹配"a" 、"aaa" |
? | 匹配前一个字符0次或1次 | a? 匹配"" 或"a" |
^ | 匹配行的开头 | ^a 匹配以a 开头的字符串 |
$ | 匹配行的结尾 | a$ 匹配以a 结尾的字符串 |
[] | 匹配括号内的任意字符 | [abc] 匹配"a" 、"b" 或"c" |
` | ` | 逻辑“或” |
() | 分组,用于提取或应用量词 | (abc)+ 匹配"abc" 、"abcabc" |
3. Java中的正则表达式
在Java中,正则表达式的支持通过java.util.regex
包提供。主要使用两个类:
- Pattern:用于编译正则表达式并创建Matcher。
- Matcher:用于对目标字符串进行匹配。
4. Pattern
类
4.1 编译正则表达式
Pattern pattern = Pattern.compile("正则表达式");
4.2 创建Matcher对象
Matcher matcher = pattern.matcher("目标字符串");
5. Matcher
类的方法
方法 | 描述 |
---|---|
find() | 查找下一个匹配,返回boolean值 |
matches() | 检查整个字符串是否匹配 |
replaceAll(String replacement) | 替换所有匹配的子串 |
group() | 返回当前匹配的子串 |
start() | 返回当前匹配的开始索引 |
end() | 返回当前匹配的结束索引 |
group(int group) | 返回指定组的匹配 |
6. 示例代码
以下是一个使用正则表达式的示例程序,包括邮箱和电话号码的匹配。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExample {
public static void main(String[] args) {
String input = "Hello, my email is [email protected] and my phone number is 123-456-7890.";
// 匹配邮箱地址
String emailRegex = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}";
Pattern emailPattern = Pattern.compile(emailRegex);
Matcher emailMatcher = emailPattern.matcher(input);
while (emailMatcher.find()) {
System.out.println("Found email: " + emailMatcher.group());
}
// 匹配电话号码
String phoneRegex = "\\d{3}-\\d{3}-\\d{4}";
Pattern phonePattern = Pattern.compile(phoneRegex);
Matcher phoneMatcher = phonePattern.matcher(input);
while (phoneMatcher.find()) {
System.out.println("Found phone number: " + phoneMatcher.group());
}
}
}
7. 代码解析
匹配邮箱:
- 使用正则表达式
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}
匹配字符串中的邮箱地址。 +
表示前面的字符类可以出现一次或多次。
- 使用正则表达式
匹配电话号码:
- 使用正则表达式
\\d{3}-\\d{3}-\\d{4}
匹配格式为123-456-7890
的电话号码。 \\d
表示数字,{3}
表示数字出现三次。
- 使用正则表达式
8. 常见应用场景
- 输入验证:用于验证用户输入,例如邮箱、电话号码、身份证号码等格式。
- 文本处理:从文本中提取特定模式的信息,或进行字符串的替换。
- 数据清洗:在数据处理过程中,清理不必要的字符或格式。
9. 常用正则表达式示例
9.1 邮箱验证
String emailPattern = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}";
9.2 电话号码验证
String phonePattern = "\\d{3}-\\d{3}-\\d{4}"; // 格式:123-456-7890
9.3 日期验证(YYYY-MM-DD)
String datePattern = "\\d{4}-\\d{2}-\\d{2}"; // 格式:2023-10-01
9.4 IP地址验证
String ipPattern = "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
10. 练习
练习 1:匹配网址
编写一个程序,使用正则表达式匹配字符串中的所有网址。
String urlPattern = "(http|https)://[a-zA-Z0-9.-]+(\\.[a-zA-Z]{2,})+";
练习 2:验证密码
编写一个方法,验证密码是否符合以下规则:至少8个字符,至少一个字母和一个数字,不能有空格。
String passwordPattern = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$";
练习 3:提取日期
编写一个程序,从字符串中提取格式为YYYY-MM-DD
的日期。
String dateRegex = "\\d{4}-\\d{2}-\\d{2}";
练习 4:查找重复单词
编写一个程序,查找字符串中出现的重复单词。
String duplicateWordPattern = "\\b(\\w+)\\b(?=.*\\b\\1\\b)";
练习 5:替换特定字符
编写一个程序,使用正则表达式将字符串中的所有数字替换为*
。
String replaceDigitsPattern = "\\d";
42- 正则表达式案例
练习案例 1:匹配合法邮箱地址
题目
编写一个程序,检查给定字符串是否是合法的邮箱地址。
解题思路
使用正则表达式来匹配邮箱的基本格式:用户名@域名.顶级域名。考虑到邮箱的常见结构,正则表达式可以包含字母、数字、下划线、点等字符。
代码示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class EmailValidator {
public static void main(String[] args) {
String input = "[email protected]";
String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
Pattern pattern = Pattern.compile(emailRegex);
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) {
System.out.println(input + " 是一个合法的邮箱地址。");
} else {
System.out.println(input + " 不是一个合法的邮箱地址。");
}
}
}
代码解释
^
表示字符串开头,$
表示字符串结尾,确保整个字符串都符合正则表达式。+
表示前面的字符类可以出现一次或多次,确保邮箱地址的格式。
练习案例 2:提取手机号码
题目
从给定文本中提取所有的手机号码,手机号码格式为139-1234-5678
。
解题思路
使用正则表达式来匹配特定格式的手机号码。需要匹配数字和破折号。
代码示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PhoneNumberExtractor {
public static void main(String[] args) {
String input = "我的电话号码是139-1234-5678,另外一个是139-8765-4321。";
String phoneRegex = "\\d{3}-\\d{4}-\\d{4}";
Pattern pattern = Pattern.compile(phoneRegex);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
System.out.println("找到的手机号码: " + matcher.group());
}
}
}
代码解释
\\d{3}
表示匹配三个数字,-
表示破折号,\\d{4}
表示匹配四个数字。find()
方法用于查找输入字符串中的所有匹配。
练习案例 3:验证密码强度
题目
编写一个方法,验证密码是否符合以下规则:至少8个字符,至少一个字母和一个数字,且不能有空格。
解题思路
使用正则表达式来检查密码是否符合规则。
代码示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PasswordValidator {
public static void main(String[] args) {
String password = "Pass1234";
String passwordRegex = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$";
Pattern pattern = Pattern.compile(passwordRegex);
Matcher matcher = pattern.matcher(password);
if (matcher.matches()) {
System.out.println("密码符合要求。");
} else {
System.out.println("密码不符合要求。");
}
}
}
代码解释
(?=.*[A-Za-z])
确保至少有一个字母,(?=.*\\d)
确保至少有一个数字。{8,}
表示长度至少为8个字符。
练习案例 4:提取日期
题目
从给定字符串中提取所有格式为YYYY-MM-DD
的日期。
解题思路
使用正则表达式匹配日期格式。
代码示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DateExtractor {
public static void main(String[] args) {
String input = "今天的日期是2024-11-01,明天是2024-11-02。";
String dateRegex = "\\d{4}-\\d{2}-\\d{2}";
Pattern pattern = Pattern.compile(dateRegex);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
System.out.println("找到的日期: " + matcher.group());
}
}
}
代码解释
\\d{4}
表示匹配四个数字,\\d{2}
表示匹配两个数字。- 使用
find()
方法提取所有匹配的日期。
练习案例 5:查找重复单词
题目
编写一个程序,查找字符串中出现的重复单词。
解题思路
使用正则表达式来匹配并查找重复的单词。
代码示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DuplicateWordFinder {
public static void main(String[] args) {
String input = "This is a test test string with duplicate duplicate words.";
String duplicateWordRegex = "\\b(\\w+)\\b(?=.*\\b\\1\\b)";
Pattern pattern = Pattern.compile(duplicateWordRegex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
System.out.println("找到的重复单词: " + matcher.group());
}
}
}
代码解释
\\b
表示单词边界,(\\w+)
表示匹配一个或多个字母或数字,(?=.*\\b\\1\\b)
是一个后顾式匹配,用于查找后续出现的同一个单词。- 通过
find()
方法找到所有重复的单词。
43- 综合案例-学生管理系统
1. 功能需求
- 添加学生
- 查看所有学生
- 删除学生
- 更新学生信息
- 搜索学生
- 保存和加载学生数据(文件持久化)
- 按姓名排序
- 按年龄筛选学生
2. 类结构
Student
类:表示学生对象StudentManager
类:管理学生的添加、删除、更新等操作FileManager
类:处理文件的读取和写入StudentManagementSystem
类:主程序,负责用户交互
3. 代码实现
3.1 Student
类
public class Student {
private String name;
private String studentId;
private int age;
private String email;
// 构造方法
public Student(String name, String studentId, int age, String email) {
this.name = name;
this.studentId = studentId;
this.age = age;
this.email = email;
}
// Getter 和 Setter
public String getName() {
return name;
}
public String getStudentId() {
return studentId;
}
public int getAge() {
return age;
}
public String getEmail() {
return email;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "姓名: " + name + ", 学号: " + studentId + ", 年龄: " + age + ", 邮箱: " + email;
}
}
3.2 FileManager
类
import java.io.*;
import java.util.ArrayList;
public class FileManager {
private static final String FILE_PATH = "students.txt";
// 保存学生到文件
public void saveStudents(ArrayList<Student> students) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH))) {
for (Student student : students) {
writer.write(student.getName() + "," + student.getStudentId() + "," + student.getAge() + "," + student.getEmail());
writer.newLine();
}
} catch (IOException e) {
System.out.println("保存学生信息时出错: " + e.getMessage());
}
}
// 从文件加载学生
public ArrayList<Student> loadStudents() {
ArrayList<Student> students = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
if (parts.length == 4) {
String name = parts[0];
String studentId = parts[1];
int age = Integer.parseInt(parts[2]);
String email = parts[3];
students.add(new Student(name, studentId, age, email));
}
}
} catch (IOException e) {
System.out.println("加载学生信息时出错: " + e.getMessage());
}
return students;
}
}
3.3 StudentManager
类
import java.util.ArrayList;
import java.util.Comparator;
public class StudentManager {
private ArrayList<Student> students;
private FileManager fileManager;
public StudentManager() {
fileManager = new FileManager();
students = fileManager.loadStudents(); // 加载学生信息
}
// 添加学生
public void addStudent(String name, String studentId, int age, String email) {
Student newStudent = new Student(name, studentId, age, email);
students.add(newStudent);
fileManager.saveStudents(students); // 保存到文件
}
// 查看所有学生
public ArrayList<Student> viewStudents() {
return students;
}
// 删除学生
public boolean deleteStudent(String studentId) {
for (Student student : students) {
if (student.getStudentId().equals(studentId)) {
students.remove(student);
fileManager.saveStudents(students); // 保存到文件
return true;
}
}
return false;
}
// 更新学生信息
public boolean updateStudent(String studentId, String newName, Integer newAge, String newEmail) {
for (Student student : students) {
if (student.getStudentId().equals(studentId)) {
if (newName != null) student.setName(newName);
if (newAge != null) student.setAge(newAge);
if (newEmail != null) student.setEmail(newEmail);
fileManager.saveStudents(students); // 保存到文件
return true;
}
}
return false;
}
// 按姓名排序学生
public void sortStudentsByName() {
students.sort(Comparator.comparing(Student::getName));
}
// 根据年龄筛选学生
public ArrayList<Student> filterStudentsByAge(int minAge, int maxAge) {
ArrayList<Student> filtered = new ArrayList<>();
for (Student student : students) {
if (student.getAge() >= minAge && student.getAge() <= maxAge) {
filtered.add(student);
}
}
return filtered;
}
}
3.4 StudentManagementSystem
类
import java.util.Scanner;
public class StudentManagementSystem {
private StudentManager studentManager;
private Scanner scanner;
public StudentManagementSystem() {
studentManager = new StudentManager();
scanner = new Scanner(System.in);
}
public void mainMenu() {
while (true) {
System.out.println("\n学生管理系统");
System.out.println("1. 添加学生");
System.out.println("2. 查看所有学生");
System.out.println("3. 删除学生");
System.out.println("4. 更新学生信息");
System.out.println("5. 按姓名排序学生");
System.out.println("6. 根据年龄筛选学生");
System.out.println("7. 退出");
System.out.print("请选择操作: ");
int choice = Integer.parseInt(scanner.nextLine());
switch (choice) {
case 1:
addStudent();
break;
case 2:
viewStudents();
break;
case 3:
deleteStudent();
break;
case 4:
updateStudent();
break;
case 5:
studentManager.sortStudentsByName();
System.out.println("学生信息已按姓名排序。");
break;
case 6:
filterStudentsByAge();
break;
case 7:
System.out.println("退出系统。");
scanner.close();
return;
default:
System.out.println("无效的选择,请重试。");
}
}
}
private void addStudent() {
System.out.print("请输入姓名: ");
String name = scanner.nextLine();
System.out.print("请输入学号: ");
String studentId = scanner.nextLine();
System.out.print("请输入年龄: ");
int age = Integer.parseInt(scanner.nextLine());
System.out.print("请输入邮箱: ");
String email = scanner.nextLine();
studentManager.addStudent(name, studentId, age, email);
System.out.println("学生信息已添加。");
}
private void viewStudents() {
for (Student student : studentManager.viewStudents()) {
System.out.println(student);
}
}
private void deleteStudent() {
System.out.print("请输入要删除的学号: ");
String studentId = scanner.nextLine();
if (studentManager.deleteStudent(studentId)) {
System.out.println("学生信息已删除。");
} else {
System.out.println("未找到该学号的学生。");
}
}
private void updateStudent() {
System.out.print("请输入要更新的学号: ");
String studentId = scanner.nextLine();
System.out.print("请输入新姓名 (按Enter不修改): ");
String newName = scanner.nextLine();
System.out.print("请输入新年龄 (按Enter不修改): ");
String ageInput = scanner.nextLine();
Integer newAge = ageInput.isEmpty() ? null : Integer.parseInt(ageInput);
System.out.print("请输入新邮箱 (按Enter不修改): ");
String newEmail = scanner.nextLine();
if (studentManager.updateStudent(studentId, newName.isEmpty() ? null : newName, newAge, newEmail.isEmpty() ? null : newEmail)) {
System.out.println("学生信息已更新。");
} else {
System.out.println("未找到该学号的学生。");
}
}
private void filterStudentsByAge() {
System.out.print("请输入最小年龄: ");
int minAge = Integer.parseInt(scanner.nextLine());
System.out.print("请输入最大年龄: ");
int maxAge = Integer.parseInt(scanner.nextLine());
for (Student student : studentManager.filterStudentsByAge(minAge, maxAge)) {
System.out.println(student);
}
}
public static void main(String
[] args) {
StudentManagementSystem system = new StudentManagementSystem();
system.mainMenu();
}
}
4. 代码详解
- Student类:用于封装学生的基本信息,包括姓名、学号、年龄和邮箱,并提供相应的getter和setter方法。
- FileManager类:负责文件的读取和写入操作,支持保存和加载学生信息。
- StudentManager类:管理学生的增、删、改、查操作,并提供按姓名排序和根据年龄筛选功能。
- StudentManagementSystem类:提供一个交互式的菜单,允许用户通过命令行进行学生信息的管理。
5. 扩展与优化
可以进一步添加如下功能:
- 界面优化:通过图形用户界面(GUI)改善用户体验。
- 错误处理:增加输入验证和错误处理,确保程序的健壮性。
- 数据库支持:使用数据库(如SQLite)替代文件系统进行数据存储,便于数据管理和查询。