一、定义
在生活中,我们会经常听到继承这个词语,例如:某某某继承了某某某的遗产,某某某继承了某某某的皇位......其实在Java中也是类似的。在Java中,继承,是将两个类的共性抽取出来,从而达到对代码的复用(重复使用),将这些共性再组成一个类,这两个类就叫做子类(派生类),而新组成的这个类,就叫做父类(基类、超类),当子类继承父类后,就会把父类的成员和方法全部继承。读到这里,相信大家还是不怎么懂的,接下来我会用代码来帮助大家理解。
二、代码简单实现继承
我们这里定义了两个类,分别猫类和狗类(其中extends为继承的关键字,表示继承关系):
而小猫小狗会有很多共同的特性,如:颜色、年龄、名字,以及行为方面的,如:睡觉......,于是我们便把这些特性抽取出来,来组成一个新的类(Animal):
于是Animal类便是Dog类和Cat类的父类,Dog类和Cat类便是Animal类的子类。
在这里我们需要注意以下几点:
1.在Java中一个子类只能继承一个父类,若继承多个父类,是会报错的(如图所示)。
2.若父类中的成员或方法是用private来修饰的,那子类仍然会继承父类的这些成员或方法,但是无法访问。
如上图所示,我们将父类中的成员name改为private修饰,那么我们在子类中就无法访问这个成员(注意是继承了父类成员和方法,但是无法访问):
我们访问的话会变红报错(如上图所示)。
三、访问父类成员(以下以成员变量为例,方法也是一样的)
1、父类和子类成员变量不同名
我们可以直接访问从Big中继承的a和b:
运行结果:
2、父类和子类成员变量同名
当发生如下情况时:
此时,优先访问子类自己(其中super为关键字(下面会详细解释,要耐心看完哦),可直接访问父类):
我们分别打印子类和父类中的成员变量a,我们发现父类中的a为默认值0,子类中a的值为我们所赋的值1,故:当父类和子类成员变量同名,优先访问子类中的成员变量(就近原则)
但是,如果我们非要访问父类中的a成员呢?
很简单,我们只需要一个关键字---super(下面会详细解释,要耐心看完哦)
如下:
super.a便可访问父类中的成员变量,运行结果如下:
3、访问的成员变量父类和子类中都没有
如果访问的成员变量子类中没有,则访问父类中的,如果父类中也没有,则编译报错。
四、重载和重写
根据前期学习的JavaSE,我们初步的了解了重载,我们可能简单的认为重载只能在一个类中使用,其实不是这样的:(下图为Java官方给出的重载定义)
故子类和父类中,也可以构成重载。
当父类和子类中成员方法名字相同,而参数不同时,构成重载;
当父类和子类中成员方法名字以及参数相同时,构成重写;
五、super关键字
在Java中,由于设计的不好,或者特殊场景的需要,父类和子类中可能会存在相同名称的成员,如果我们要在子类方法中访问父类同名成员,我们就需要super关键字来访问。
我们需要注意以下几点:
1.super和this的区别
(以我们上面所写代码为例)
相同点:
(1)this是一个关键字,会优先访问子类自己的成员,如果没有,则再访问父类的。
(2)super也是一个关键字(并非引用),在代码层面起到易读的效果。
(3)都只能在类的非静态方法中使用,用来访问非静态成员方法和字段。
不同点:
(1)this,会优先访问子类自己的成员,如果没有,则再访问父类的。
(2)在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性。
(3)构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有。
2.super的使用
(1)super.data;访问父类的普通成员变量
(2)super.func();调用父类的普通成员方法
(3)super();调用父类的构造方法
注意事项:
1.super只能在非静态方法中使用
因为static修饰的成员方法是属于类的,和对象无关,在加载时就被调用,故静态的方法中不能使用super也不能使用this
2.在子类方法中,访问父类的成员变量和方法
六、使用 super();调用父类构造方法
在了解这点之前,我们先来看看这段代码:
我们发现,当我们在Animal类中写了一个带两个参数的构造方法后,Dog类有了报错警告,这是因为,我们没有对父类进行初始化,当我们写了带两个参数的构造方法后,系统便不再提供的不带参数的构造方法(父类即Animal类中),这时父类无法初始化,于是出现了错误,要知道对象属性的初始化一定得调用构造方法。
接下来,就需要suepr关键字出场了:
首先,我们在main方法中实例化子类对象时,将父类及子类成员要初始化的值通过参数传过去,接着在子类中用带参数构造方法接收,并用super来调用父类构造方法并传参,完成对父类成员的初始化。
-------可能大家心存疑问:可是没有调用带参数的构造方法之前也没有出错啊?我们也没有初始化啊,为什么调用了之后就会出错呢?
-------这是因为,系统默认帮我们调用了不带参数的构造方法,来完成了默认的初始化。如下图:
只是在我们看不见的地方,系统完成了默认初始化。
我们打印name,便是默认初始化得值null:
七、继承关系上的执行顺序
相信在学static时,我们就已经知道static所修饰的在加载时就已经执行,那在继承上,执行顺序又是如何呢?
我们先来看以下代码:
我们来运行一下,看一下执行顺序如何:
通过分析执行结果,得出以下结论:
1、父类静态代码块优先于子类静态代码块执行,且是最早执行
2、父类实例代码块和父类构造方法紧接着执行
3、子类的实例代码块和子类构造方法紧接着再执行
4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行
八、final关键字
final关键字可用来修饰成员变量、方法和类
1.修饰成员变量,表示常量(即不能被修改)
2.修饰类,则该类为密封类,不可再被其他类继承
九、组合
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码复用的效果。
组合并没有涉及到特殊的语法 (诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段。
组合可用以下代码实现:
组合是has a的关系(...是...的一部分),比如:狗是动物,猫是动物
继承是is a的关系(...是...的),比如:老师是学校的一部分,学生是学校的一部分
这样可以帮助大家理解
说到这里,我们继承的内容就全部讲完了,
为了写好这篇博客,花费了博主很长的时间,
如果能够帮助到大家的话,
就留下您的赞吧