Java期末复习
Java期末复习
一个简单的小复习,后面要详细再细细学习,祝Java考试大捷😎!
PPT-1
问题:
为什么Java编程语言被认为是平台独立的?
答案:
编译后的代码可以在多个平台上运行,几乎无需修改。
解释:
Java被认为是平台独立的,因为它采用了一次编写,到处运行的理念。当Java代码被编译时,它被转换成字节码(而非本机机器码),并保存在.class文件中。然后,这些字节码可以在任何安装了Java虚拟机(JVM)的平台上运行,无论底层的硬件和操作系统是什么。只要平台上有JVM,编译后的Java代码就能不做修改地运行。这就是Java平台独立性的来源。
以下是其他选项为何不正确的解释: - 不允许使用指针来操作内存:虽然Java不允许指针操作(以避免错误并增强安全性),但这并不是Java平台独立性的直接原因。 - 编译后的Java程序格式是CPU特定的代码:这是错误的。Java编译后的代码是字节码,而不是CPU特定的机器码。JVM在运行时将字节码转换为平台特定的机器码。 - 它是多线程的:虽然Java支持多线程,但这与其平台独立性没有直接关系。多线程主要涉及并发执行,而不是Java代码在多个平台上的运行能力。
问题:
The Java technology product group that is designed for developing applications for consumer devices is _______.
选项:
- Java SE JDK
- Java ES SDK
- Java EE SDK
- Java ME SDK
答案:
- Java ME SDK
解释:
Java ME (Micro Edition) 是为嵌入式和移动设备(例如手机、消费类电子产品等)设计的Java技术平台。Java ME SDK提供了开发、测试和部署Java应用程序的工具,专门用于低功耗设备和资源受限的环境,因此它适用于消费设备。
其他选项解释:
- Java SE JDK (Standard Edition):这是用于开发桌面、服务器和嵌入式系统应用程序的Java开发工具包,但它不是专门为消费类设备设计的。
- Java ES SDK (Enterprise System):这是为企业应用开发设计的Java技术平台,通常用于构建大型企业级应用系统。
- Java EE SDK (Enterprise Edition):这是面向企业级应用开发的Java平台,主要用于构建Web应用、企业应用等,和消费设备开发无关。
Problem 1: Write a program to display "Good Morning".
Java Program:
1 | public class GoodMorning { |
Explanation: This Java program creates a class
GoodMorning with a main method, which is the
entry point of the program. The System.out.println
statement is used to display the text "Good Morning" on the console.
Problem 2: What command is used to compile a Java program?
Answer: To compile a Java program, you use the
javac command.
Command:
1 | javac ProgramName.java |
Explanation:
- The
javaccommand is used to compile Java source code (.javafile) into bytecode (.classfile). - Example:
javac GoodMorning.javacompiles theGoodMorning.javasource file and creates aGoodMorning.classfile (bytecode).
Problem 3: What command is used to run a Java program?
Answer: To run a Java program, you use the
java command.
Command:
1 | java ProgramName |
Explanation:
- The
javacommand is used to run the bytecode (.classfile) generated after compilation. - Example:
java GoodMorningruns theGoodMorning.classfile and prints "Good Morning" to the console.
PPT-2
计算未来投资价值的 Java 程序
问题描述:
编写一个程序,输入投资金额、年利率和年数,使用以下公式计算未来的投资价值:
[ = (1 + )^{ } ]
例如,如果输入的金额为 1000,年利率为 3.25%,年数为 1年,则未来投资价值为 1032.98。
提示: 可以使用 Math.pow(a, b) 方法计算
a 的 b 次方。
样例运行:
1 | 样例 1: |
程序代码:
1 | import java.util.Scanner; |
代码解释:
- 输入部分:
- 使用
Scanner获取用户输入的投资金额、年利率和年数。
- 使用
- 计算月利率:
monthlyInterestRate = annualInterestRate / 1200,因为年利率是百分比,所以要除以 1200 将年利率转换为月利率。
- 计算未来价值:
- 使用公式
futureValue = investmentAmount * Math.pow(1 + monthlyInterestRate, numOfYears * 12)计算未来价值。Math.pow(a, b)方法计算a的b次方。
- 使用公式
- 输出未来价值:
System.out.print("未来投资价值是:" + (int)(futureValue * 100) / 100.0);通过乘以 100 转换为整数,再除以 100 保留两位小数。
示例输入输出:
- 输入:
- 投资金额:1000
- 年利率:4.25
- 年数:1
- 输出:
- 未来投资价值是:1043.34
注意事项:
- 程序中的
Math.pow(a, b)用于计算(1 + 月利率) 的年数乘以12次方。 - 输出保留两位小数,使用
(int)(futureValue * 100) / 100.0实现。
PPT-3
无
PPT-4
寻找最大数及其出现次数
问题描述:
编写一个程序,读取一组整数,找出其中的最大数,并统计其出现的次数。假设输入以数字 0 结束。
例如,输入为 3 5 2 5 5 5 0,程序会输出:
1
2最大数是 5
最大数的出现次数是 4
提示: - 使用两个变量 max 和
count: - max 存储当前的最大值。 -
count 存储最大值的出现次数。 - 初始时,将第一个数字赋值给
max,count 设为 1。 - 比较每个后续数字: -
如果数字大于 max,将其赋值给 max,并重置
count 为 1。 - 如果数字等于 max,则将
count 增加 1。
程序设计思路:
- 初始化:
- 输入的第一个数字赋值给
max。 - 初始化
count为 1,表示当前最大值第一次出现。
- 输入的第一个数字赋值给
- 处理后续数字:
- 遍历每个输入的数字:
- 如果数字大于当前的
max,则更新max并重置count为 1。 - 如果数字等于
max,则增加count。
- 如果数字大于当前的
- 遍历每个输入的数字:
- 结束条件:
- 输入结束时,遇到数字 0,停止输入并输出结果。
程序代码:
1 | import java.util.Scanner; |
代码解释:
- 输入与初始化:
int max = input.nextInt();读取第一个输入的数字并赋值给max。int count = 1;初始化count为 1,表示第一个数字出现一次。
- 循环输入:
while (true)循环持续输入直到遇到 0 为止。- 每次输入一个数字,将其赋值给
num。 - 如果
num == 0,则结束输入循环。
- 比较并更新:
if (num > max):如果当前输入的数字大于max,则更新max,并重置count为 1,表示当前最大值出现一次。else if (num == max):如果当前数字与max相等,则将count加 1。
- 输出结果:
- 最后输出
max和count,分别表示最大数和它的出现次数。
- 最后输出
示例输入与输出:
输入:
1
3 5 2 5 5 5 0
输出:
1
2最大数是 5
最大数的出现次数是 4
边界情况:
- 没有输入任何数字:
- 由于程序设计要求输入以
0结束,如果没有输入其他数字,程序会直接输出:1
2最大数是 0
最大数的出现次数是 1
- 由于程序设计要求输入以
- 只有一个数字:
- 如果输入的只有一个数字并且是非零的,那么该数字就是最大值,出现次数为 1。
- 所有输入数字相同:
- 如果所有输入的数字相同,则程序会统计这个数字的出现次数。
PPT-5
无
PPT-6
计算整数各位数字和的程序
问题描述:
编写一个方法
sumDigits(long n),计算一个整数的各位数字之和。
示例: - 输入:234 -
输出:9(即:2 + 3 + 4)
提示:
- 使用
%运算符来提取数字的最后一位。- 例如:
234 % 10提取出 4。
- 例如:
- 使用
/运算符来移除数字的最后一位。- 例如:
234 / 10变成 23。
- 例如:
通过不断提取和移除数字,直到所有数字被处理完。
程序设计思路:
- sumDigits 方法:
- 输入:一个长整型数字
n。 - 处理:
- 取
n的绝对值,因为负数的每一位数字的和与正数相同。 - 使用
%和/运算符提取数字,并累加到sum变量中。 - 使用
while循环不断处理数字,直到所有位数被处理完。
- 取
- 输出:数字各位数之和。
- 输入:一个长整型数字
- Test 类:
- 输入:提示用户输入一个整数。
- 输出:调用
sumDigits方法,计算并显示数字的各位和。
程序代码:
1 | import java.util.Scanner; |
程序流程:
- 输入:
- 程序提示用户输入一个整数
value。
- 程序提示用户输入一个整数
- sumDigits 方法:
- 将输入的数字
n取绝对值,处理负数情况。 - 初始化
temp为数字的绝对值,并初始化sum为 0。 - 使用
while循环:- 每次通过
% 10获取当前数字的最后一位。 - 使用
/ 10去除当前数字的最后一位。 - 将提取的数字累加到
sum中。
- 每次通过
- 循环直到所有数字处理完。
- 返回
sum。
- 将输入的数字
- 输出:
- 程序输出用户输入数字的各位数字之和。
示例运行:
输入:
1
Enter a number: 234
输出:
1
The sum of digits for 234 is 9
程序解析:
sumDigits方法:- 首先,方法将输入的数字取绝对值,以便处理负数的情况。
- 接着,进入
while循环,每次提取数字的最后一位,并加到sum中。 - 每次通过除以 10 移除数字的最后一位,直到
temp为 0,表示所有位数处理完。
main方法:- 通过
Scanner类读取用户输入的整数。 - 调用
sumDigits方法,输出结果。
- 通过
边界情况:
- 输入为负数:
- 例如输入
-234,程序会自动计算其绝对值,输出 9。
- 例如输入
- 输入为 0:
- 当输入为
0时,输出结果应为 0。
- 当输入为
- 输入为单个数字:
- 如果输入为单个数字,如
7,则输出结果为该数字本身。
- 如果输入为单个数字,如
PPT-7
1. 声明数组变量的语句:
声明一个名为
x的数组,类型为double:1
double[] x;
double[]表示数组的类型为double数组。x是数组的名称。
2.
创建一个大小为 40 的 int
类型数组的表达式:
1 | int[] arr = new int[40]; |
int[]表示该数组是存储int类型数据的数组。new int[40]表示创建一个长度为 40 的int数组。
3.
java.util.Arrays.binarySearch
的用法:
binarySearch
方法是用于在已排序的数组中进行二分查找。该方法返回目标值的索引,如果目标值不存在,返回负值(其负值加
1 表示插入位置)。
java.util.Arrays.binarySearch(new int[]{1, 2, 3, 7, 14}, 7):- 数组
new int[]{1, 2, 3, 7, 14}是一个已排序的数组。 - 目标值为
7。 - 结果:
binarySearch会返回目标值7在数组中的索引,索引为3(从 0 开始计数)。
输出:
1
3
- 数组
java.util.Arrays.binarySearch(new int[]{1, 2, 3, 7, 14}, 5):- 数组
new int[]{1, 2, 3, 7, 14}中没有值为5的元素。 - 由于
5不在数组中,binarySearch方法返回的是插入位置的负值加 1,即-4。 - 这是因为
5应该插入到索引3(7前面)的位置,所以返回的负数是-(3 + 1),即-4。
输出:
1
-4
- 数组
4. 代码的输出分析:
1 | public class Test { |
解释:
number变量:- 在
main方法中,number被初始化为0。 - 在调用
m(number, numbers)时,number被按值传递给方法m,因此在方法内修改x对number没有任何影响,number的值保持为0。
- 在
numbers数组:numbers数组被初始化为大小为 1 的数组,且初始值为0。- 在
m方法中,numbers[0]被设置为3,因此这个数组的值被修改为3。 - 注意:数组是按引用传递的,所以在方法内修改
numbers[0]会影响到main方法中的numbers数组。
程序输出:
1 | number is 0 and numbers[0] is 3 |
number的值未改变,仍为0。numbers[0]被修改为3,所以输出为3。
5. 精华所在:
- 声明和初始化数组: 可以通过
double[] x或int[] arr声明数组,并通过new关键字初始化数组。 - 二分查找:
Arrays.binarySearch用于在已排序的数组中查找元素。返回值为目标值的索引,若不存在该值则返回负值。 - 值传递与引用传递:
- 值传递: 基本数据类型(如
int)是按值传递的,修改方法内的变量不会影响外部变量。 - 引用传递: 对象(如数组)是按引用传递的,方法内对对象的修改会影响外部对象的状态。
- 值传递: 基本数据类型(如
PPT-9
1. 声明 Circle
对象的变量:
- 声明一个
Circle类型的变量x:
1 | Circle x; |
- 这里
Circle是对象类型,x是对象变量,用于引用一个Circle类的对象。
2.
使用无参构造函数创建 Circle 对象:
1 | Circle circle = new Circle(); |
Circle()是无参数构造函数,它会创建一个默认的Circle对象。
3. 声明
Circle 类型的变量并初始化:
1 | Circle x = new Circle(5.5); |
- 这里
Circle(5.5)假设构造函数Circle(double radius)已存在,用来初始化一个半径为5.5的Circle对象。
4. 调用
getArea() 方法返回 Circle
对象的面积:
1 | double area = c.getArea(); |
- 假设
c是一个已经创建的Circle对象,并且getArea()方法存在,用来计算并返回圆的面积。
5. 创建一个
Date 对象,表示当前时间:
1 | Date currentDate = new Date(); |
Date类表示一个具体的时间点。通过new Date()创建一个表示当前时间的Date对象。
6. 代码输出分析:
1 | public class Test { |
解释:
- 类
A的成员变量:i是实例变量,属于每个A对象。每次创建A类的实例时,i都会初始化为1,并且在构造函数中i会增加1,所以每个对象的i值会是2。j是静态变量,属于类A,而不是某个实例。静态变量在类的所有实例之间共享,所以j只有一个值,所有对象都共享这个值。
- 构造函数:
- 每次创建
A类的实例时,构造函数会被调用,i和j都会被加1。由于i是实例变量,因此每个实例的i都会独立增加。而j是静态变量,因此所有实例共享j,它只会增加一次。
- 每次创建
- 代码执行:
- 创建
a1对象时,i被初始化为1,然后在构造函数中增加1,所以i变为2。同时,静态变量j也被加1,所以j变为2。 - 创建
a2对象时,i也被初始化为1,然后增加1,所以i变为2。但是静态变量j在两个对象之间共享,已经增加过一次,所以j变为3。
- 创建
输出:
1 | 2 3 |
- 第一个输出是
a1.j,由于j被加过一次,a1.j的值为2。 - 第二个输出是
a2.j,j被加过两次,所以a2.j的值为3。
7. 归纳:
- 实例变量与静态变量:
- 实例变量(如
i)是每个对象独有的,每次创建一个对象时,都会为实例变量分配一个新值。 - 静态变量(如
j)是类级别的变量,所有对象共享一个静态变量,因此它的变化会影响到所有对象。
- 实例变量(如
- 构造函数:
- 在每个对象创建时,构造函数都会被调用,实例变量
i会根据对象初始化并修改,而静态变量j是类级别的,因此它的值在所有对象间共享。
- 在每个对象创建时,构造函数都会被调用,实例变量
PPT-10
String、StringBuffer与StringBuilder的性能比较
1. 程序示例与性能测试
通过以下程序,我们比较了
String、StringBuffer 和
StringBuilder 在进行字符串拼接时的性能:
1 | public class StringMore { |
该程序通过测试不同的字符串拼接方式来测量执行时间。分别测试了使用
String、StringBuffer 和
StringBuilder 对同一个字符串进行拼接的性能。
2. 性能比较
String:每次拼接字符串时都会创建一个新的字符串对象,性能较差。因为String是不可变的,每次修改都会创建新的对象,因此在频繁拼接时效率较低。StringBuffer:线程安全的字符串缓冲区。每次拼接时,StringBuffer会扩展它的内部数组并追加字符,因此在多次拼接时效率较高。StringBuffer使用了synchronized关键字来确保线程安全,导致它的性能较StringBuilder略逊一筹。StringBuilder:与StringBuffer类似,但是它没有synchronized关键字,因此它比StringBuffer更快,适用于单线程环境。
执行效率: - StringBuilder >
StringBuffer > String
3. 优化与建议
String拼接的优化:当直接用
+操作符拼接字符串时,Java 编译器会对这种情况进行优化,将多个字符串拼接转换为一个StringBuilder或StringBuffer对象的调用。例如:这样优化的效率高于手动创建1
String str = "my" + "hello" + "world"; // 编译器优化为 "my" + "hello" + "world"
StringBuilder对象并调用append方法:1
StringBuilder st = new StringBuilder("my").append("hello").append("world");
选择合适的类:
String:适合拼接次数较少,或者只有少量字符串拼接的场合。StringBuilder:适合在单线程环境下,进行大量字符串拼接的场合。StringBuffer:适合在多线程环境下进行字符串拼接的场合,虽然它的性能稍逊于StringBuilder。
4. 成员方法对比
- String:不可变,每次拼接都会创建新的对象。
- StringBuffer 和
StringBuilder:都实现了可变的字符串操作,具有
append、insert等方法,可以高效地进行字符串拼接。
StringBuffer:是线程安全的,使用了synchronized关键字。StringBuilder:不是线程安全的,性能较StringBuffer更优。
5. 精华
- 当需要频繁修改或拼接字符串时,推荐使用
StringBuilder(单线程)。 - 在多线程环境中,使用
StringBuffer(它是线程安全的)。 - 如果拼接次数较少,使用
String即可,因为它的实现简单且直观。
PPT-11
1. Superclasses and Subclasses (父类与子类)
在面向对象编程中,类继承是构建类关系的一种方式。类与类之间可以形成父类(superclass)与子类(subclass)的关系。继承机制使得子类可以继承父类的属性和方法,从而避免重复代码。
- 父类(Superclass):是一个被其他类继承的类,通常包含一些通用的属性和方法。
- 子类(Subclass):继承父类的类。子类可以继承父类的所有非私有属性和方法,并可以根据需要重写或扩展这些属性和方法。
extends关键字:用于表示继承关系,子类通过extends关键字继承父类。
示例:
1 | class Animal { // 父类 |
关键点:
- 子类通过继承父类,可以访问父类的公有属性和方法。
- 子类可以通过方法重写(Override)父类的方法。
- 子类可以使用父类的构造方法,但父类的构造方法必须通过
super()显式调用。
2. The Object Class and Its Methods (Object类及其方法)
Object 类是 Java
中的根类,所有的类(包括数组)都直接或间接继承自 Object
类。Object
类中定义了许多常用的方法,这些方法可以被所有类所使用。
常用的 Object 类方法:
toString():返回对象的字符串表示。
- 默认返回对象的类名和内存地址,可以被子类重写以提供更有意义的输出。
1
2
3
4
public String toString() {
return "Dog";
}equals(Object obj):比较两个对象的相等性。
- 默认通过内存地址比较两个对象,但通常会重写该方法来比较对象的内容。
hashCode():返回对象的哈希码。
- 通常与
equals()方法一起重写,确保当两个对象相等时,它们的哈希码也相等。
- 通常与
getClass():返回对象的类类型。
- 可以用来获取对象的实际类。
示例:
1 | public class Animal { |
3. Polymorphism, Dynamic Binding and Generic Programming (多态、动态绑定和泛型编程)
3.1 Polymorphism (多态)
多态是面向对象编程的核心概念之一,它允许使用统一的接口来操作不同类型的对象。多态使得程序具有更强的灵活性和可扩展性。
- 编译时多态(方法重载):方法名相同,但参数列表不同。
- 运行时多态(方法重写):子类重写父类的方法。
3.2 Dynamic Binding (动态绑定)
动态绑定是指程序在运行时决定方法调用的具体类型(方法的实现)。例如,当子类重写父类的方法时,Java 会根据对象的实际类型来决定调用哪个方法。
- 动态绑定通常发生在多态的情况下,即方法重写。
- 方法重载是编译时绑定。
3.3 Generic Programming (泛型编程)
泛型是 Java 提供的一种支持类型参数化的机制。通过泛型,可以在编译时检查类型错误,而不是运行时。
- 泛型使得代码更加通用和可重用。
- 泛型使用尖括号
<>来指定类型。
示例:
1 | // 泛型方法 |
4. The ArrayList Class (ArrayList类)
ArrayList 是 Java
中的一个可动态扩展的数组实现,它是 List
接口的实现类之一。与普通数组不同,ArrayList
可以自动调整大小。
主要特点:
- 动态扩展:当添加元素超过容量时,
ArrayList会自动扩展。 - 顺序存储:它保持元素的插入顺序,并且允许重复的元素。
- 元素访问:通过索引访问元素,时间复杂度为 O(1)。
常用方法:
add(E e):添加元素。get(int index):获取指定索引的元素。size():返回元素的数量。remove(int index):删除指定索引的元素。
示例:
1 | import java.util.ArrayList; |
5. The protected / final Modifier (protected / final 修饰符)
5.1 protected 修饰符
protected允许类中的成员被当前类、同一包中的其他类以及所有继承该类的子类访问。protected主要用于继承机制中的属性和方法共享。
示例:
1 | class Animal { |
5.2 final 修饰符
final用于变量、方法和类:
final变量:值不可更改,一旦赋值就不能修改。final方法:不能被子类重写。final类:不能被继承。
示例:
1 | final class FinalClass { |
精华:
- Superclasses and Subclasses:通过继承机制,子类能够继承父类的属性和方法,并可以重写和扩展。
- The Object Class:
Object类是所有 Java 类的根类,提供了如toString()、equals()等常用方法。 - Polymorphism and Dynamic Binding:通过多态性,可以让不同类型的对象调用相同的方法,且方法调用的实际实现通过动态绑定决定。
- The ArrayList Class:
ArrayList是一个动态扩展的数组实现,适用于需要频繁增加和删除元素的场景。 - The protected/final
Modifier:
protected提供了访问权限控制,而final用于限制变量、方法和类的修改和继承。
PPT-12
1. Exception (异常)
异常(Exception)
是程序运行过程中发生的意外事件,它通常导致程序的正常执行流中断。Java
使用异常处理机制来处理这些错误和异常情况。异常可以是运行时错误或逻辑错误,并且可以通过异常处理机制(如
try-catch)来捕获和处理。
主要特点:
- 异常是对象,可以使用
throw语句抛出。 - 异常通常会导致程序终止,但可以通过适当的异常处理机制恢复程序的执行。
2. Exception Advantages (异常的优势)
异常处理机制提供了以下几个主要优势:
- 提高程序的可维护性:通过异常处理,程序能够明确处理不同的错误情况,而不会让错误影响到其他部分的逻辑。
- 减少错误:通过集中处理错误,程序能够避免出现未处理的错误。
- 增强代码的健壮性:通过捕获和处理异常,程序能够在出现问题时优雅地失败或恢复,而不是直接崩溃。
- 代码清晰:异常处理机制使得错误处理与正常逻辑分开,增强了代码的可读性。
3. Exception Types (异常类型)
在 Java 中,异常类型可以分为以下几类:
Checked Exception(已检查异常):- 这些异常在编译时就能被发现,必须被显式捕获或声明。
- 常见的
Checked Exception包括IOException、SQLException等。 - 这些异常通常是由外部因素引起的,如文件不存在、数据库连接失败等。
Unchecked Exception(未检查异常):- 这些异常是程序错误引起的,通常在运行时发生。
- 常见的
Unchecked Exception包括NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException等。 - 未检查异常不需要显式地处理或声明。
Error(错误):- 错误通常是由系统级问题引起的,例如
OutOfMemoryError或StackOverflowError,这些通常无法通过代码处理。
- 错误通常是由系统级问题引起的,例如
4. Declaring, Throwing, and Catching Exceptions (声明、抛出和捕获异常)
4.1 声明异常(Declaring Exceptions)
如果方法中可能会抛出
Checked Exception,那么必须在方法签名中使用
throws 关键字声明该异常。
1 | public void readFile() throws IOException { |
4.2 抛出异常(Throwing Exceptions)
通过 throw 语句可以在程序中显式抛出异常。
1 | throw new ArithmeticException("Cannot divide by zero"); |
4.3 捕获异常(Catching Exceptions)
通过 try-catch
语句来捕获和处理异常。如果发生异常,程序会跳转到对应的
catch 块中。
1 | try { |
4.4 多重捕获(Multiple Catch Blocks)
可以有多个 catch 块来捕获不同类型的异常。
1 | try { |
4.5 finally 块
finally
块用于执行清理代码(如释放资源),无论是否发生异常,它始终都会被执行。
1 | try { |
5. Text I/O (文本输入输出)
Java 提供了多种方式来处理文本的输入输出。常用的类包括
FileReader、BufferedReader 和
PrintWriter。
5.1
FileReader 和
BufferedReader
FileReader
用于读取字符文件,但它的效率较低,因此通常配合
BufferedReader 使用来提高效率。
1 | FileReader fr = new FileReader("file.txt"); |
5.2 PrintWriter
PrintWriter
是一种便捷的类,可以用于输出文本数据,支持自动刷新和格式化输出。
1 | PrintWriter writer = new PrintWriter("output.txt"); |
6. File (文件处理)
在 Java 中,文件处理可以通过 File
类来实现,File
类提供了文件和目录的创建、删除、重命名等操作。
1 | File file = new File("example.txt"); |
常用方法:
createNewFile():创建新文件。delete():删除文件。exists():检查文件或目录是否存在。getAbsolutePath():返回文件的绝对路径。
7. PrintWriter (PrintWriter类)
PrintWriter 是 Java
中用于写入字符数据到文件或控制台的类。它具有更高效的输出能力,并且支持自动刷新功能。
1 | PrintWriter writer = new PrintWriter(new FileWriter("output.txt")); |
flush():刷新流,确保数据写入。close():关闭流,释放资源。
8. Scanner (Scanner类)
Scanner
类是用于从控制台或文件中读取输入的工具。它支持读取各种类型的数据,包括整数、浮点数、字符串等。
示例:
1 | Scanner sc = new Scanner(System.in); |
常用方法:
nextLine():读取一行文本。nextInt():读取一个整数。nextDouble():读取一个浮点数。close():关闭Scanner对象。
精华:
- 异常是 Java 中重要的概念,通过
try-catch机制来捕获和处理运行时错误。 - 异常的种类包括
Checked Exception和Unchecked Exception,每种类型的异常有不同的处理方式。 - Text I/O 涉及读取和写入文本文件,常用的类有
FileReader、BufferedReader、PrintWriter等。 - 文件操作可以通过
File类来进行文件的创建、删除、检查等。 PrintWriter提供了便捷的文本输出功能,Scanner用于读取输入。
PPT-13
深拷贝 (Deep Copy) 和浅拷贝 (Shallow Copy)
在对象复制的过程中,常常遇到浅拷贝和深拷贝的问题。它们之间的区别在于是否对对象内部的引用类型字段进行了复制。
浅拷贝 (Shallow Copy):只复制对象的引用,而不复制对象内部的引用类型字段。即复制后的对象与原对象共享相同的引用数据。
深拷贝 (Deep Copy):不仅复制对象本身,还会复制对象内部引用的数据,使得复制后的对象与原对象完全独立,所有字段都有自己的副本。
问题描述:在
Course1 类中实现 clone() 方法并对
students 字段进行深拷贝
Course1 类中有一个 students
字段,表示课程中的学生数组。需要实现 clone()
方法,确保在克隆 Course1 对象时,students
数组进行深拷贝。
Course1
类设计
假设 Course1 类的设计如下:
1 | public class Course1 implements Cloneable { |
代码详解
Course1类字段:courseName:课程名称,类型为String。students:一个长度为 100 的String数组,表示学生的姓名。numberOfStudents:记录学生的数量。
- 构造方法
(
Course1(String courseName)):- 用于初始化课程名称和学生数量。
addStudent(String student)方法:- 用于添加学生到
students数组中,numberOfStudents会自增。
- 用于添加学生到
getStudents()方法:- 返回学生数组。
getNumberOfStudents()方法:- 返回当前学生的数量。
getCourseName()方法:- 返回课程名称。
dropStudent(String student)方法:- 用于从学生数组中删除指定学生。删除后数组会左移,
numberOfStudents减 1。
- 用于从学生数组中删除指定学生。删除后数组会左移,
clone()方法:clone()方法用于克隆对象。在 Java 中,Object类提供了一个clone()方法,但它是浅拷贝。为了实现深拷贝,我们在clone()方法中手动拷贝students数组。- 首先,调用
super.clone()完成浅拷贝,复制Course1对象的基本属性(如courseName和numberOfStudents)。 - 然后,使用
System.arraycopy()或者循环手动拷贝students数组,以确保新的Course1对象拥有一个独立的students数组副本。
深拷贝的实现方式
在 clone() 方法中实现深拷贝有两种常见方式:
- 使用
System.arraycopy():System.arraycopy(this.students, 0, c.students, 0, 100);直接将原数组的内容拷贝到新数组。这样可以有效地复制students数组,但两者依然是独立的数组副本。
- 使用循环手动拷贝:
- 使用
for循环遍历students数组,将每个学生的引用逐一复制到新数组中。
1
2
3for (int i = 0; i < numberOfStudents; i++) {
c.students[i] = this.students[i];
} - 使用
为什么要使用
clone() 方法?
clone()
方法提供了一种创建对象副本的简便方式。通过实现深拷贝,我们确保了两个
Course1 对象之间不会互相影响。特别是在涉及到
students 数组这样的引用类型字段时,深拷贝非常重要。
- 浅拷贝:如果不进行深拷贝,克隆后的
Course1对象和原对象会共享students数组中的数据。对其中一个对象的修改可能会影响到另一个对象的状态。 - 深拷贝:通过深拷贝,我们确保了原对象和克隆对象的
students数组是完全独立的,互不干扰。
注意事项
Cloneable接口:要使用clone()方法,类必须实现Cloneable接口,否则会抛出CloneNotSupportedException异常。super.clone():super.clone()会调用Object类的clone()方法,这会返回一个浅拷贝的副本,之后可以在此基础上进行深拷贝操作。
精华
在 Course1 类中,通过实现 clone() 方法并对
students 数组进行深拷贝,确保了克隆的 Course1
对象拥有独立的学生数组,从而避免了原对象和克隆对象之间的相互影响。这种深拷贝的方式是对对象内部引用字段进行复制的标准做法,适用于具有复杂属性的类。
PPT-14
JavaFX vs Swing and AWT
1. Swing: - Swing 是 Java 中的一个 GUI(图形用户界面)工具包,它基于 AWT(抽象窗口工具包)进行扩展。 - Swing 提供了丰富的控件,如按钮、标签、文本框等,使用 Java 编写而不是依赖于本地操作系统的窗口组件,因此界面更加一致。 - Swing 中的组件是“轻量级”的,意味着它们不依赖于操作系统的窗口,而是由 Java 绘制的。
2. AWT (Abstract Window Toolkit): - AWT 是 Java 的基础 GUI 库,用于构建图形界面。 - 与 Swing 不同,AWT 组件通常是“重量级”的,即它们依赖于操作系统提供的本地组件,因此它们的外观和行为可能因平台而异。 - AWT 是 Java GUI 的最初实现,但功能较为简单,不支持高级图形处理。
3. JavaFX: - JavaFX 是 Java 8 引入的新 GUI 库,用于开发丰富的桌面应用程序。 - 相比于 Swing 和 AWT,JavaFX 提供了更强大的功能,如硬件加速的图形处理、动画、3D 图形、样式表支持(CSS)、更现代的布局管理和易于使用的事件处理。 - JavaFX 基于 Scene Graph(场景图)模型,它比 Swing 和 AWT 更灵活、强大,支持多种控件和图形元素。
4. 比较总结: - Swing vs JavaFX:Swing 的设计比较旧,适合传统的桌面应用,而 JavaFX 适合构建现代的、具有多媒体功能的桌面应用。 - AWT vs JavaFX:AWT 提供基础功能,JavaFX 提供更现代和丰富的功能,支持硬件加速和复杂的界面设计。
SceneBuilder
SceneBuilder 是一种 JavaFX 可视化布局工具,用于创建 JavaFX 界面的 FXML 文件。FXML 是一种类似于 HTML 的标记语言,用于描述 JavaFX 应用的用户界面。SceneBuilder 提供了一个图形化的界面,用户可以通过拖放组件来设计 JavaFX 界面,然后生成相应的 FXML 文件。
特点: - 图形化界面:通过拖放界面控件,快速构建界面。 - 生成 FXML 文件:自动生成 FXML 文件,用户可以进一步在 Java 代码中引用。 - 与代码分离:JavaFX 与 FXML 分离,代码更加清晰,易于维护。
优势: - 提高开发效率:无需手动编写 UI 布局代码,便于快速构建应用。 - 支持预览:可以实时预览界面设计效果。 - 可与 Java 代码无缝集成:FXML 与 Java 代码结合,支持动态控制界面元素。
Basic Structure of JavaFX
JavaFX 的基本结构包括:
- Application 类:
- 所有 JavaFX 程序都必须继承
javafx.application.Application类,并重写start()方法。 start()方法接受一个Stage参数,表示应用的主窗口。
- 所有 JavaFX 程序都必须继承
- Stage(舞台):
Stage是应用的顶层容器,它表示一个窗口。- 每个 JavaFX 程序至少有一个
Stage对象,应用程序的主界面是Stage上的Scene。
- Scene(场景):
Scene表示一个容器,包含所有界面元素(控件、布局等)。- 场景是添加到舞台上的,舞台可以持有多个场景。
- Node(节点):
Node是 JavaFX 中所有可视化元素的基类,包括图形、控件、容器等。每个节点都可以是Stage或Scene的一部分。- 常见的节点有
Button、TextField、ImageView、Shape等。
Stage/Scene/Pane/Node
- Stage:
- JavaFX 的
Stage类是舞台,它表示一个窗口。 - 每个 JavaFX 应用程序必须至少有一个
Stage,它是界面的容器。
- JavaFX 的
- Scene:
Scene是舞台中的内容,包含所有的 UI 元素,和事件处理。Scene可以包含多个控件和布局元素。
- Pane:
Pane是 JavaFX 中的容器类,主要用于布局和组织其他节点。- 常见的
Pane类型包括StackPane、GridPane、FlowPane等,它们有不同的布局策略。
- Node:
Node是所有 JavaFX 可视元素的基类,可以是 UI 控件(如按钮、标签)或图形元素(如矩形、圆形)。
Binding Property (属性绑定)
属性绑定是 JavaFX 中的强大功能,它允许控件或对象的属性相互关联,并自动更新。当一个属性的值发生变化时,绑定到该属性的其他属性也会自动更新。
常见的属性绑定方式: - 双向绑定:两个属性互相绑定,互相更新。 - 单向绑定:一个属性绑定到另一个属性,源属性变化时目标属性自动更新。
示例:
1 | TextField textField = new TextField(); |
在此示例中,label 的文本会始终与 textField
的文本内容同步。
Common Properties and Methods for Nodes
常见的 JavaFX 节点属性和方法包括:
- 属性:
x和y:定义节点的位置。width和height:定义节点的尺寸。opacity:设置节点的透明度。style:设置节点的 CSS 样式。visible:设置节点是否可见。rotate:设置节点的旋转角度。
- 方法:
setLayoutX()和setLayoutY():设置节点的位置。setWidth()和setHeight():设置节点的宽度和高度。setStyle():设置节点的 CSS 样式。
Style / Rotate
Style:
- JavaFX 使用 CSS 来控制界面元素的样式。通过
setStyle()方法可以动态改变节点的样式。 - 可以设置属性,如
background-color、font-size、color等。
示例:
1
button.setStyle("-fx-background-color: blue;");
- JavaFX 使用 CSS 来控制界面元素的样式。通过
Rotate:
rotate属性用于旋转节点,单位是度(°)。- 旋转是相对于节点的原点进行的,可以通过
setRotate()方法设置旋转角度。
示例:
1
rectangle.setRotate(45); // 旋转 45 度
Color / Font / Layout Panes / Image / Shape
Color:
- JavaFX 提供了
Color类用于设置颜色。可以使用预定义的颜色常量,或通过 RGB 值自定义颜色。
示例:
1
2Color color = Color.RED; // 使用预定义颜色
Color customColor = Color.rgb(255, 0, 0); // 使用 RGB 值- JavaFX 提供了
Font:
Font类用于设置文本的字体、大小等属性。
示例:
1
Font font = Font.font("Arial", 20); // 设置 Arial 字体,大小为 20
Layout Panes:
- JavaFX 提供了多种布局容器类(
Pane),如VBox、HBox、GridPane、FlowPane,用于自动排列子节点。
示例:
1
2VBox vbox = new VBox();
vbox.getChildren().add(button); // 将按钮添加到垂直布局- JavaFX 提供了多种布局容器类(
Image:
Image类用于处理图像。可以加载本地或远程图片并显示。
示例:
1
2Image image = new Image("file:picture.jpg");
ImageView imageView = new ImageView(image);Shape:
- JavaFX 提供了多种形状类,如
Rectangle、Circle、Ellipse、Line,可以用来绘制图形。
示例:
1
Rectangle rect = new Rectangle(100, 100, 200, 150); // 创建一个矩形
- JavaFX 提供了多种形状类,如
PPT-15
Java Event Delegation Model
Java 中的 事件委托模型(Event Delegation Model)是事件处理的核心。它是处理 GUI 事件(如按钮点击、鼠标移动等)的机制,并基于分离关注的设计理念。事件的发生与事件的响应(处理)是分离的,事件源和事件处理器(监听器)是解耦的。
基本概念:
- 事件源(Event Source):事件源是触发事件的对象。在 Java 中,通常是 GUI 组件(如按钮、文本框等)。
- 事件(Event):事件表示用户与应用程序的交互行为(如点击、按键、鼠标移动等)。Java
中的事件通常继承自
java.util.EventObject类。 - 事件监听器(Event Listener):事件监听器是对特定事件做出响应的对象。它会在事件发生时被触发,并执行相应的处理逻辑。
事件处理的过程:
- 用户在界面上与某个组件交互(如点击按钮)。
- 该组件会生成一个事件(例如
ActionEvent)。 - 事件通过事件源传播到注册的监听器(事件处理器)。
- 监听器接收事件并根据事件的类型执行对应的处理方法。
事件委托模型的优势:
- 松散耦合:事件源和监听器是解耦的,事件源不需要知道监听器的具体实现,监听器通过接口与事件源进行交互。
- 灵活性:多个监听器可以监听同一个事件源,允许事件的灵活处理。
Event / Event Source / Event Handler (Listener)
- Event(事件):
- 事件是用户与 GUI 组件交互时产生的一个对象,表示某种动作或状态变化。
- Java 提供了多种不同的事件类,如
ActionEvent(按钮点击事件),KeyEvent(键盘事件),MouseEvent(鼠标事件)等。
- Event Source(事件源):
- 事件源是产生事件的对象。在 Java 中,常见的事件源是 GUI 组件,如
Button、TextField、Label等。 - 事件源通过
addXXXListener()方法将事件监听器注册到自身。当事件发生时,事件源会通知所有已注册的监听器。
- 事件源是产生事件的对象。在 Java 中,常见的事件源是 GUI 组件,如
- Event Handler(事件处理器,Listener):
- 事件监听器是实现特定事件处理逻辑的对象。监听器实现特定的事件监听接口,并定义响应事件的方法。
- 每个事件类型都有对应的监听接口,例如:
ActionListener(用于按钮点击),MouseListener(用于鼠标事件),KeyListener(用于键盘事件)等。
Inner Class(内部类)
内部类是定义在另一个类中的类。Java 中有四种内部类类型:
- 成员内部类:定义在外部类的成员位置,且可以访问外部类的成员。
- 静态内部类:定义为
static的内部类,它不依赖于外部类的实例,因此不能访问外部类的实例成员。 - 局部内部类:定义在方法中,作用范围限定在方法内。
- 匿名内部类:没有名字的类,它是对某个类的快速实现,通常用于简化代码,特别是在事件处理时。
内部类的应用:
- 内部类可以访问外部类的成员和方法,因此它可以直接访问外部类的非静态变量和方法。
- 内部类能有效实现封装和逻辑分离,特别适合事件处理和回调等场景。
示例:
1 | class OuterClass { |
Anonymous Inner Class (匿名内部类) / Lambda Expression
1. Anonymous Inner Class (匿名内部类):
- 匿名内部类是没有名字的内部类,它通常用来简化事件监听器的实现。匿名内部类可以在创建的同时初始化并实现接口或继承类。
- 常用在事件监听中,如按钮的点击事件监听。
示例:
1 | button.addActionListener(new ActionListener() { |
匿名内部类无需单独定义一个实现类,而是直接在创建监听器时实现事件处理方法。
2. Lambda Expression (Lambda 表达式):
- 从 Java 8 开始,Java 引入了 Lambda 表达式,它是一种简洁的方式来表示函数式接口的实现,特别是对于事件监听器的处理更加简洁和清晰。
- Lambda 表达式为事件监听提供了简化的语法,避免了冗长的匿名内部类定义。
示例:
1 | button.addActionListener(e -> System.out.println("Button clicked!")); |
Lambda 表达式简化了事件处理代码,使得事件处理变得更加直观和易于维护。
Listeners for Observable Objects
在 Java 中,某些对象支持监听其状态的变化,这些对象称为
可观察对象(Observable Objects)。Java 提供了
Observable 类和 Observer
接口来实现对象状态变化的监听。
- Observable 类:
Observable是 Java 中一个抽象类,表示可被观察的对象。它维护了一些观察者(Observer)的列表,当其状态变化时,通知所有注册的观察者。 - Observer 接口:
Observer接口表示观察者,它定义了一个update()方法,用于接收被观察对象的状态变化通知。
示例:
1 | import java.util.*; |
精华
- Java 事件委托模型:通过事件源、事件和事件监听器解耦了事件的发生和处理,使得代码更加灵活和易于维护。
- 事件源与监听器:事件源产生事件,监听器接收并处理事件。通过
addXXXListener()方法将监听器注册到事件源。 - 内部类:内部类能够访问外部类的成员,常用于事件处理。匿名内部类简化了事件处理器的定义。
- Lambda 表达式:从 Java 8 开始,Lambda 表达式简化了函数式接口(如事件监听器)的实现。
- 可观察对象:
Observable类和Observer接口为对象的状态变化提供了通知机制,允许多个观察者监听对象的状态变化。
PPT-16
无
PPT-17
Text I/O 与 Binary I/O
在 Java 中,输入和输出操作分为两种主要类型:文本输入/输出(Text I/O) 和 二进制输入/输出(Binary I/O)。两者主要区别在于数据的处理方式,文本 I/O 处理的是字符数据,而二进制 I/O 处理的是原始字节数据。
1. Text I/O 与 Binary I/O 的区别
- Text I/O(文本输入/输出):
- 处理的是字符数据。文本文件通常是由字符(例如 ASCII 或 UTF-8 编码的字符)组成的。
- Java 提供了字符流类,例如
FileReader、FileWriter、BufferedReader和BufferedWriter等,主要用于字符的读取与写入。 - 文本流会自动进行字符编码与解码(例如从字节转换为字符)。
- Binary I/O(二进制输入/输出):
- 处理的是字节数据。二进制文件可以包含任何类型的数据(如图片、音频、视频、程序文件等)。
- Java 提供了字节流类,如
InputStream、OutputStream、FileInputStream、FileOutputStream、DataInputStream、DataOutputStream等,用于处理字节数据。 - 二进制流不会进行编码或解码操作,直接读取或写入字节数据。
2. InputStream 和 OutputStream
- InputStream:
InputStream是所有字节输入流的父类,用于表示字节输入流的基类。它定义了从输入流中读取字节的基本方法。- 常用方法:
read():读取一个字节并返回(返回 -1 表示流结束)。read(byte[] b):读取一定数量的字节并存储到数组中。close():关闭流。
- OutputStream:
OutputStream是所有字节输出流的父类,用于表示字节输出流的基类。它定义了向输出流写入字节的基本方法。- 常用方法:
write(int b):写入一个字节。write(byte[] b):写入字节数组。flush():刷新输出流,确保所有数据都被写入。close():关闭流。
3. FileInputStream 和 FileOutputStream
FileInputStream:
- 用于从文件中读取字节数据,继承自
InputStream类。 - 读取文件的字节流,并将内容传递给程序。
示例:
1
2
3
4
5
6FileInputStream fis = new FileInputStream("file.txt");
int byteData;
while ((byteData = fis.read()) != -1) {
System.out.print((char) byteData); // 将字节转换为字符
}
fis.close();- 用于从文件中读取字节数据,继承自
FileOutputStream:
- 用于向文件中写入字节数据,继承自
OutputStream类。 - 向指定的文件中写入字节数据。
示例:
1
2
3
4FileOutputStream fos = new FileOutputStream("file.txt");
String content = "Hello, Java!";
fos.write(content.getBytes()); // 将字符串转换为字节并写入文件
fos.close();- 用于向文件中写入字节数据,继承自
4. DataInputStream 和 DataOutputStream
DataInputStream:
DataInputStream是InputStream的子类,用于以机器无关的方式读取原始数据类型(如int、float、double、long、boolean)以及 UTF-8 编码的字符串。- 它提供了许多方法,可以直接读取 Java 中的基本数据类型。
常用方法:
readInt():读取一个int。readFloat():读取一个float。readUTF():读取一个 UTF-8 编码的字符串。
示例:
1
2
3
4DataInputStream dis = new DataInputStream(new FileInputStream("data.dat"));
int number = dis.readInt();
String name = dis.readUTF();
dis.close();DataOutputStream:
DataOutputStream是OutputStream的子类,用于以机器无关的方式写入原始数据类型。- 它提供了写入 Java 中基本数据类型的方法。
常用方法:
writeInt(int v):写入一个int。writeFloat(float v):写入一个float。writeUTF(String str):写入一个 UTF-8 编码的字符串。
示例:
1
2
3
4DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.dat"));
dos.writeInt(100);
dos.writeUTF("Hello");
dos.close();
5. BufferedInputStream 和 BufferedOutputStream
BufferedInputStream:
BufferedInputStream是InputStream的子类,使用一个缓冲区来提高读取数据的效率。它通过减少磁盘操作来提升性能。- 一般在需要频繁读取数据时使用
BufferedInputStream。
示例:
1
2
3
4
5
6BufferedInputStream bis = new BufferedInputStream(new FileInputStream("file.txt"));
int byteData;
while ((byteData = bis.read()) != -1) {
System.out.print((char) byteData); // 将字节转换为字符
}
bis.close();BufferedOutputStream:
BufferedOutputStream是OutputStream的子类,使用缓冲区来提高写入数据的效率。- 它将数据先写入缓冲区,再一次性写入磁盘,从而减少磁盘操作,提高性能。
示例:
1
2
3
4BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("file.txt"));
String content = "Buffered Output!";
bos.write(content.getBytes());
bos.close();
6. RandomAccessFile
- RandomAccessFile:
RandomAccessFile类允许随机访问文件内容,可以在文件的任意位置读写数据。它既可以用于读取数据,也可以用于写入数据。RandomAccessFile与其他流类的不同之处在于,它支持读写文件中的任意位置,而不必按顺序读取或写入。
seek(long pos):设置文件指针的位置,可以随机访问文件中的任意位置。read():读取一个字节。write(byte[] b):写入字节数组。
1
2
3
4RandomAccessFile raf = new RandomAccessFile("file.txt", "rw");
raf.seek(5); // 设置文件指针到第5个字节位置
raf.write("Hello".getBytes()); // 写入数据
raf.close();
精华:
- Text I/O 和 Binary I/O 主要的区别在于数据的处理方式:Text I/O 处理字符数据,Binary I/O 处理字节数据。
- 字节流(
InputStream和OutputStream)适用于读取和写入所有类型的数据,包括文本和二进制数据。 - 字符流(如
FileReader和FileWriter)专门用于处理文本文件。 - DataInputStream 和 DataOutputStream 提供了读取和写入 Java 原始数据类型的方法。
- BufferedInputStream 和 BufferedOutputStream 提供了带缓冲的字节流,提升了 I/O 操作的效率。
- RandomAccessFile 允许随机访问文件中的任意位置,是一种灵活的文件操作方式。
PPT-18
无
PPT-19
无
PPT-20
无
PPT-21
无







