java面向对象程序设计综合复习总结

作者:古如健


第1章 初识 Java 与面向对象程序设计

1.1 Java 概述

1.1.1 计算机编程语言发展史

机器语言:计算机直接执行的二进制指令,由0和1组成,难以阅读和编写,但执行效率高。

汇编语言:使用助记符代替机器指令,比机器语言更易理解,但仍与硬件紧密相关,移植性差。高级语言:如Fortran、C、C++等,语法更接近人类自然语言,提高了开发效率,同时具备较强的可移植性。


1.1.2 Java 语言发展史起源:由Sun Microsystems公司于1995年推出,最初设计用于嵌入式系统,命名为Oak。发展:随着互联网的兴起,Java因其跨平台特性迅速成为Web开发的主流语言,广泛应用于企业级开发、移动应用(Android)和大数据领域。现状:2010年,Oracle收购Sun Microsystems,Java继续发展,并推出了许多新特性,如Lambda表达式、模块化系统(Java 9)等。

1.1.3 Java 语言的特点简单性:语法基于C++,但去除了复杂特性(如指针和多继承),降低了学习难度。面向对象:万物皆对象,支持封装、继承和多态,使程序结构更清晰、易于维护。分布式:内置网络支持,适合开发分布式应用,如Web服务、微服务等。健壮性:强类型检查、异常处理机制,减少运行时错误,提高程序稳定性。安全性:提供安全管理机制,防止恶意代码攻击,如字节码验证器、安全管理器等。跨平台性:通过JVM实现“一次编写,到处运行”,开发者无需针对不同平台修改代码。高性能:JIT(即时编译)技术将字节码编译为本地机器码,提高执行效率。多线程:支持并发编程,提高程序效率,适合开发高并发应用。动态性:支持动态加载类和反射机制,使程序更具灵活性。

1.1.4 Java 跨平台原理字节码:Java程序编译后生成与平台无关的字节码文件(.class)。JVM:不同平台有对应的JVM实现,负责解释执行字节码文件。优势:开发者无需针对不同平台修改代码,降低了开发和维护成本,同时提高了程序的可移植性。

1.2 面向对象程序设计思想

1.2.1 面向过程程序设计核心:以过程(函数)为中心,数据和操作分离。示例:计算圆的面积,通过函数实现计算逻辑。缺点:随着程序规模增大,代码可维护性和可扩展性变差。


1.2.2 面向对象程序设计核心:以对象为中心,对象包含数据和方法。示例:定义一个“圆”类,包含半径属性和计算面积的方法。优点:更符合人类思维方式,代码可维护性和可扩展性更强。1.2.3 面向对象与面向过程的比较面向对象:适合复杂系统开发,代码结构清晰,易于维护和扩展。面向过程:适合简单任务,但随着程序规模增大,维护成本增加。


1.3 Java 开发环境搭建

1.3.1 JDK 与 JREJDK:Java开发工具包,包含编译器、调试器等开发工具。JRE:Java运行时环境,用于运行Java程序。

1.3.2 JDK 安装从Oracle官网下载适合操作系统的JDK版本并安装。

1.3.3 环境变量配置配置JAVA_HOME指向JDK安装目录。将%JAVA_HOME%\bin添加到系统的PATH变量中。1.4 第一个 Java 程序:HelloWorld!

1.4.1 显示文件扩展名在操作系统中设置显示文件扩展名,以便识别.java和.class文件。1.4.2 编写代码创建HelloWorld.java文件,内容如下:


1.4.3 编译与执行

使用javac HelloWorld.java编译生成.class文件。

使用java HelloWorld运行程序。

1.4.4 代码解析

public class HelloWorld:定义一个公共类。

public static void main(String[] args):程序入口点。

System.out.println("Hello, World!");:输出字符串到控制台。

1.4.5 代码的注释

单行注释:// 这是单行注释。

多行注释:/* 这是多行注释 */。

1.5 Java 常用开发工具

1.5.1 IntelliJ IDEA

下载并安装IntelliJ IDEA,利用其智能提示、代码重构等功能进行开发。

1.6 本章思政元素融入点

强调编程规范和职业道德,如代码版权保护、开源精神等。

在编程实践中培养耐心、细心和创新精神。

1.7 本章小结

本章介绍了Java的特点、面向对象思想、开发环境搭建以及第一个Java程序的编写。

1.8 习题

编写简单的Java程序,如实现一个计算器,支持加、减、乘、除运算。


第2章 Java 编程基础

2.1 变量与常量

2.1.1 核心概念

关键字:Java中具有特定语法功能的保留字,如public、class、if等,不能用作自定义标识符。

保留字:目前未作为关键字,但为Java预留备用的词,如goto、const等。

标识符:用于给变量、类、方法等命名的字符序列,需遵循命名规范(如以字母、下划线或美元符号开头,不能以数字开头)。

数据类型:分为基本数据类型(如int、double、char、boolean等)和引用数据类型(如类、接口、数组等)。


知识点及示例代码

命名规范示例

变量名通常采用驼峰命名法,例如studentName(变量名以小写字母开头,后续单词首字母大写);类名采用大写字母开头的驼峰命名法,如StudentClass。

基本数据类型示例

变量:在程序运行过程中其值可以改变的量,需先定义再赋值后使用。

