本章内容
类的继承
理解继承的含义
在Java中定义一个类时,让该类通过关键字extends继承一个已有的类,这就是类的继承(泛化)。
被继承的类称为父类(超类,基类),新的类称为子类(派生类)。
子类继承父类的所有属性和方法,同时也可以增加自己的属性和方法。
ava中只能单继承,也就是说每个类只能有一个直接父类;一个父类可以有多个子类。
其实,在继承关系中我们还能发现一个规律:子类是父类的一种,也可以说“子类就是父类”。如:人类就是动物,动物就是生物。记住这个定律对我们理解继承的概念非常有帮助。但是,反过来看,父类是子类的说法正确吗?
继承的语法和规则
示例 Employee.java Worker.java
[修饰符]class子类名extends父类名
☻ 练习 Officer.java TestOfficer.java
用java中类的继承机制,实现Officer类,并设计一个测试程序TestOfficer类,来访问Officer类
继承的好处
子类实例化的过程
子类实例化时先实例化其父类,然后实例化子类。
要先调用父类的构造器,父类构造器运行完毕,才调用子类的构造器。
如果实例化类D,说出构造器执行的顺序。
super和this关键字
super()
this()
作用:调用本类的构造器
只能写在构造器的第一行
在同一个构造器中super()和this()不能同时出现
子类实例化的过程
使用默认的构造器
在子类中的创建构造器 示例 Worker.java
在子类中创建构造器时,必须调用父类的构造器
子类可以在自己的构造器中使用super关键字来调用父类的构造器
super(参数1,参数2,…);
如果使用super关键字调用父类构造器,必须写在该子类构造器的第一行
如调用的是父类中无参的构造器,则可以不写super( )
如果子类中调用了父类无参的构造器,而父类中没 有无参构造器则系统编译出错
super.
指向父类的引用。
通过关键字super我们可以指定子类在构造时调用父类的哪个构造器,达到先实例化父类然后实例化子类的目的。
子类的构造器默认的调用父类无参构造器,即子类构造器中没有用super指明调用父类哪个构造器的话,实际上编译器会自动的在子类构造器第 一行加入代码super( );
this.
指向本类的引用。
我们知道子类在实例化时必须调用父类的构造器,实际上有的子类构造器
也可以先调用本类的其他构造器,然后再通过那个构造器调用父类的构造器
无论是调用父类的构造器还是子类的构造器,最终都是找到最顶级的父类自
上而下的实例化。只要中间环节有一个构造器没找到,这个子类就无法完成实例化
给定以下代码:
答案:A
Java包的概念
包的概念及应用
在Java中,包主要有以下用途 :
包允许将类组合成较小的单元
有助于避免命名冲突
包允许在更广的范围内保护类、数据和方法
包可以是类、接口和子包的集合
将类放入包中
package包名 ;
注意:
在java中位于包中的类,在文件系统中的存放位置,必须有与包名层次相对应的目录结构
package语句作为java源文件的第一条语句
每个源文件只能声明一个包
如果没有package语句,则默认为无名包
Java类库中常用的包
java.lang
Java语言包,任何程序中,该包都被自动导入。
java.awt
图形用户界面包
java.awt.event
图形用户界面事件处理包。
java.swing
跨平台轻量级组件包。
java.sql
数据库访问包。
java.io
这个包由对您的输入/输出操作有用的类组成。
java.util
该包提供了许多创建如:lists, calendar, date等所需要的类和接口。
java.net
该包提供了许多进行TCP/IP网络编程的类和接口。
import导入包中的类
包名.路径名
package test;
class Cat extends p08.Animal{…}
使用import关键字引入其它包中的类
package test;
import p08.Animal;
class Cat extends Animal{…}
位于同一包中的类可以直接访问
导入包中所有的类
import 包名.*;
导入子包中所有的类
import 包名.子包名.*;
导入包中的某个类
import 包名.子包名.类名;
权限访问操作符
使用访问权限修饰符对类的成员进行控制,在java中称为“封装”。
不过不要把封装理解为private,不要误认为不能访问成员才是封装。实际上对成员访问权限的任何控制(包括public)都可以称为封装机制。
构造器和类的权限通常为public;private权限最小,限制类外访问,一般把属性设为private,让其他类不能直接访问属性,达到保护属性的目的;friendly是默认权限,即不使用权限修饰符时,即为friendly,该权限声明的成员在类内以及在同一个包中的其他类可以访问;而protected所修饰的成员在类内、同一个包中、所在类的子类中都可以访问。
public > protected > friendly > private
封装
信息隐藏,隐藏对象的实现细节,不让用户看到
将东西包装在一起,然后以新的完整形式呈现出来
例如,两种或多种化学药品组成一个胶囊
将方法和属性一起包装到一个单元中,单元以类的形式实现
“隐藏属性、方法或实现细节的过程称为封装。”
隐藏类的实现细节
让使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作
便于修改,增强代码的可维护性
可进行数据检查
示例 Employor.java TestEmployer.java
访问权限修饰符
用来控制类的成员和类的使用范围
类成员的访问权限修饰符:private、default、protected、public
类的访问权限修饰符:public、default
示例:Access.javaTestAccess.java
☻ 练习
给定以下代码:
方法的覆盖
方法的覆盖(override)
重写(rewrite)
对从父类中继承来的方法进行改造
在子类继承父类时发生
方法覆盖的规则
在子类中的覆盖方法与父类中被覆盖的方法应具有
相同的方法名相同的参数列表(参数数量、参数类型、参数顺序都要相同)相同的返回值类型子类覆盖方法的访问权限要不小于父类中被覆盖方法的访问权限示例Worker.java
☻ 练习
给定下列代码:
当在第6行加入什么方法时会引起编译错误?
答案:B
☻ 练习
给定类
class A{ int method1(inta, double b){return 0; }
在其子类中
引用数据类型的转换
上溯造型
示例:TestStudent.java
向上转型(Upcasting)— 子类转换为父类,自动转换;
前提 — 具有继承或实现关系
向上转换损失了子类新扩展的属性和方法,仅可以使用从父类中继承的属性和方法
下溯造型 示例:TestStudent.java
向下转型(Downcasting):强制转换
instanceof 运算符
其实经过上溯和下溯造型之后,我们很难知道某个引用到底指向哪种类型的对象了。
可以通过instanceof来判断该经过上溯转型后是哪一个子类的。
instanceof运算符的一般格式:
instanceof 运算符
判断一个类是否实现了某个接口
对象 instanceof 接口
判断一个实例对象是否属于一个类
对象 instanceof 类
它的返回值是boolean型的
示例 TestStudent.java
多态
多态
简单来说,多态是具有表现多种形态的能力的特征
同一个实现接口,使用不同的实例而执行不同操作
多态(动态绑定、Polymorphism )
不同的对象对同一行为作出的不同响应
多态存在的三个必要条件
要有继承,或实现
要有重写
父类引用指向子类对象
一旦满足以上3个条件,当调用父类中被重写的方法后,
运行时创建的是哪个子类的对象,就调用该子类中重写的那个方法
在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际类型调用相应的方法
多态的优点
简化代码
改善代码的组织性和可读性
易于扩展
☻ 示例 Parker.java Vehicle.java Bus.java Truck.java Car.java
在停车场收费系统中,
收费者会根据车型的不同收取不同的停车费,其中,
客车:15元/小时
货车:12元/小时
轿车:8元/小时
编写java程序完成此功能
static关键字
静态变量
所有对象共享
也称为类变量
用static修饰的成员变量,它们在类被载入时创建,只要类存在,static变量就存在(参考java虚拟机视频)
两种方式访问:
直接访问:类名.属性;
实例化后访问:对象名.属性
静态方法
不需要实例化,可以直接访问
也称为类方法
两种方式访问:
直接访问:类名.方法名()
实例化后访问:对象名.方法名()
static方法的作用
简化方法的使用;
便于访问静态属性;
注意事项
静态方法里只能直接访问静态成员,而不能直接访问类中的非
静态成员静态方法中不能使用this、super关键字
静态方法不能被非静态方法覆盖,静态方法不能修饰构造器
静态代码块
一个类中由static关键字修饰的,不包含在任何方法体中的代码块
当类被载入时,静态代码块被执行,且只被执行一次
静态块经常用来进行类属性的初始化
以下代码的执行结果是_____?
A. 编译失败
B. 编译成功,输出“0”
C. 编译成功,输出“1”
D. 编译成功,输出“2”
答案:A
☻ 练习
单例模式
单例模式(singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点
单例模式要点:
某个类只能有一个实例
它必须自行创建这个示例
必须自行向整个系统提供这个实例
单例模式实现:
拥有一个私有构造器
提供一个自身静态私有的成员变量
提供一个公有的静态公有的方法
final关键字
final关键字
final可以修饰的元素:
类:不能被继承
变量(属性和局部变量):不能被重新赋值
在声明时赋值,或在构造器中赋值系统不会对final属性默认的赋初始值
方法:不能在子类中被覆盖,即不能修改。
示例 Final.java TestFinal.java
在程序中经常使用的一些常量,如圆周率,没必要在程序中频繁的修改它那么我们可以:
首先把它设置为静态static,多个实例共享该常量,没有必要每个对象保存一份;
其次,设置为final类型,赋值以后不能再改变;
最后注意遵守常量命名规范,所有字母大写、单词之间用下划线。
练习
抽象类与final类的区别?
final方法是否可以被子类继承?
抽象类
抽象类和抽象方法的概念
抽象类是抽象方法和非抽象方法的集合
[访问权限修饰符] abstract class 类名{ ……}
特殊情况
全部是抽象方法
全部为非抽象方法
抽象类和抽象方法的概念
抽象方法
只有方法声明,没有方法实现的方法
[访问权限修饰符] abstract 返回值类型 抽象方法名 (参数列表) ;
abstract class A{
abstract int method1(int a,int b);}
抽象类的规则
注意:
抽象类不能被实例化;其包含的抽象方法必须在其子类中被实现,否则该子类只能声明为abstract;抽象方法不能为static;
在下列情况下,一个类必须声明为抽象类:
当一个类的一个或多个方法是抽象方法时;
当类是一个抽象类的子类,并且没有实现父类的所有抽象方法,即只实现部分;
当一个类实现一个接口,并且不能为全部抽象方法都提供实现时;
☻ 练习
给定以下代码:
接 口(interface)
接口的概念 示例 AudioDevice.java VideoDevice.java
接口中只包含常量和抽象方法,而没有变量和方法的实现
接口对类来说是一套规范,是一套行为协议;
接口不是一个类,不能实例化
接口的成员:
常量(字段)
抽象方法
注意:
接口不是一个类,没有构造器,不能被实例化
接口使用interface关键字来定义,而不是class
接口默认:
常量:public static final
抽象方法:public abstract
☻ 练习
给定以下代码:
☻ 练习
下列选项中,哪些可以定义在一个接口中?
接口的概念
示例 VADevice.java
接口可以实现多继承:
用接口可以实现混合类型(主类型,副类型),java 中可以通过接口分出主次类型
主类型使用继承,副类型,使用接口实现
接口可以使方法的定义和实现相分离,降低模块间或系统间的耦合性
针对接口编程可以屏蔽不同实现间的差异,看到的只是实现好的功能。
接口和类的关系
类实现接口 — implements
为了使用一个接口,你要编写实现接口的类
如果一个类要实现一个接口,那么这个类就必须实现接口中所有抽象方法。否则这个类只能声明为抽象类
多个无关的类可以实现一个接口,一个类可以实现多个无关的接口
一个类可以在继承一个父类的同时,实现一个或多个接口
示例 Television.java
接口和类的关系
☻ 示例 Student.java Consumer.java Person.java
有一个Student类该类继承了Person类,并实现了Consumer接口该类具有String类型的属性school并有一个study方法,在该方法中,系统可打印出学生在那所学校学习并创建一个测试方法,测试Student类
接口与抽象类的对比
接口不能含有任何非抽象方法,而抽象类可以。
类可以实现多个接口,但只能有一个父类。
接口和接口之间可以多继承
抽象类可以理解为抽象方法和非抽象方法的混合体,而接口中的方法完全是抽象方法,是一套纯粹的规范。一般来说,有关系的类才能继承同一个抽象类,而无关的类不可能有同一个抽象父类,但是无关的类可以实现同一个接口。
内部类
内部类特性
内部类就是定义在另一个类内部的类。
内部类对于同一包中的其它类来说,内部类能够隐藏起来。
注意
内部类可以访问其外部类中所有的属性和方法
无需创建外部类的对象,即可从内部类访问外部类的变量和方法。
必须创建内部类的对象,否则无法从外部类访问内部类的变量和方法。
如果内部类中有和外部类同名的变量或方法,则内部类的变量和方法将获得比外部类的变量和方法更高的优先级。
不能定义static变量
内部类特性
示例Outer.java
一个类只会被这个类所调用,其他类不会使用他,你可以把它定义成一内部类,这样可以隐藏实现细节,避免错误的调用。
内部类特性
普通类的访问权限修饰符
default
public
内部类的访问权限修饰符
default
public
protected
private
示例 Outer3.java OuterTest.java
在Outer内访问Inner,只需如下:
Inner in=new Inner() ;
在Outer外访问Inner,必须如下:
Outer o =new Outer();//实例化外部类Outer.Inner oi = o.new Inner();//实例化内部类
静态内部类
用static标识的内部类为静态内部类。
静态内部类作为外部类的静态成员,不能访问外部类非静态成员。
非静态内部类只能定义非静态成员,而静态内部类可以定义静态成员和非静态成员。
使用Outer.Inner inn=new Outer.Inner()方式实例化静态内部类。
非静态内部类不可以使用上面的方式实例化。
示例:OuterStatic.java
局部内部类
在一个类的方法体中或程序块内定义的内部类
示例
在方法定义的内部类中只能访问方法中的final类型的局部变量
本章重点总结
类的继承Java中的包和访问修饰符方法的覆盖引用数据类型的转换多态static关键字抽象类和接口final关键字
课后作业
创建一个球员类,并且该类最多只允许创建十一个对象。提示利用 static 和 封装性来完成。 [必做题]
类图如下:
效果如下:
设计2个类,要求如下:(知识点:类的继承 方法的覆盖) [必做题]
2.1 定义一个汽车类Vehicle,
2.1.1 属性包括:汽车品牌brand(String类型)、颜色color(String类型)和速度speed(double类型)。
2.1.2 至少提供一个有参的构造方法(要求品牌和颜色可以初始化为任意值,但速度的初始值必须为0)。
2.1.3 为属性提供访问器方法。注意:汽车品牌一旦初始化之后不能修改。
2.1.4 定义一个一般方法run(),用打印语句描述汽车奔跑的功能
2.1.5 在main方法中创建一个品牌为“benz”、颜色为“black”的汽车。
2.2 定义一个Vehicle类的子类轿车类Car,要求如下:
2.2.1 轿车有自己的属性载人数loader(int 类型)。
2.2.2 提供该类初始化属性的构造方法。
2.2.3 重新定义run(),用打印语句描述轿车奔跑的功能。
2.2.4 在main方法中创建一个品牌为“Honda”、颜色为“red”,载人数为2人的轿车。
设计三个类,分别如下:(知识点:抽象类及抽象方法) [必做题]
3.1 设计Shape表示图形类,有面积属性area、周长属性per,颜色属性color,有两个构造方法(一个是默认的、一个是为颜色赋值的),还有3个抽象方法,分别是:getArea计算面积、getPer计算周长、showAll输出所有信息,还有一个求颜色的方法getColor。
3.2 设计 2个子类:
3.2.1 Rectangle表示矩形类,增加两个属性,Width表示长度、height表示宽度,重写getPer、getArea和showAll三个方法,另外又增加一个构造方法(一个是默认的、一个是为高度、宽度、颜色赋值的)。
3.2.2 Circle表示圆类,增加1个属性,radius表示半径,重写getPer、getArea和showAll三个方法,另外又增加两个构造方法(为半径、颜色赋值的)。
3.3 在main方法中,声明创建每个子类的对象,并调用2个子类的showAll方法。
Cola公司的雇员分为以下若干类:(知识点:多态) [必做题]
4.1 ColaEmployee :这是所有员工总的父类,属性:员工的姓名,员工的生日月份。方法:getSalary(int month) 根据参数月份来确定工资,如果该月员工过生日,则公司会额外奖励100 元。
4.2 SalariedEmployee : ColaEmployee 的子类,拿固定工资的员工。属性:月薪
4.3 HourlyEmployee :ColaEmployee 的子类,按小时拿工资的员工,每月工作超出160 小时的部分按照1.5 倍工资发放。属性:每小时的工资、每月工作的小时数
4.4 SalesEmployee :ColaEmployee 的子类,销售人员,工资由月销售额和提成率决定。属性:月销售额、提成率
4.5 定义一个类Company,在该类中写一个方法,调用该方法可以打印出某月某个员工的工资数额,写一个测试类TestCompany,在main方法,把若干各种类型的员工放在一个ColaEmployee 数组里,并单元出数组中每个员工当月的工资。
利用接口实现动态的创建对象[选做题]
5.1 创建4个类:
苹果
香蕉
葡萄
园丁
5.2 在三种水果的构造方法中打印一句话.
以苹果类为例
class apple
{
public apple()
{
System.out.println(“创建了一个苹果类的对象”);
}
}
类图如下:
5.3 要求从控制台输入一个字符串,根据字符串的值来判断创建三种水果中哪个类的对象
如图:
编写三个系别的学生类:英语系,计算机系,文学系(要求通过继承学生类) [选做题]
6.1各系有以下成绩:
英语系: 演讲,期末考试,期中考试;
计算机系:操作能力,英语写作,期中考试,期末考试;
文学系: 演讲,作品,期末考试,期中考试;
6.2各系总分评测标准:
英语系: 演讲 50%
期末考试 25%
期中考试 25%
计算机系: 操作能力 40%
英语写作 20%
期末考试 20%
期中考试 20%
文学系: 演讲 35%
作品 35%
期末考试 15%
期中考试 15%
6.3定义一个可容纳5个学生的学生类数组,使用随机数给该数组装入各系学生的对象,然后按如下格式输出数组中的信息:
学号:XXXXXXXX 姓名:XXX 性别:X 年龄:XX 综合成绩:XX