培养编程思维,做Java高手!
系统全面:内容全面,循序渐进,带领零基础的你走上编程之路!
视频教程:图文教程+视频教程,为你打造轻松易学的教程套餐!
轻松上手:边学边练,随时进行自我检测,保证重点难点全掌握!
第5章
类与对象
本书的第1章提到了Java是一门面向对象的语言,那什么是“面向对象”呢?下面我们就来具体解释一下这个概念。
5.1 面向对象
面向对象程序设计方法(Object-Oriented Programming,OOP)是一种运用对象、类、继承、封装等概念来构造计算机程序的方法。它要求从现实世界中客观存在的事物出发来建立软件系统,强调直接以现实世界中的事物为中心来思考问题、认识问题,这种解决问题的思路是人类习惯使用的思维方式。与面向过程语言相比,面向对象语言能够有效提高编程的效率并降低编程难度和复杂度,让程序更简洁、更高效、更高质地运行。
5.1.1 对象的基本概念
在面向对象语言诞生之前,程序员主要使用面向过程语言编写程序。面向过程语言也叫命令式语言、强制式语言,是按步骤重复计算低级(非抽象)值并将其赋值给变量(对象)的语言。在解决问题时,面向过程语言通常要把复杂的任务分解成若干个子任务,其程序语言是按顺序执行的指令串。随着时代发展,人们需要处理的任务越来越复杂,面向过程语言渐渐不能满足需求,并且面向过程语言本身也存在一些问题,比如效率低、成本高、难以维护等,于是面向对象语言和面向对象的程序设计方法应运而生。
理解面向对象的关键是理解对象。面向对象的程序设计方法将问题分解为一系列对象,然后围绕这些对象建立数据和函数。
“对象”包含三个方面的内容:对象的名称、对象的属性和对象的操作。
(1)对象的名称。每个对象的名称都是不同的,当需要用对象来表示实体时,要注意区分它们的名称。
(2)对象的属性。不同对象的属性不同,这种不同分为属性的种类不同和属性的内容不同。举例来说,猫和狗有不同种类的属性,而两只猫各自有其独特的属性内容。在面向对象的程序设计方法中,对象的属性表示了对象包含的数据。
(3)对象的操作。这是指对象能进行的行为,比如“奔跑”“卧倒”等。
下面来看一个具体的例子。
对象的名称:王小花
对象的属性:
性别:女
年龄:19
专业:汉语言文学
对象的操作:
上课
考试
5.1.2 类的基本概念
我们在生活中不会把每个对象都看成孤立的个体,而是会看到一些共性,比如白猫、黑猫、花猫有不同的属性,但会把它们都归类为猫。在面向对象的程序设计方法中,也有与之相似的“类”的概念。
在面向对象的程序设计语言中,不同的类代表不同的对象类型。类如同模板,用同样的模板可以定义许多对象。例如,定义一个“学生类”。
类名称:学生
类属性:
性别
年龄
专业
操作:
上课
考试
比较这个例子和上一小节的例子,可以看到如下情况。
(1)类名称并不指代某个固定的对象,“学生”指的是一个范围里的人,而不是某个具体的人;对象则是具体的,可以对应到某个人。
(2)类属性的值并不固定,比如年龄可以是合理范围的任一数字;对象的属性则是确定的。
(3)类和对象都有操作,而且是相同的操作。
由此可以看出,对象和类的关系是具体和抽象的关系。类是对有同类型属性和操作的多个对象的抽象归类,而对象则是类的具体化,给类这个模板上加一些确定的值就可以定义到某个具体的对象。一个类可以生成多个不同的对象,对象则是某个类的实例。
5.1.3 对象的交互
在面向对象的程序设计语言中,与解决问题有关的函数(也被称为方法)都被放进了类和对象中。与面向过程语言一样,面向对象语言在解决复杂问题时也会把问题分解成若干个子任务,但面向对象的程序设计语言会把函数分类到与其功能对应的对象中(哪个对象能在实际意义上具有这个行为,就把这个功能的函数分配到哪个对象)。如果是复杂的功能,某个单一的对象无法独自完成,就需要多个对象协作完成。这种多个对象间的协作就是对象的交互。
在面向过程语言中,程序的结构是有层级的,不同功能的函数放置在不同模块中,解决某个问题的函数都放在一起,主程序逐个调用、返回即可,控制流程比较简单。而在面向对象语言中,方法被放在对象中,如果一个方法想调用其他对象中的方法,两个对象之间就会发生交互,因此面向对象的控制流程相对比较复杂。
面向过程的编程方法构建的程序有点像军队,上下级明确,上级给下级布置任务,下级完成任务并返回结果,最上层的领导可以统率全局。而面向对象的编程方法构建的程序则大多没有这种上下级关系,在处理复杂任务时,各个对象处理好自己应该处理的那部分任务,再把需要别的对象处理的任务传给对方并等待回应即可。
对象的交互是通过消息传递的方式进行的,通过这种方式,程序可以将分散在不同对象中的方法联合起来。在面向对象的编程方法构建的程序中,程序的运行是靠消息传递来推动的,这种执行形式是由对象的特性和封装性决定的。
注意:对象之间通过传递消息来进行相互的联系,发送消息的对象要指明接收消息的对象,同时要在消息中说明接收消息的对象所要完成的动作。当一个对象发送一个消息后,被指定的对象接收到该消息并对消息进行分析,然后执行该动作。
5.1.4 封装和抽象
类与对象都有封装性。简单来说,封装是对象对自身内部数据和操作的隐藏,一个对象无法查看其他对象内部的数据和操作。如果一个对象需要其他对象协作,只需要向对方传递“做什么”的信息,不用管对方“怎么做”,事实上它也无法知道对方是怎么做的。
这些被传递的信息是在一定规则下制定的,因此双方都能正确理解。这些规则是对功能的抽象描述,相当于“使用指南”,可以让其他对象明白该对象能做什么,以及怎么让该对象去做那些事情。
类与对象的封装性使它们很像带有接口的盒子,从外面看只能看到接口,而看不到里面的结构。对类与对象来说,如果没有抽象出来的接口,它们就不能发生作用;如果没有封装性,数据和操作会被暴露出来,这既没有必要,也不安全。
5.1.5 继承的概念
现实世界中,万事万物皆可关联。关联描述的是两个类之间的关系,例如一个家庭类与家庭成员类就是一个关联。两个类之间的关联有很多种,继承是关联中的一种。继承描述的是事物之间的所属关系,比如大熊猫属于哺乳动物,因此可以称大熊猫类是哺乳动物类的继承类;哺乳动物属于动物,因此可以称哺乳动物类是动物类的继承类。拥有继承关系的两个类之间存在继承与被继承的关系,可以称这种关系为“父子关系”,其中继承类是子类(或派生类),被继承类为父类(或基类)。子类拥有父类的所有属性和行为,同时又有自己独特的行为和属性。例如,大熊猫类和哺乳动物类是两个类,都有恒温和胎生等属性,但是大熊猫类还有很多独特的属性,比如吃竹子。
由此可以总结,在面向对象程序设计中,有继承关系的两个类(或两个对象)之间有以下两个特征。
(1)继承类具有被继承类的所有属性和行为。
(2)继承类具有被继承类没有的属性和行为。
因此,在上面的例子中,不能反过来说哺乳动物这个对象继承了大熊猫这个对象的所有属性。
继承可以形成层次结构,也就是说一个类可以间接继承多个类。这种继承也被称为多重继承。比如大熊猫属于动物界的脊索动物门中哺乳纲下食肉目的熊科,大熊猫这个对象继承了熊科这个对象的所有属性,熊科这个对象继承了食肉目这个对象的所有属性,因此大熊猫这个对象也间接继承了食肉目这个对象的所有属性。依此类推,大熊猫这个对象继承了前面列举的所有“界门纲目科”等对象的属性。
按照继承源的不同,可以把继承分为单继承和多继承。单继承是只有一个基类的继承,比如上面举的大熊猫的例子就属于单继承。多继承是有多个基类的继承,比如小孩的肤色、血型等属性同时继承了父亲和母亲的某些特点。需要注意的是,多继承会造成许多问题,因此Java不支持多继承。不过,Java可以“声明多继承”,即Java的接口可以多继承:一个类可以“继承”多个接口的方法,一个接口可以“继承”多个接口的方法。
继承是面向对象的重要特征,它可以减少编写重复代码的工作量,极大地提升了编程效率。
注意:系统在创建一个子类的时候,会自动将这个子类所继承的父类中的相关代码复制到子类中。由此可见,继承虽然一定程度上减轻了程序员的负担,但是并没有减少系统的负担。
5.1.6 多态性
同样的消息传递给同属的不同类型的对象会导致同一行为的不同表现,这就是面向对象的多态性。比如大熊猫和狗都属于动物,这两种动物都具有吃饭的行为,我们让大熊猫和狗通过消息传递(方法调用)做出吃饭的行为,虽然二者的行为都表现为吃饭,但是吃的内容不一样——大熊猫吃的是竹子,狗吃的是狗粮。
多态性与继承有关。体现多态性的对象,既有共性,也有特性。共性是指这些对象具有相同的父类、相同的属性和行为,特性是指同一行为具有不同的行为表现。
多态性使面向对象语言更加灵活、抽象,一定程度上也能减少代码量,提高使用效率。
5.1.7 包的基本概念
包(package) 是组织类的一种方式。包是类的容器,其作用是分隔类名空间。打个形象点的比方,包有点像电脑硬盘中的文件夹。
包可以很好地保证类名的唯一性。如果没有包,都是一个个类的话,程序员在编程时很可能不记得或不知道现存的类有哪些类名,有可能会设置与之前的类相同的类名,那系统就会产生冲突。使用包便可以避免这类问题。
Java编译器认为不同的包之间没有关系,即使两个包里都有同一个类名的类,也不会产生冲突。
Java 的包机制为程序开发带来了很多好处。比如Java本身提供了很多类库,这些类库通常被称为“应用程序接口”或者“API”。Java 通过包机制把一些平时开发过程中较为通用的类和接口封装成类库,极大地提高了开发效率。
第1章 Java概述
1.1 Java语言简介
1.1.1 Java语言的起源和发展
1.1.2 Java语言的优点
1.2 Java语言与Java平台
1.2.1 Java语言
1.2.2 Java平台
1.3 搭建Java程序开发环境
1.3.1 系统要求
1.3.2 下载JDK
1.3.3 安装JDK
1.3.4 在Windows系统下配置JDK
1.4 开发第一个Java应用程序
1.4.1 创建第一个Java应用程序源文件
1.4.2 将HelloJava.java源文件编译为“.class”文件
1.4.3 运行HelloJava应用程序
1.4.4 Java应用程序的基本结构
第2章 基本语法
2.1 标识符和关键字
2.1.1 标识符
2.1.2 关键字
2.1.3 标识符命名规则
2.2 常量与变量
2.2.1 常量的概念及常量声明
2.2.2 变量的概念及变量声明
2.3 基本数据类型
2.3.1 原始数据类型和构造数据类型
2.3.2 整数型
2.3.3 浮点型
2.3.4 字符型
2.3.5 逻辑型(布尔型)
2.3.6 不同数据类型间的转换
2.4 运算符和表达式
2.4.1 算术运算符和算术表达式
2.4.2 赋值运算符和赋值表达式
2.4.3 自增运算符和自减运算符
2.4.4 关系运算符和关系表达式
2.4.5 逻辑运算符和逻辑表达式
2.4.6 位运算符
2.4.7 三元运算符
2.4.8 运算符的优先级
第3 章 数组
3.1 数组的概念与特点
3.1.1 数组的概念
3.1.2 Java 语言中数组的特点
3.2 一维数组
3.2.1 声明一维数组变量
3.2.2 创建一维数组对象
3.2.3 访问一维数组元素
3.2.4 修改一维数组元素
3.3 二维数组
3.3.1 声明二维数组变量
3.3.2 创建二维数组对象
3.3.3 访问二维数组元素
3.3.4 修改二维数组元素
第4 章 程序流程控制语句
4.1 选择结构
4.1.1 if 语句
4.1.2 if-else 双分支选择结构语句
4.1.3 if-else-if 多分支选择结构语句
4.1.4 if 语句的嵌套
4.1.5 switch 语句
4.1.6 if 语句与switch 语句的区别
4.2 循环语句
4.2.1 while 语句
4.2.2 do-while 语句
4.2.3 for 语句
4.2.4 循环语句的嵌套
4.2.5 foreach 语句
4.2.6 对一维数组进行排序
4.3 跳转语句
4.3.1 break 语句
4.3.2 continue 语句
4.4 实例
4.4.1 译密码
4.4.2 九九乘法表.
第5 章 类与对象
5.1 面向对象
5.1.1 对象的基本概念
5.1.2 类的基本概念
5.1.3 对象的交互
5.1.4 封装和抽象
5.1.5 继承的概念
5.1.6 多态性
5.1.7 包的基本概念
5.2 定义类
5.2.1 类的基本结构
5.2.2 成员变量
5.2.3 成员方法
5.2.4 方法重载
5.2.5 构造方法(构造器)
5.3 访问权限修饰符
5.4 对象
5.4.1 创建对象
5.4.2 对象的使用
5.4.3 对象的清除
5.5 进一步讨论方法
5.5.1 成员方法的返回值
5.5.2 get() 方法和set() 方法
5.5.3 static 修饰符
5.5.4 类成员和实例成员
5.5.5 final 修饰符
5.6 this 关键字
5.6.1 对成员变量使用this 关键字
5.6.2 对构造方法使用this 关键字
5.7 实例:Car 类
5.8 初始化成员变量
5.8.1 静态初始化块
5.8.2 初始化实例成员
5.9 枚举类型
5.10 标注
5.10.1 标注的用法
5.10.2 文档标注
5.10.3 预定义标注
5.10.4 标注处理
第6 章 继承
6.1 继承概述
6.1.1 Java 平台中的类层次
6.1.2 一个关于继承的示例
6.1.3 在派生类中可以做的事情
6.2 在派生类中访问基类的私有成员
6.3 对象类型转换
6.3.1 向上转型
6.3.2 向下转型
6.4 覆盖和隐藏基类中的方法
6.4.1 覆盖基类中的实例方法
6.4.2 协变覆盖
6.4.3 隐藏基类中的类方法
6.4.4 方法重写和方法隐藏后的修饰符
6.4.5 方法重写和方法隐藏总结
6.5 隐藏基类中的成员变量
6.6 使用super 关键字访问基类中的成员
6.6.1 调用基类中被重写的方法
6.6.2 访问基类中被重写的成员变量
6.7 使用super 关键字调用基类的构造方法
6.7.1 调用基类的无参构造方法
6.7.2 调用基类的带参构造方法
6.7.3 构造方法链
6.8 Object 类
6.8.1 作为基类的Object 类
6.8.2 Object 类的对象克隆方法——clone()
6.8.3 Object 类的对象比较方法——equals()
6.8.4 Object 类的对象清除方法——finalize()
6.8.5 Object 类的获取对象类信息的方法——getClass()
6.8.6 Object 类的获得对象内存地址的方法——hashCode()
6.8.7 Object 类的对象字符串表示方法——toString()
6.9 final 类和final 方法
6.9.1 使用final 关键字声明final 类
6.9.2 使用final 关键字声明final 方法
第7 章 数字、字符和字符串处理
7.1 数字
7.1.1 数字包装类
7.1.2 数字的格式化输出
7.1.3 Math 数学运算处理类
7.2 字符
7.2.1 Character 字符包装类
7.2.2 转义字符序列
7.3 String 类
7.3.1 创建字符串对象
7.3.2 获取字符串的长度
7.3.3 连接字符串
7.3.4 字符串与字符数组
7.3.5 操作字符串的内容
7.3.6 字符串的比较
7.4 StringBuilder 类
7.4.1 认识StringBuilder 类
7.4.2 StringBuilder 对象的长度和容量
7.4.3 StringBuilder 类提供的操作方法
7.5 实例
7.5.1 用户登录验证程序
7.5.2 敏感词过滤程序
第8 章 接口
8.1 接口概述
8.1.1 日常生活中的“接口
8.1.2 接口的概念
8.1.3 接口的定义
8.1.4 接口的使用
8.1.5 作为API 的接口
8.1.6 接口和多继承
8.2 定义接口
8.2.1 声明接口
8.2.2 接口体
8.3 实现接口
8.3.1 实现接口的语法
8.3.2 实例:Compare
8.3.3 实现多个接口时的常量和方法冲突问题
8.4 将接口作为类型使用
8.5 改写接口
第9 章 抽象类与内部类
9.1 抽象方法和抽象类.
9.1.1 抽象方法
9.1.2 抽象类
9.1.3 抽象类与接口的比较
9.1.4 抽象类实例
9.2 内部类
9.2.1 使用内部类的原因
9.2.2 静态内部类
9.2.3 内部类实例
9.2.4 局部内部类和匿名内部类
第10 章 泛型
10.1 泛型概述
10.1.1 使用泛型的原因
10.1.2 泛型的优点和缺点
10.2 泛型的声明
10.2.1 泛型类的声明
10.2.2 泛型方法的声明
10.3 泛型的类型参数命名惯例
10.4 限定类型参数
10.5 泛型的派生类型
10.6 通配符
10.7 类型擦除
第11 章 包
11.1 包的创建
11.1.1 创建包
11.1.2 命名包
11.2 使用包的成员
11.2.1 通过全限定名引用包的成员
11.2.2 导入包的成员
11.2.3 导入整个包
11.2.4 包的层级
11.2.5 静态导入语句
11.3 管理源文件和类文件
11.3.1 管理源文件的实现策略
11.3.2 设置CLASSPATH 系统变量
第12 章 异常处理
12.1 Java 中的异常处理与错误类型
12.1.1 编译时错误
12.1.2 运行时错误
12.1.3 逻辑错误
12.1.4 Java 程序中的异常处理机制
12.1.5 Java 中的异常处理类
12.2 Java 程序中的异常处理
12.2.1 使用try-catch 语句保护代码和捕获异常
12.2.2 使用多个catch 子句
12.2.3 使用finally 子句
12.2.4 可嵌入的try 块
12.3 抛出异常
12.3.1 使用throws 声明抛出异常的方法
12.3.2 使用throw 关键字抛出异常
12.3.3 异常类的常用方法
12.4 自定义异常
12.4.1 创建自定义异常类
12.4.2 使用throw 和try-catch 语句处理自定义异常
第13 章 输入与输出
13.1 文件(File)类的使用
13.1.1 创建File 类对象
13.1.2 文件或目录的属性
13.2 流的概念
13.2.1 对流的认识
13.2.2 输入流与输出流
13.2.3 字节流与字符流
13.3 字节流
13.3.1 InputStream 类与OutputStream 类
13.3.2 FileInputStream 类与FileOutputStream 类
13.3.3 BufferedInputStream 类与BufferedOutputStream 类
13.4 字符流
13.4.1 FileReader 类与FileWriter 类
13.4.2 BufferedReader 类与BufferedWriter 类
13.4.3 PrintStream 类与PrintWriter 类
13.5 实现用户输入
13.5.1 使用System.in 类获取用户输入
13.5.2 使用Scanner 类获取用户输入
13.5.3 使用命令行参数