常量:程序运行期间其值不能被改变的量,使用final关键字修饰。



续表

变量定义与赋值示例


类型转换示例


Scanner 使用示例:

2.2 运算符与表达式

核心概念:

算术运算符:用于进行基本的数学运算,如加、减、乘、除、取余以及自增、自减操作。

赋值运算符:将值赋给变量,包括基本赋值(=)和复合赋值(如 +=、-= 等)运算符。

关系运算符:比较两个值的大小关系,结果为布尔值(true 或 false)。

逻辑运算符:用于对布尔值进行逻辑运算,如逻辑与、逻辑或、逻辑非。

位运算符:对整数的二进制位进行操作,如按位与、按位或、按位异或等。

三元运算符:根据条件表达式的结果返回两个值中的一个,格式为 条件表达式? 值 1 : 值 2。

运算符优先级:决定表达式中不同运算符执行的先后顺序。

知识点及示例代码

算术运算符示例


赋值运算符示例


关系运算符示例


逻辑运算符示例


三元运算符示例


2.3 选择结构

核心概念:

if 语句:根据条件表达式的真假来决定是否执行特定的代码块,可包含 if - else、if - else if - else 等多种形式。

switch 语句:基于表达式的值选择执行多个分支中的一个,表达式类型有限制(整数、字符、枚举、字符串等),每个分支需用 break 跳出(除非有意贯穿执行)。

选择结构嵌套:在一个选择结构内部再嵌套其他选择结构,以实现更复杂的条件判断逻辑。

两种选择结构对比:理解 if 语句和 switch 语句各自适用的场景及优缺点。

知识点及示例代码:

if 语句示例:


switch 语句示例


选择结构嵌套示例


2.4 循环结构

核心概念:

for 语句:适用于已知循环次数的情况,通过初始化表达式、条件表达式和更新表达式控制循环过程。

while 语句:根据条件表达式的真假决定是否重复执行循环体,循环变量初始化一般在循环外进行,需手动更新循环变量。

do...while 语句:先执行一次循环体,再根据条件表达式决定是否继续循环,保证循环体至少执行一次。

break 和 continue 语句:break 用于跳出当前循环结构;continue 用于跳过本次循环体剩余代码,直接进入下一次循环条件判断。

循环语句嵌套:在一个循环内部嵌套另一个循环,常用于处理多维数据或复杂重复逻辑。

三种循环结构应用场景:掌握不同循环结构适合的具体编程场景。

知识点及示例代码:

for 语句示例:


while 循环


do...while 循环


break 语句


continue 语句


循环嵌套


写一个九九乘法表:


2.5 方法

核心概念:

方法:可重复调用的代码块,用于封装特定功能,提高代码复用性、可读性和可维护性,可接收参数并返回值(或无返回值)。

方法声明:包括访问修饰符、返回类型、方法名、参数列表等部分。

方法调用:通过方法名及对应参数列表来执行方法。

方法重载:在同一类中定义多个同名方法,但参数列表不同(个数、类型、顺序有差异),编译器根据传入参数自动选择合适的方法调用。

方法递归:方法自身调用自身的编程技巧,需设定递归终止条件,否则会导致无限递归。

知识点及示例代码:

方法声明与调用示例:


方法重载示例


方法递归示例


2.6 数组

核心概念:

数组:存储相同类型数据的容器,具有固定长度,通过索引访问元素(索引从 0 开始),分为一维数组和多维数组(如二维数组)。

数组常见操作:初始化、访问元素、修改元素、遍历等操作方法。

数组排序算法:如冒泡排序、选择排序、插入排序等,用于将数组元素按特定顺序排列。

二分查找法:基于有序数组进行快速查找元素的方法,通过不断缩小查找范围来定位目标元素。

可变参数:允许方法接收不定数量的参数,通过特定语法在参数类型后添加省略号(...)来实现。

Arrays 工具类:提供诸多便捷操作数组的静态方法,如排序、比较、填充等功能。

知识点及示例代码:

数组初始化与访问示例:


冒泡排序示例


二分查找法示例


2.7 JVM 中的堆内存与栈内存

2.7.1 堆和栈

核心概念:

栈内存:主要用于存储局部变量、方法调用的相关信息(如方法的返回地址、参数等),遵循后进先出(LIFO)的原则,其内存分配和释放由系统自动管理,当方法执行结束时,对应的栈帧(存放方法相关信息的内存区域)就会被销毁,局部变量所占内存也随之释放。

堆内存:用于存储通过 new 关键字创建的对象实例以及数组等,是 JVM 中最大的一块内存区域,由垃圾回收器(GC)负责回收不再使用的对象内存,以管理内存的分配和释放,程序员一般不需要手动干预,但需要注意避免内存泄漏等问题。

2.7.2 数据类型传递

核心概念:

值传递:在 Java 中,基本数据类型作为参数传递给方法时,传递的是实际的值,方法内对参数的修改不会影响到方法外原来的变量值。

引用传递(本质也是值传递,但传递的是对象的引用地址):对于引用数据类型,传递给方法的是对象的引用,在方法内通过该引用对对象进行修改会影响到方法外指向该对象的引用所对应的对象状态,但如果重新赋值引用,不会影响方法外原来的引用指向。

2.7.3 方法中的数据交换

核心概念:

