10-01继承的概述
- 在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类
- 子类会自动拥有父 类所有非private修饰的属性和方法
10-02继承的定义格式和使用
- 格式
class 子类 extends 父类 {} - 通过子类对象既可以调用自身的非private修饰的成员,也可以调用父类的非private修饰的成员
- 雇员(Employee)与研发部员工(Developer)案例:
Employee.java:
/*
* 定义员工类Employee
*/
class Employee {
String name; // 定义name属性
public void work() {// 定义员工的工作方法
System.out.println("尽心尽力地工作");
}
}
Developer.java:
/*
* 定义研发部员工类Developer 继承 员工类Employee
* 继承了父类中所有非private修饰的成员变量
*/
class Developer extends Employee {
// 定义一个打印name的方法
public void printName() {
System.out.println("name=" + name);
}
}
*测试员工类与研发部员工类:
/*
* 定义测试类
*/
public class Example01 {
public static void main(String[] args) {
Developer d = new Developer(); // 创建一个研发部员工类对象
d.name = "小明"; // 为该员工类的name属性进行赋值
d.printName(); // 调用该员工的printName()方法
d.work(); // 调用Developer类继承来的work()方法
}
}
10-03继承的好处
- 继承的出现提高了代码的复用性,提高软件开发效率。
- 继承的出现让类与类之间产生了关系,提供了多态的前提。
10-04继承的注意事项
- 在Java中,类只支持单继承,不允许多继承,也就是说一个类只能有一个直接父类,例如下面这种情况是不合法的。
class A{}
class B{}
class C extends A,B{} // C类不可以同时继承A类和B类
- 多个类可以继承一个父类,例如下面这种情况是允许的
class A{}
class B extends A{}
class C extends A{} // 类B和类C都可以继承类A
- 在Java中,多层继承是可以的,即一个类的父类可以再去继承另外的父类,
class A{}
class B extends A{} // 类B继承类A,类B是类A的子类
class C extends B{} // 类C继承类B,类C是类B的子类,同时也是类A的子类
10-05继承的体系
- 动物体系是对每个具体事物共性的抽取,子类的共性抽取形成父类
- 父类:具有所有子类的共性内容
子类:不但有共性还有自身特有的内容 - 整个继承体系,越向上越抽象,越向下越具体
10-06继承后子类父类成员变量的特点
- 子类的对象调用成员变量的时候,子类自己有,使用子类,子类自己没有调用的父类
- 在子类中需要访问父类中非私有成员变量时,需要使用super关键字
- this.调用自己本类成员,super.调用的自己的父类成员
Fu.java
public class Fu{
//Fu中的成员变量。
int num = 5;
}
Zi.java
public class Zi extends Fu {
//Zi中的成员变量
int num = 6;
void show(){
//子类的局部变量
int num=7;
//直接访问,遵循就近查找原则
System.out.println(num);//7
//子父类中出现了同名的成员变量时
//在子类中需要访问父类中非私有成员变量时,需要使用super关键字
//访问父类中的num
System.out.println("Fu num="+super.num);//5
//访问子类中的num2
System.out.println("Zi num2="+this.num);//6
}
}
Test.java
public class Test {
public static void main(String[] args) {
Zi z = new Zi(); //创建子类对象
z.show(); //调用子类中的show方法
}
}
10-07子类重写父类方法
- 为什么要有重写
Fu类中的方法最先存在,那么如果项目需求变了,该方法的功能不能够满足我们的需求,此时我们也不会去改这个方法,因为项目中可能有大量的功能已经使用到该方法,如果随意修改可能使调用该方法的功能出现问题,所以使用重写方式基于原有功能提供更强的功能 - 子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为override重写、复写或者覆盖
Fu.java
public class Fu {
public void show(){
System.out.println("Fu show");
}
}
Zi.java
public class Zi extends Fu {
//子类复写了父类的show方法
public void show(){
System.out.println("Zi show");
}
}
Test.java
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show(); //Zi show 子类有直接使用子类
}
}
10-08方法覆盖的需求
- 比如手机,当描述一个手机时,它具有发短信,打电话,显示来电号码功能,后期由于手机需要在来电显示功能中增加显示姓名和头像,这时可以重新定义一个类描述智能手机,并继承原有描述手机的类。并在新定义的类中覆盖来电显示功能,在其中增加显示姓名和头像功能
- 我们不改装(破坏)原来的手机,而是再买一个新的智能手机,不但有原有的功能,而且还有特有功能,对于发短信和打电话功能,让智能手机直接沿用(继承)手机的就可以,但是在智能手机中的来电显示不但实现号码,还显示姓名和头像,同样的都是来电显示功能,智能手机的来电显示比手机的功能更加强大,我们考虑使用重写
10-09方法覆盖的手机案例实现
Phone.java
public class Phone {
public void sendMessage(){
System.out.println("发短信");
}
public void call(){
System.out.println("打电话");
}
public void showNum(){
System.out.println("来电显示号码");
}
}
NewPhone.java
public class NewPhone extends Phone {
//覆盖父类的来电显示号码功能,并增加自己的显示姓名和图片功能
//从现实生活角度考虑沿用原有的showNum方法名便于用户更快熟悉和接受,而不是再起个新的名字
//用户还需要花费大量时间慢慢接受
public void showNum(){
//调用父类已经存在的功能使用super
//如果不加super这是调用子类自身的showNum(),自己调用自己,递归
//方法不断入栈导致内存溢出
super.showNum();
//增加自己特有显示姓名和图片功能
System.out.println("显示来电姓名");
System.out.println("显示头像");
}
}
Test.java
public class Test {
public static void main(String[] args) {
new NewPhone().showNum();//来电显示 显示来电姓名 显示头像
}
}
10-10方法覆盖的注意事项
- 权限:子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
- 四大权限:public>默认(default(不写就是默认))=protected>private
- 方法定义:子类方法和要重写的父类的方法:方法的方法名和参数列表都要一样。
- 关于方法的返回值:
*如果是基本数据类型,子类的方法和重写的父类的方法返回值类型必须相同
*如果是引用数据类型,子类的方法和重写的父类的方法返回值类型可以相同或者子类方法的返回值类型是父类方法返回值类型的子类
10-11抽象类的产生
- 分析事物时,发现了共性内容,就出现向上抽取。抽取到一定程度时,方法功能声明相同,但方法功能主体不同,那么此方法就是一个抽象方法。
2.抽象类只有方法声明,没有方法主体。
10-12抽象类的定义格式 - 抽象方法定义的格式:
public abstract 返回值类型 方法名(参数); - 抽象类定义的格式:
abstract class 类名 {
} - 抽象方法,必须使用关键字abstract修饰
- 抽象的方法,必须存在于抽象的类中,类也必须用abstract修饰
10-13抽象类的使用方式
- 抽象类,不能实例化对象, 不能new
2.原因: 如果真的new了对象.调用抽象方法,抽象方法没有主体,根本就不能运行 - 抽象类使用: 定义类继承抽象类,将抽象方法进行重写,创建子类的对象
- 只有覆盖了抽象类中所有的抽象方法后,其子类才可以创建对象。否则该子类还是一个抽象类。因为子类会继承父类的方法,若是没有全部重写方法,子类方法中依旧有抽象方法,子类就依旧是个抽象类。
5.例子
Develop.java
public abstract class Develop {
public abstract void work();
}
JavaEE.java
public class JavaEE extends Develop{
//重写父类的抽象方法
//去掉abstract修饰符,加上方法主体
public void work(){
System.out.println("JavaEE工程师在开发B/S 软件");
}
}
Test.java
public class Test {
public static void main(String[] args) {
JavaEE ee = new JavaEE();
ee.work();//"JavaEE工程师在开发B/S 软件"
}
}
10-14抽象类的设计思想
继承的体系,抽象类强制子类重写抽象的方法
例如:抽象员工类中规定一个方法,工作(work),那么子类(JavaEE员工)中就必须有工作(work)方法
10-15抽象类的细节
- 抽象类一定是个父类,因为抽象类是由子类不断抽取而来的。
- 抽象类中可以不定义抽象方法,可以定义带有方法体的方法
3.那这个抽象类的存在到底有什么意义呢?不让该类创建对象,方法可以直接让子类去使用 - 抽象关键字abstract不可以和以下关键字共存
- private:私有的方法子类是无法继承到的,也不存在覆盖,而abstract和private一起使用修饰方法,abstract既要子类去实现这个方法,而private修饰子类根本无法得到父类这个方法。互相矛盾。
- final,暂时不关注,后面学
- static,暂时不关注,后面学
10-16员工案例
- 需求描述:
某IT公司有多名员工,按照员工负责的工作不同,进行了部门的划分(研发部员工、维护部员工)。
研发部根据所需研发的内容不同,又分为JavaEE工程师、Android工程师;
维护部根据所需维护的内容不同,又分为网络维护工程师、硬件维护工程师。
公司的每名员工都有他们自己的员工编号、姓名,并要做它们所负责的工作。
工作内容:
JavaEE工程师:员工号为xxx的 xxx员工,正在研发淘宝网站
Android工程师:员工号为xxx的 xxx员工,正在研发淘宝手机客户端软件
网络维护工程师:员工号为xxx的 xxx员工,正在检查网络是否畅通
硬件维护工程师:员工号为xxx的 xxx员工,正在修复打印机 - 代码
Employee.java
public abstract class Employee {
private String name; // 员工姓名
private String Id;// 员工编号
public abstract void work();//工作方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return Id;
}
public void setId(String id) {
Id = id;
}
}
Develop.java
public abstract class Develop extends Employee {
}
Maintainer.java
public abstract class Maintainer extends Employee {
}
JavaEE.java
public class JavaEE extends Develop {
//JavaEE开发工程师类
@Override
public void work() {
System.out.println("员工号为"+super.getId()+"的"+super.getName()+"员工,正在研发淘宝网站");
}
}
Android.java
public class Android extends Develop {
//Android工程师类
@Override
public void work() {
System.out.println("员工号为"+super.getId()+"的"+super.getName()+"员工,正在研发淘宝手机客户端软件");
}
}
Network.java
public class Network extends Maintainer {
//网络维护工程师类
@Override
public void work() {
System.out.println("员工号为"+super.getId()+"的"+super.getName()+"员工,正在检查网络是否畅通");
}
}
Hardware.java
public class Hardware extends Maintainer {
//硬件维护工程师类
@Override
public void work() {
System.out.println("员工号为"+super.getId()+"的"+super.getName()+"员工,正在修复打印机");
}
}
Test.java
public class Test {
public static void main(String[] args) {
//创建对象
JavaEE ee = new JavaEE();
//设置编号
ee.setId("100015");
//设置姓名
ee.setName("张三");
//调用方法
ee.work();
Android an = new Android();
an.setId("200007");
an.setName("李四");
an.work();
Network net = new Network();
net.setId("300123");
net.setName("王五");
net.work();
Hardware ha = new Hardware();
ha.setId("400110");
ha.setName("赵六");
ha.work();
}
}