Java 中的继承介绍和使用
一、继承的概述
继承的好处
1、提高了代码的复用性
2、让类与类之间产生了关系,给第三个特征多态提供了前提。
多重继承问题
java 中支持单继承,不直接支持多继承,但对C++中多继承机制进行了改良。
单继承:一个子类只能有一个直接父类。
多继承:一个子类可以有多个直接父类(java 中不允许,进行改良 -> 多重继承) 不直接支持是因为多个父类中有相同的成员时,会产生调用不确定性。
二、继承的特点
在子父类中,成员的特点体现
成员变量
当本类的成员变量和局部变量同名时,用this区分 当子父类中的成员变量同名时,用super区分父类
this代表一个本类对象的引用 super代表一个父类空间
成员函数
当子父类中出现成员函数一模一样(函数名、返回值、参数个数、参数类型)的情况,会运行子类的函数。这种现象,称为覆盖操作。
函数两个特性:
1、重载。同一个类中 2、覆盖。子类中。覆盖也称为重写,覆写。
注意:子类方法覆盖父类方法时,子类全县必须要大于等于父类的权限。静态只能覆盖静态,或被静态覆盖。
构造函数
子父类的构造函数特点:
在子类构造对象时候,发现,访问子类构造函数时,父类也就运行了。 原因是:在子类构造函数中第一行有一个默认的隐式语句。
super()
注意:
- 子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。 super语句必须要定义在子类构造函数的第一行。因为父类的初始化动作要先完成。
- 为什么子类实例化的时候要访问父类中的构造函数呢?
- 那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前 要先看父类是如何对自己初始化的。
- 所以子类在构造对象时,必须访问父类中的构造函数, 为了完成这个必须的动作,就在子类中的构造函数中加了super()语句。
- 如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用父类中哪个构造函数。
- 父类中哪个构造函数,同时再累构造函数中如果使用this调用了本类构造函数时,那么super就没有了。 因为super和this都只能定义第一行,所以只能有一个。但是可以保证的是,子类中肯定会有其他的构造函数 访问父类的构造函数。
示例代码
class Fu{
Fu(){
System.out.println("Fu run");
}
}
class Zi{
Zi(){
//这里有一个隐式语句,调用的就是父类中的空参数的构造函数。
//如果父类中没有空参数的构造函数,则会报错。
//super()
System.out.println("Zi run");
}
}
class ExtendsDemo{
public function void main(){
new Zi();
}
}
子父类中的成员变量内存图解
子父类中的构造函数 - 子类的实例化过程图解
class Fu{
Fu(){
super();
show();
return;
}
void show(){
System.out.println("fu show");
}
}
class Zi extends Fu{
int num = 8;
Zi(){
super();
//-->通过super初始化父类内容时,子类的成员变量并未显示初始化。等super()父类初始化完毕后
//才进行子类成员变量的显示初始化。
System.out.println("zi cons run...."+num);
return;
}
void show(){
System.out.println("zi show..."+num);
}
}
class ExtendsDemo{
public static void main(String[] args){
}
}
一个对象实例化过程
Person p = new Person();
1、JVM会读取指定路径下的Person.class文件,并加载进内存,并会先加载Person的父类 (如果有直接的父类情况下)
2、在堆内存中的开辟空间,分配地址
3、在对象空间中,对对象属性进行默认初始化。
4、调用对应的构造函数进行初始化。
5、在构造函数中,第一行会先调用父类中的构造函数进行初始化。
6、父类初始化完毕后,再对子类的属性进行显示初始化。
7、再进行子类构造函数的特定初始化
8、初始化完毕后,将地址赋值给引用变量。
三、final关键字
final 可以修饰类、方法、变量
- final 修饰的类不可以被继承
- final 修饰的方法不可以被覆盖
- final 修饰的变量是一个常量,只能被赋值一次
- 内部类只能访问被 final 修饰的局部变量。
四、抽象类
抽象类特点
1、方法只有声明没有实现,该方法就是抽象方法,需要被abstract修饰。
2、抽象方法必须定义在抽象类中,该类必须也被abstract修饰
3、抽象类不可以被实例化。只能被继承。
4、继承抽象类的子类,必须覆盖抽象类的所有抽象方法后,该子类才可以实例化。否则该子类还是抽象类。
问答
1、抽象类中有构造函数吗? 有,用于给子类对象进行初始化
2、抽象类可以不定义抽象方法吗? 可以的,但是很少见,目的就是不让该类创建对象。AWT的适配器对象就是这种类
3、抽象关键字不可以和哪些关键字共存? private/static/final
4、抽象类和一般类的区别? 一般类中不能定义抽象方法,抽象类中可以定义抽象方法。 一般类可以被实例化,抽象类不能被实例化。
5、抽象类一定是个父类吗? 是的。因为需要子类覆盖其方法后才可以对子类实例化。
五、接口
当一个抽象类中的方法都是抽象方法的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口-interface
格式:定义接口使用的的关键字不是class而是interface
interface{}
接口中的成员修饰符是固定的 成员常量:public static final 成员函数:public abstract 发现接口中的成员都是public的
接口的出现将“多继承”通过另一种形式体现出来,即“多实现”
接口的实现 implements
类与类之间是继承关系,类与接口之间是实现关系
接口是一个特殊的抽象类,任然不可以被实例化,只能由实现了接口的子类覆盖了接口中所有的抽象方法后,该子类、才可以实例化。否则这个子类就是一个抽象类
在 java 中不直接支持多继承,因为会出现调用的不确定性,所以 java 将多继承机制进行改良,在 java 中变成多实现。一个类可以实现多个接口
一个类在继承另一个类的同时,还可以实现多个接口
接口的特点
1、接口是对外暴露的规则
2、接口是程序的功能扩展
3、接口的出现降低耦合性
4、接口可以用来多实现
接口与抽象类的区别
共性:都是不断抽取出来的抽象概念
区别1:抽象类体现继承关系,一个类只能但继承 接口体现实现关系,一个类可以多实现
区别2:抽象类是继承,是 is a 关系,接口是实现,是 like a 关系
区别3:抽象类可以定义非抽象方法,供子类直接使用,接口中的方法都是抽象的,接口中的成员都有固定修饰符。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论