在方法中交换两个变量的值,对于基本数据类型,直接交换形参的值无法影响到方法外实参的值,因为是值传递;对于引用数据类型,如果是交换对象内部的数据成员等是可行的,但如果是单纯交换两个引用本身,同样需要考虑是传递引用地址的特性以及是否会影响方法外的引用指向情况。

知识点及示例代码(以基本数据类型交换为例说明值传递影响):

2.8 本章思政元素融入点

核心概念:

编程规范与职业道德:在编写 Java 代码过程中,要遵循代码规范,如命名规范、代码结构合理等,培养严谨、细致的编程习惯,同时尊重知识产权,不抄袭代码,正确使用开源资源并遵循开源协议,养成良好的职业道德。

团队协作与沟通:在实际项目开发中,尤其是面对较为复杂的功能模块涉及多人合作时,要学会团队协作,理解他人代码逻辑,做好接口设计与沟通交流,共同解决遇到的技术问题,提高团队整体效率。

解决问题的思维培养:通过学习 Java 编程基础中的各种概念、算法等,锻炼逻辑思维和分析解决问题的能力,遇到问题时冷静分析、逐步排查,尝试不同的解决方案,养成积极面对并攻克难题的思维习惯。

2.9 本章小结

核心概念:

对整个 Java 编程基础章节所学内容进行总结回顾,涵盖变量与常量、运算符与表达式、选择结构、循环结构、方法、数组以及 JVM 内存相关知识等,梳理各知识点之间的联系以及如何综合运用这些知识来编写 Java 程序,明确掌握这些基础内容对于后续深入学习 Java 编程的重要性。

第3章 面向对象程序设计(基础)

3.1 面向对象的概念

核心概念:

面向对象思想:将现实世界中的事物抽象为对象,对象具有属性和行为,通过对象之间的交互来构建程序逻辑,模拟和解决现实问题。

面向对象特性:

封装:把对象的属性和方法结合成一个独立的系统单元,并尽可能隐藏对象的内部细节,只对外提供必要的接口。例如,将汽车的发动机、轮胎等属性以及启动、行驶等方法封装在 Car 类中,外部使用者无需了解其内部复杂的机械结构和运行原理,只需调用相应的方法即可操作汽车。

继承:一个子类可以继承其父类的属性和方法,实现代码复用和功能扩展。比如,SportsCar 类可以继承自 Car 类,继承 Car 的基本属性如车轮数量、颜色等,以及行驶方法,同时还可以添加自己特有的属性如最高时速、加速性能等方法。

多态:不同的对象对相同的消息(方法调用)产生不同的响应。例如,Animal 是一个父类,Cat 和 Dog 是其子类,它们都继承了 Animal 的 makeSound 方法,但 Cat 的 makeSound 方法可能是发出 “喵呜” 声,而 Dog 的 makeSound 方法则是发出 “汪汪” 声。当调用 Animal 类型的对象的 makeSound 方法时,会根据对象的实际类型(是 Cat 还是 Dog)执行相应的声音输出,这就是多态的体现。

类和对象:

类:是对具有相同属性和行为的一组对象的抽象描述,是创建对象的模板。例如,Person 类可以定义人的通用属性如姓名、年龄、性别等,以及行为方法如说话、行走等。

对象:是类的具体实例,具有类所定义的特定属性值和行为能力。例如,Person 类的一个对象可以是名为 “张三”,年龄为 20 岁的具体个人。

3.2 面向对象编程

核心概念:

类的定义:


对象的创建与使用



这里使用了

class

用于定义一个类。例如:class Person { ... }。

new

用于创建对象。例如:Person person = new Person();。

void:用于声明方法没有返回值。例如:void introduce() { ... }。

public:用于修饰类或方法,表示公开访问。例如:public class ObjectExample { ... }。

static:用于修饰方法或变量,表示属于类而非对象。例如:public static void main(String[] args) { ... }。

第四章 面对对象程序设计(进阶)

4.2封装

封装是面向对象程序设计(OOP)中的一个核心概念,它涉及到将数据(属性)和操作数据的方法(行为)捆绑在一起,形成一个对象。以下是封装的一些关键点复习总结:

什么是封装:封装是将对象的实现细节隐藏起来,只暴露出一个可以被外界访问的接口。这样,对象的内部状态不会被外部直接修改,从而保护了对象的完整性。

访问修饰符

public:成员可以被任何其他类访问。

protected:成员可以被定义它们的类本身、该类同一包中的其他类以及该类的子类访问。

private:成员只能被定义它们的类访问。

get()/set()方法

get方法用于获取私有属性的值。

set方法用于设置私有属性的值,通常在设置值之前会进行一些验证。

封装的好处

隐藏实现细节,保护对象的完整性。

提高代码的可维护性和可扩展性。

允许独立地修改对象的实现,而不影响使用该对象的代码。

封装的实践

将类的属性设置为私有(private)。

提供公共的get和set方法来访问和修改这些私有属性。

在set方法中加入逻辑来验证属性值的有效性。

封装与继承、多态的关系

封装是继承和多态的基础。通过封装,子类可以继承父类的属性和方法,同时可以重写(override)方法来实现多态。

封装的注意事项

合理使用访问修饰符,避免过度公开或过度隐藏。

在设计类的时候,考虑哪些属性和方法应该是公开的,哪些应该是私有的。

