封装
继承
多态
面向对象思想,有 3大特性,封装,继承,多态
个人认为,这 3大特性,是整个 面向对象思想的核心和精髓,深刻理解和掌握这 3大思想,是好好掌握 Java语言的关键
1 概述
父类是 不断地从子类向上抽取而来的,继承可以 提高代码的 复用性
继承的优点:
- 提高了代码的复用性
- 让类与类之间,产生了关系,给第三个特征 — 多态 的出现,提供了前提
2 单继承与多重继承
Java支持单继承,不直接支持多继承,但是,可以通过 多实现
的方式,实现多继承
要使用一个继承体系时
1 查看该体系中的 顶层类,了解该体系的基本功能
2 创建体系中的 最子类对象,完成功能的使用
定义继承
当类与类之间,存在着所属关系时,就定义继承
A 是 B 的一种,A extends B
所属关系: is a
3 子父类中成员特点
子有不找父,局部有不找成员,先找自己内存空间的,再找外部内存空间的
在子父类中,成员的特点体现
1 成员变量
2 成员函数
3 构造函数
3.1 成员变量
a 区分
子父类中的成员变量同名,用 super 区分父类
本类的成员变量和局部变量同名,用 this 区分
this:代表一个本类对象的引用
super:代表一个父类空间
this 代表子类对象,super 不代表父类对象,仅代表父类空间
在代码Zi z = new Zi()
中,有子类对象,没有父类对象,子类为什么能够获得父类对象的内容,因为,子类持有父类的引用super
b 子父类成员变量的内存图解
代码分析:
Zi z = new Zi();
加载子类 Zi,因为 子继承父,class Zi extends Fu
,父先进来,父类是没有对象的,那么父类的属性 num,就存储到了子类内存中。
怎么存储的:
子一继承父,就意味着子多了一个属性 num,子的 num,默认为 0,父的 num,默认为 0,然后分别进行初始化,5,4
在实际开发中,这种情况基本没有
因为子类继承父类,那么父类中的属性,一定是公用的,不需要修改的, 如果有,说明父类写的不够好
num 一般都定义为 private,对外提供 set , get 方法,进行获取和修改
子类不能直接访问父类中的私有内容,但是可以间接访问,比如通过 set get 方法
3.2 成员函数
覆盖
当子父类中出现成员函数一模一样的情况,会运行子类的函数,这成为函数的覆盖
函数的两个特性
- 重载 — 同一个类中 (override)
- 覆盖 — 子类中 — 也成为 重写,覆写 (override)
覆盖注意事项
- 子类方法覆盖父类方法时,子类权限必须要大于等于父类的权限
- 静态只能覆盖静态,或被静态覆盖
覆盖的应用 — 什么时候使用
当对一个类,进行子类的扩展时,子类需要保留父类的功能声明,但是要定义子类中,该功能的 特有内容时,就使用覆盖操作
不建议对原代码进行修改,把原代码的功能进行继承,自己添加新的功能
3.3 构造函数
子父类构造函数的特点:
子类中所有的构造函数,默认都会访问,父类中的空参构造函数
class Fu
{
int num ;
Fu()
{
num =10;
System.out.println("A fu run");
}
Fu(int x)
{
System.out.println("B fu run..."+x);
}
}
class Zi extends Fu
{
int num;
Zi()
{
//super();//调用的就是父类中的空参数的 构造函数。
System.out.println("C zi run"+num);
}
Zi(int x)
{
this(); // 有this(),就没有super(); 怎么访问父类?
// 通过 this(),访问 Zi(){} 通过Zi(){}中的 默认super()访问父类
// super();
//super(x); --- 父类是带参构造函数,子类可以指定参数,super(x)
System.out.println("D zi run "+x);
}
}
class ExtendsDemo4
{
public static void main(String[] args)
{
new Zi(6);
// new Zi(6) 这个怎么走
// 首先找到子类构造函数 Zi( int x); 这个构造函数的第一句是默认的 super();
//所以去找父类的空参构造函数,如果没有,报错,不是去找 父类的带参构造函数Fu(int x);
//如果想使用指定的构造函数,必须手动指定 super(x);
}
}
class Demo//extends Object
{
/*
Demo()
{
super(); --- Java面向对象,对象就有共性,Java将所有对象进行抽取,抽取出一个最顶层的类 Object
--- 所以,创建的任何对象,都是 Object的子类,所以 class Demo 等于 class Demo extends Object
return;
}
*/
}
1 为什么子类实例化的时候,要访问父类中的构造函数
因为子类继承父类,继承了父类的内容(属性和方法),所以在使用父类内容之前,要先看看,父类是如何对自己的内容进行初始化的
为了完成这个必须的动作,就在子类的构造函数中,加入了 super() 语句
2 如果父类中,没有定义空参构造函数,那么子类的构造函数,必须用 super(),明确要调用父类中的哪个构造函数;同时,子类构造函数中如果使用 this调用了本类的构造函数时,那么 super 就没有了。因为 super 和 this,都只能定义一行,所以只能有一个。
但是,可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。若没有,初始化不了
super 语句,必须要定义在子类构造函数的第一行
因为 父类的初始化动作,要先完成