通过封装,我们可以创建出更加健壮、易于维护和扩展的软件系统。在实际开发中,封装是实现模块化和降低系统复杂性的重要手段。

封装是面向对象编程中的一个基本概念,它涉及到将数据(属性)和操作这些数据的方法(行为)结合在一起,并对外部隐藏对象的内部状态和行为的实现细节。以下是使用Java语言实现封装的示例:


4.2继承

继承是面向对象编程(OOP)中的一个核心概念,它允许我们创建基于现有类的新的类。继承提供了代码重用和扩展现有功能的能力。以下是继承的一些关键点总结:

基本概念

父类(基类、超类):被继承的类,提供了一些基本属性和方法。

子类(派生类):继承父类的类,可以添加新的属性和方法,或者覆盖父类的方法。

继承的优点

代码重用:子类可以继承父类的属性和方法,减少代码重复。

扩展性:子类可以扩展父类的功能,增加新的属性和方法。

维护性:修改父类的方法会影响到所有继承该父类的子类,方便统一维护。

继承的实现

在Java中,使用extends关键字来实现继承:


方法覆盖(Override)

子类可以覆盖父类的方法,提供特定的实现:


构造函数

子类的构造函数需要调用父类的构造函数,通常使用super()关键字。


访问控制

子类继承父类的属性和方法时,访问权限会遵循原有的访问控制(public、protected、private)。

继承的层次结构

继承可以形成层次结构,一个父类可以有多个子类,一个子类也可以有子类(孙类),形成继承链。

多态性

继承支持多态性,允许我们用父类类型的引用指向子类的对象,并调用相应的方法。

注意事项

继承应该谨慎使用,过度使用继承可能导致类结构过于复杂。

继承破坏了封装性,因为子类依赖于父类的内部结构。

考虑使用组合和接口实现来替代继承,以提高灵活性和降低耦合度。

继承是实现代码重用和扩展功能的强大工具,但也需要合理使用,以保持代码的清晰和可维护性。

4.3 super关键字

1. 调用父类的构造函数

super关键字可以用来调用父类的构造函数,这在子类的构造函数中非常有用,尤其是在需要初始化继承的属性时。例如:


2. 访问父类的属性和方法

super可以用来访问父类的属性和方法,这在子类中覆盖(Override)了父类的方法或需要同时使用父类和子类版本的属性或方法时非常有用。例如:


3. 在子类构造函数中初始化父类属性

在子类的构造函数中,super可以用来初始化继承的属性,确保父类的构造函数被正确调用,从而正确初始化所有继承的属性。

4. 使用super作为前缀

在某些情况下,super可以用作前缀来引用父类中的属性和方法,以区分同名的子类属性和方法。这在子类覆盖了父类的方法或属性时特别有用。

注意事项

super必须在子类构造函数的第一行使用,因为任何构造函数的第一条语句都是调用父类的构造函数。

如果子类的构造函数没有显式调用super(),编译器会自动插入super()。

如果父类的构造函数是私有的,那么子类将无法使用super来调用它。

super不能用来调用final方法,因为final方法不能被子类覆盖。

总的来说,super关键字是Java中实现继承和多态性的重要工具,它允许子类与父类进行交互,包括调用父类的构造函数、方法和属性。正确使用super可以确保类的继承关系被正确处理,同时保持代码的清晰和可维护性。

4.4 final关键字

final关键字在Java中是一个非常重要的修饰符,它有多种用途,主要用于限制代码的修改和增强性能。以下是final关键字的一些主要用途和总结:

1. 最终变量

基本数据类型的变量:将基本数据类型的变量声明为final意味着一旦赋值后,其值就不能被改变。

引用类型的变量:将引用类型的变量声明为final意味着变量引用的对象不能被改变,但对象内部的状态可以被修改(除非对象本身也是不可变的)。


2. 最终方法

将方法声明为final意味着这个方法不能被子类覆盖。这通常用于确保方法的实现不会被改变,或者用于优化(因为JVM可以内联最终方法)。


3. 最终类

将类声明为final意味着这个类不能被继承。这通常用于防止类的实现被扩展,确保类的完整性。


4. 性能优化

由于final方法不能被子类覆盖,JVM和JIT编译器可以对这些方法进行更多的优化,如方法内联,这可以提高程序的执行效率。

5. 匿名内部类中的final变量

在匿名内部类中,如果需要使用外部方法的局部变量,这个变量必须被声明为final或事实上的final(即在声明后没有被修改)。


注意事项

final变量一旦被赋值后,其值就不能被改变。

final方法和final类提供了一种机制来防止代码被不当修改,增强代码的安全性和稳定性。

final关键字的使用应该谨慎,因为它会限制代码的灵活性。

总的来说,final关键字是Java中一个强大的工具,它可以用来确保数据的不变性,限制类的继承和方法的覆盖,以及优化性能。正确使用final可以提高代码的安全性和效率。

4.5 Object类

在Java中,Object类是所有类的根父类,位于类继承层次结构的最顶端。这意味着Java中的每个类都是Object类的子类,直接或间接地继承了Object类。以下是Object类的一些关键点总结:

基本属性

Object类本身没有属性。

基本方法

equals(Object obj)

用于比较两个对象的引用是否相等。默认实现比较的是对象的内存地址。

通常需要被重写以提供逻辑上的相等比较(例如,比较对象的内容)。

hashCode()

返回对象的哈希码值,通常用于哈希表。

好的哈希函数应该尽量减少哈希冲突,并且当重写equals()方法时,应该同时重写hashCode()方法,以保持一致性。

toString()

返回对象的字符串表示。

默认返回对象的类名、@符号和对象的哈希码的无符号十六进制表示。

通常需要被重写以提供更有意义的信息。

getClass()

返回对象的运行时类信息。

notify()notifyAll()

用于多线程编程,唤醒在此对象监视器上等待的一个或所有线程。

wait()

导致当前线程等待,直到另一个线程调用此对象的notify()或notifyAll()方法。

重要特性

多态性:Object类的方法在子类中可以被重写,这是多态性的体现。

封装性:Object类的方法提供了基本的封装机制,如equals()和hashCode()。

继承性:作为根类,Object类体现了Java的单一继承特性。

使用场景

通用编程:Object类的方法在通用编程中非常有用,比如在集合框架中比较和存储对象。

多线程编程:wait()、notify()和notifyAll()方法在多线程编程中用于线程间的协调。

重写方法的建议

equals()和hashCode():当重写equals()方法时,通常也需要重写hashCode()方法,以确保相等的对象有相同的哈希码。

toString():重写toString()方法可以提供对象的更有意义的字符串表示,这对于调试和日志记录非常有用。

注意事项

性能:频繁调用toString()、equals()和hashCode()方法可能会影响性能,尤其是在大型集合中。

线程安全:wait()、notify()和notifyAll()方法需要在同步块或方法中使用,以避免线程安全问题。

Object类是Java中所有类的基石,提供了一组基本的方法,这些方法在Java编程中扮演着重要的角色。理解和正确使用Object类的方法,可以帮助我们编写出更健壮、更高效的Java程序。


4.6多态

多态是面向对象编程(OOP)的一个核心概念,它允许不同类的对象对同一消息做出响应。多态性使得方法调用在编译时不需要确定具体的类,而是在运行时根据对象的实际类型来决定调用哪个方法。以下是多态的一些关键点总结:

多态的类型

编译时多态(静态多态)

通过方法重载(方法名相同,参数列表不同)和方法覆盖(子类重写父类方法)实现。

编译器在编译时就能确定具体调用哪个方法。

运行时多态(动态多态)

通过方法覆盖和接口实现实现。

调用哪个方法取决于运行时对象的实际类型。

多态的实现条件

继承

子类继承父类,并重写父类的方法。

接口实现

类实现一个或多个接口,并提供接口中声明方法的具体实现。

方法覆盖

子类提供一个与父类同名的方法,并且参数列表相同。

向上转型

将子类的对象赋值给父类的引用变量。

多态的优点

提高代码的可维护性

通过多态,可以在不修改现有代码的情况下扩展新功能。

提高代码的可读性和可复用性

多态允许开发者编写更通用的代码,减少重复代码。

解耦合

多态允许将接口和实现分离,降低类之间的耦合度。

多态的注意事项

方法签名

只有方法名和参数列表完全匹配时,子类的方法才能覆盖父类的方法。

访问修饰符

如果父类中的方法访问修饰符为private,则子类无法覆盖该方法。

final方法

被声明为final的方法不能被覆盖。

static方法

静态方法不参与多态,因为静态方法属于类不属于对象。

多态的示例


4.7

抽象类是面向对象编程中的一个概念,它是一种不能被实例化的类,通常用来作为其他类的基类。抽象类可以包含抽象方法,这些方法只有声明没有实现,迫使子类去实现这些方法。以下是抽象类的一些关键点总结:

定义抽象类

在Java中,使用abstract关键字来定义一个抽象类:


抽象方法

抽象类可以包含抽象方法,这些方法没有具体的实现,只有声明:


抽象类的特点

不能被实例化

你不能创建抽象类的实例。

可以包含构造函数

尽管不能直接实例化,但抽象类可以有构造函数,主要用于子类调用父类的构造函数。

可以包含属性和具体方法

抽象类可以包含属性和具体的方法实现。

可以被继承

非抽象子类必须实现抽象类中的所有抽象方法,除非该子类也是抽象的。

抽象类的作用

代码复用

提供一个公共的父类,使得子类可以继承共同的属性和方法。

模板方法设计模式

定义一个算法的框架,让子类在不改变算法结构的情况下重新定义算法的某些步骤。

强制子类实现特定方法

通过抽象方法,强制子类去实现某些行为。

抽象类的使用场景

当你有一个类层次结构,并且希望强制子类实现特定的方法时。

当类的设计允许存在多种子类,且子类之间共享共同的属性和方法时。

抽象类的示例


4.8接口

接口(Interface)在Java中是一种引用类型,它定义了一组抽象方法,这些方法可以由任何实现了该接口的类来具体实现。以下是接口的一些关键点总结:

定义接口

在Java中,使用interface关键字来定义一个接口:


接口的特点

完全抽象

在Java 8之前,接口只能包含抽象方法和常量。

从Java 8开始,接口可以包含默认方法(带有实现的方法)和静态方法。

不能被实例化

接口不能被直接实例化,必须通过实现接口的类来创建对象。

多继承

一个类可以实现多个接口,这允许形式上的多继承。

没有构造函数

接口不能包含构造函数。

没有实现

接口中的方法默认是抽象的,除非提供了默认实现。

接口的方法类型

抽象方法

只有方法声明,没有方法体。

默认方法(Java 8及以后):

有方法声明和方法体,允许接口有默认实现。

静态方法(Java 8及以后):

可以在接口中直接实现静态方法。

接口的作用

定义规范

接口定义了一组规范,任何实现该接口的类都必须遵守这些规范。

实现多继承

通过实现多个接口,一个类可以获得多个来源的行为。

解耦合

接口提供了一种方式,允许类在不依赖于具体实现的情况下进行交互。

类型安全

接口提供了一种类型安全的方式,确保实现类提供了必要的方法。

接口的实现

一个类通过使用implements关键字来实现一个接口:


接口的继承

一个接口可以通过extends关键字扩展另一个或多个接口:


接口的示例


在这个例子中,Printable是一个接口,它定义了一个print()方法。Document类实现了Printable接口,并提供了print()方法的具体实现。

总的来说,接口是Java中实现抽象和多态的重要工具,它们定义了一组方法规范,允许不同的类以统一的方式交互,同时提供了一种形式上的多继承机制。

第五章 异常

5.1异常概述

异常处理是编程中用于处理程序执行过程中出现的非预期情况(如错误和异常条件)的一种机制。在Java中,异常处理是一种结构化的方式来处理程序运行时可能出现的错误。以下是异常处理的一些关键点概述:

异常类

Java中的所有异常都是Throwable类的子类。

Throwable有两个重要的子类:Exception(可检查异常)和Error(系统错误)。

异常类型

检查型异常(Checked Exception)

这些是程序必须显式处理的异常(通过捕获或声明抛出)。

例子包括IOException和SQLException。

非检查型异常(Unchecked Exception)

这些是程序不需要显式处理的异常。

包括运行时异常(RuntimeException)和错误(Error)。

例子包括NullPointerException和ArithmeticException。

异常处理机制

try语句块

使用try块来包裹可能抛出异常的代码。

catch语句块

用来捕获并处理特定类型的异常。

finally语句块

无论是否捕获到异常,finally块中的代码都会执行,常用于资源清理。

throw关键字

用于手动抛出异常。

throws关键字

用于在方法签名中声明该方法可能抛出的异常。

异常处理的步骤

识别潜在的异常

确定代码中可能抛出异常的位置。

捕获异常

使用try-catch块来捕获并处理异常。

处理异常

在catch块中实现异常处理逻辑。

资源清理

在finally块中释放资源,如关闭文件流。

声明抛出异常

使用throws关键字声明方法可能抛出的异常。

异常处理的示例


异常处理的最佳实践

不要忽略异常

捕获异常时,应提供有意义的处理逻辑,而不是仅仅捕获它们。

不要过度使用异常

异常应该用于处理真正的异常情况,而不是正常的程序流程控制。

使用自定义异常

根据需要创建自定义异常类,以提供更具体的错误信息。

避免在finally块中抛出新异常

finally块中抛出的异常会覆盖当前捕获的异常,这可能导致调试困难。

资源管理

使用try-with-resources语句自动管理资源,如文件和数据库连接。

异常处理是Java程序中不可或缺的一部分,它帮助程序更加健壮和可靠,能够优雅地处理错误和异常情况。正确使用异常处理机制可以提高程序的稳定性和用户体验。

复制再试一次分享

5.2 异常处理

异常处理是Java编程中用于管理和响应程序运行时错误的一种机制。以下是异常处理的关键点总结:

异常类层次结构

所有异常类都是java.lang.Throwable类的子类。

Throwable有两个主要子类:Exception和Error。

Exception:可控制的异常,分检查型异常(checked exceptions)和非检查型异常(unchecked exceptions)。

Error:不可控异常,通常是JVM问题,如OutOfMemoryError。

检查型异常 vs 非检查型异常

检查型异常:必须被捕获或声明抛出的异常,例如IOException、SQLException。

非检查型异常:运行时异常(RuntimeException及其子类),例如NullPointerException、ArithmeticException,编译器不强制处理。

异常处理关键字

try:用于包裹可能抛出异常的代码块。

catch:用于捕获特定类型的异常,并进行处理。

finally:无论是否捕获异常,finally块中的代码都会执行,常用于资源清理。

throw:用于手动抛出异常。

throws:用于在方法签名中声明该方法可能抛出的异常。

异常处理流程

识别潜在异常:确定代码中可能抛出异常的位置。

捕获异常:使用try-catch结构捕获异常。

处理异常:在catch块中编写处理异常的逻辑。

资源清理:在finally块中释放资源,确保资源总是被正确清理。

声明抛出异常:使用throws关键字声明方法可能抛出的异常。

异常处理的最佳实践

具体且有意义的异常处理:避免捕获所有异常并使用空的catch块。

避免异常用于流程控制:异常应该用于处理真正的异常情况,而不是正常的程序流程控制。

使用自定义异常:根据需要创建自定义异常类,以提供更具体的错误信息。

避免在finally块中抛出新异常:finally块中抛出的异常会覆盖当前捕获的异常,这可能导致调试困难。

资源管理:使用try-with-resources语句自动管理资源,如文件和数据库连接。

示例代码


异常处理是确保程序稳定性和健壮性的关键部分,它允许程序在遇到错误时优雅地恢复或终止,而不是产生不可预测的行为。正确和合理地使用异常处理机制,可以提高程序的质量和用户体验。

第6章 java常用类

包装类在Java中扮演着至关重要的角色,它们为基本数据类型提供了对象的形式,使得基本类型也能使用对象特有的功能,如方法调用、继承等。以下是对Java中包装类的一个总结:

包装类概述

包装类是Java为每个基本数据类型提供的对应的类,它们位于java.lang包中。包装类的主要作用包括:

提供对象形式的基本类型:允许基本类型参与需要对象的方法或操作。

提供类型安全:避免基本类型和对象之间的混淆。

提供额外的方法:如字符串表示、比较、包装和拆箱等。

基本包装类及其对应关系

int -> Integer

byte -> Byte

short -> Short

long -> Long

float -> Float

double -> Double

char -> Character

boolean -> Boolean

包装类的特性

不可变性:除了Boolean和Character,大多数包装类是不可变的,一旦创建,其值就不能改变。

自动装箱与拆箱:Java 5引入了自动装箱(将基本类型转换为包装类)和拆箱(将包装类转换为基本类型)的特性,简化了类型转换。

缓存机制:对于Integer和Long,Java提供了一个缓存机制,用于存储-128到127之间的Integer对象和-1024到1024之间的Long对象,以提高性能。

包装类的方法

包装类提供了多种方法,用于执行常见的操作,如:

toString():返回对象的字符串表示。

equals():比较两个对象的值是否相等。

hashCode():返回对象的哈希码。

compareTo():比较两个对象的大小。

示例代码


大数字运算

对于超出基本数据类型范围的大数字,Java提供了BigInteger和BigDecimal类,它们允许进行高精度的数学运算。


包装类在Java中是连接基本类型和对象之间的桥梁,它们提供了丰富的方法和特性,使得基本类型也能享受到对象的好处。自动装箱和拆箱的引入,进一步简化了编程,使得Java语言更加灵活和强大。

6.2 String类概述

String类在Java中是一个非常核心的类,用于表示字符串。字符串是不可变的字符序列,这意味着一旦创建,它们的值就不能被改变。以下是String类的一些关键点概述:

不可变性

由于String对象是不可变的,对String对象的任何修改都会创建一个新的String对象。

这个特性使得String对象线程安全。

字符串池

Java有一个字符串池(String Pool),用于存储所有字符串字面量。

当你创建一个新的字符串时,Java会首先检查字符串池中是否已经存在相同的字符串,如果存在,则不会创建新的对象,而是返回池中对象的引用。

这样可以节省内存并提高性能。

基本操作

String类提供了大量的方法来操作字符串,包括:

连接字符串:concat(), + 操作符。

比较字符串:equals(), equalsIgnoreCase(), compareTo()。

查找字符和子字符串:charAt(), indexOf(), contains(), startsWith(), endsWith()。

转换大小写:toLowerCase(), toUpperCase()。

修剪空白:trim(), strip()。

分割字符串:split()。

替换和去除字符:replace(), replaceAll(), remove()。

字符串创建

字符串可以通过多种方式创建:

使用双引号创建字符串字面量,如 String s = "Hello";。

使用new关键字和String构造函数,如 String s = new String("Hello");。

使用字符串连接,如 String s = "Hello" + "World";。

字符串与字符数组

String类提供了将字符串转换为字符数组的方法:toCharArray()。

也提供了从字符数组创建字符串的方法:new String(char[] value)。

Unicode支持

Java中的String使用Unicode编码,可以表示世界上大多数语言的字符。

多线程和性能

由于字符串的不可变性,String对象在多线程环境中是安全的。

在性能方面,由于字符串池的存在和字符串的不可变性,频繁的字符串操作可能会导致性能问题,尤其是在大量创建和销毁字符串时。

示例代码


String类是Java编程中使用最频繁的类之一,理解其特性和行为对于编写高效和安全的Java程序至关重要。

6.3 StringBuffer类与StringBuilder类

StringBuffer类和StringBuilder类都是Java中用于创建可变字符串的类,它们提供了一种在原有字符串基础上进行修改的方法,而不需要每次都创建一个新的字符串对象。以下是这两个类的主要特点和区别的总结:

StringBuffer类

线程安全:StringBuffer是线程安全的,这意味着它的方法是同步的,可以在多线程环境中安全使用。

性能:由于线程安全的需要,StringBuffer的性能比StringBuilder稍慢,因为它的方法是同步的。

使用场景:当字符串在多线程环境中被修改时,应该使用StringBuffer。

StringBuilder类

非线程安全:StringBuilder不是线程安全的,它的方法是最快的,因为没有同步的开销。

性能:在单线程环境中,StringBuilder的性能优于StringBuffer。

使用场景:当字符串在单线程环境中被修改,或者不需要保证线程安全时,应该使用StringBuilder。

共同特性

可变字符串:StringBuffer和StringBuilder都允许字符串在原有基础上进行修改。

丰富的方法:两者都提供了丰富的方法来进行字符串操作,如append(), insert(), delete(), replace()等。

初始容量:都可以在创建实例时指定初始容量,以提高性能。

链式编程:两者都支持链式编程,可以连续调用多个方法。

示例代码


性能比较

在单线程环境中,StringBuilder通常比StringBuffer更快,因为它不需要进行同步。然而,在多线程环境中,如果多个线程同时修改同一个字符串,使用StringBuffer可以避免数据不一致的问题。

总结

选择StringBuffer还是StringBuilder取决于你的具体需求。如果你的程序是多线程的,并且字符串会被多个线程修改,那么StringBuffer是更好的选择。如果你的程序是单线程的,或者你不需要线程安全,那么StringBuilder将提供更好的性能。在Java 5之后,由于自动装箱和拆箱的引入,这两个类的使用变得更加方便和直观。

6.4 时间和日期相关类

在Java中,处理时间和日期是一个常见的需求,Java提供了多个类来帮助开发者处理时间日期相关的操作。以下是Java中时间和日期相关类的一个总结:

java.util.Date

Date类用于表示特定的瞬间,精确到毫秒。

它是java.util包的一部分,从Java 0版本开始就存在。

Date对象可以直接与毫秒数(自1970年1月1日00:00:00 GMT以来的毫秒数)相互转换。

java.util.Calendar

Calendar类是一个抽象类,提供了一个日历系统,用于对Date对象进行操作。

它允许开发者执行各种操作,如添加、减去天数,设置和获取日期和时间字段等。

Calendar是线程不安全的。

java.text.SimpleDateFormat

SimpleDateFormat类是用于格式化和解析日期的具体类,继承自DateFormat类。

它允许开发者根据自定义的模式格式化和解析Date对象。

SimpleDateFormat不是线程安全的,每个线程都应该有自己的实例或者适当地同步。

java.util.TimeZone

TimeZone类表示时区,它允许开发者处理与时区相关的操作。

它与Calendar和Date类一起使用,以处理不同时区的时间。

java.time(Java 8+)

从Java 8开始,引入了新的日期和时间API,位于java.time包中,提供了更加全面和一致的日期时间操作能力。

LocalDate:表示没有时区信息的日期,例如2014-03-05。

LocalTime:表示没有时区信息的时间,例如14:30。

LocalDateTime:表示没有时区信息的日期和时间,例如2014-03-05T14:30。

ZonedDateTime:表示带时区的日期和时间。

Instant:表示一个时间点,基于UTC的时区。

DurationPeriod:分别表示时间持续和日期持续。

Clock:提供当前日期时间或者固定日期时间的访问。

旧API与新API的比较

旧API(Date、Calendar、SimpleDateFormat)在多线程环境下需要特别的注意,因为它们大多数不是线程安全的。

新API(java.time包中的类)是不可变的且线程安全的。

新API提供了更好的时间日期操作能力,例如时区处理、日期时间计算等。

示例代码

使用旧API:


使用新API:


总的来说,Java 8引入的java.time包提供了更加强大和灵活的日期时间处理能力,推荐在新的项目中使用。对于维护旧代码或者需要与旧的系统兼容时,可能还需要使用Date、Calendar等旧API。

6.5 其他常用类

Java提供了大量的类来支持各种操作,以下是一些除了String、异常处理、时间日期处理之外的常用类的总结:

java.util.ArrayList

ArrayList是List接口的一个实现,基于动态数组实现。

它允许对元素的快速随机访问,但在列表的中间或开始处插入和删除元素时可能较慢。

ArrayList不是同步的。

java.util.LinkedList

LinkedList也是List接口的一个实现,基于双向链表实现。

它提供了在列表的任何位置快速插入和删除元素的能力。

LinkedList同样不是同步的。

java.util.HashMap

HashMap是Map接口的一个实现,基于哈希表实现。

它允许快速插入、删除和访问键值对。

HashMap不保证映射的顺序,且不是同步的。

java.util.TreeMap

TreeMap是Map接口的一个实现,基于红黑树实现。

它保证了键值对的排序,通常是按照键的自然顺序或指定的比较器。

TreeMap不是同步的。

java.util.HashSet

HashSet是Set接口的一个实现,基于HashMap实现。

它不允许重复元素,并且不保证元素的顺序。

HashSet不是同步的。

java.util.TreeSet

TreeSet是Set接口的一个实现,基于TreeMap实现。

它不允许重复元素,并且元素将按照自然顺序或指定的比较器排序。

TreeSet不是同步的。

java.util.Collections

Collections是一个包含静态方法的工具类,用于操作和返回集合。

提供了诸如排序、搜索、替换、反转等对集合的操作。

java.util.Arrays

Arrays是一个包含静态方法的工具类,用于操作和返回数组。

提供了排序、搜索、比较等对数组的操作。

java.util.Scanner

Scanner类用于解析基本类型和字符串的简单文本扫描。

它可以解析原始类型(如int、double)和String。

java.io.File

File类表示文件和目录路径名的抽象表示。

它提供了文件创建、删除、重命名、设置权限等操作。

java.net.URL

URL(Uniform Resource Locator)类表示一个统一资源定位符。

它用于表示资源的位置,如网页、文件等。

java.util.concurrent 包

这个包提供了对并发程序设计的支持,包括线程安全的集合、同步器等。

例如,ConcurrentHashMap、CopyOnWriteArrayList、ExecutorService等。

示例代码


这些类是Java编程中非常基础和常用的类,它们提供了处理集合、文件、网络资源等操作的基本工具,是任何Java程序员都应该熟悉的。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容