继承的起源
在很多问题域当中,类与类之间除了has-a\use-a这两种关系之外,还有一种“is-a”。
从“继承”在生活中的概念,我们能够轻易得到继承是发生在具有上下关系(或者叫父子关
系)当中的,子不需要做任何努力直接就可以得到父所拥有的内容。
Java中做继承的语法
Java里面继承的语法很简单,就是“extends”关键字
```java
public class 子类 extends 父类 {
}
```
属性在继承中的表现
结论:父类中的属性 在继承的情况,是肯定被放入到了子类对象当中。只是由于访问修饰
符的限制,导致某些特殊访问修饰符的属性在子类中不能被直接访问。
访问修饰符
在Java当中一共提供了3个关键字,4种情况来表现访问修饰;
本类同包非子类 同包子类 非同包子类 非同包非子类
| | MySelf | MyWife | MySon | MyDaughter | Stranger |
|---|
| public公共 | 能 | 能 | 能 | 能 | 能 |
| protected受保护 | 能 | 能 | 能 | 能 | |
| 不写(默认)同包 | 能 | 能 | 能 | | |
| private私有 | 能 | | | | |
在这里看到,对于父类当中的私有属性,子类是看不见,但不代表它没有被继承。
父类当中的同包属性,非同包子类是看不见,同样不代表它没有被继承。
父类 与 子类 当中定义了重名属性
1、这在语法上是可行,但是我们应该避免这种设计情况,因为它会给我们造成认知上的麻
烦。正常的设计不应该出现这种情况;
2、这个时候在子类中由于拥有了两个重名属性,而不是用子类的属性覆盖了父类的同名属
性。只是说,当我们直接用属性名在子类中操作的时候,它会根据就近原则默认为本类声明
的属性;如果我们能加了this,那么在子类中写的this,仍然是子类的当前对象,所以仍
然认为是子类定义的那个属性。
如果在这种情况下,我们一定要去访问父类中定义的同名属性,那么用把"this."修改
为"super."。
这里我们引出了super这个关键字,如果说“this”代表的是当前对象,那么“super”代表的
是当前对象的来自于父类的部分。
构造方法 在继承中的表现
结论:父类的构造方法是不会被子类继承的。
原因:
1、从语法层面上,构造方法的名字必须和类名保持一致。如果子类继承了父类的构造
方法,那么相当于在子类里面有一个构造方法,但是该方法的名字是父类的名字。这样
语法体系出现了冲突。
2、从场景来说,构造方法的作用是用来产生对象的。父类的构造方法是产生父类对
象,子类构造方法是产生子类对象。如果子类继承了父类的构造方法,就相当于子类有
方法用来产生父类对象了,这明显不合理吧。
虽然没有继承,但是父类的构造方法在继承的实现机制中起了不可替代的作用的
Java当中实现继承的本质 --- 内存叠加
当我们new一个子类对象的时候,它会首先调用父类的构造方法,产生父类对象部分,然后
再调用子类的构造方法,在内存中父类对象的下面叠加上子类对象部分,从而形成一个完整
的子类对象。
当我们new一个子类对象是不是产生了两个对象(一个父一个子)?
答案:不是。我们只产生了一个对象,就是子类对象。只是由于这个子类对象是由两部分组
成的,一个是来自于父类的共有部分,然后叠加了来自子类的特有部分。
普通方法 在继承当中的表现
结论:父类当中的所有方法都会被子类继承,当然子类能不能调用到这个方法,仍然是受访
问修饰符的影响。
方法的重写
如果子类中重新定义一个与父类一模一样的方法,书写上子类自己的实现,那么子类的方法
就会覆盖父类的方法。
重写方法的规范要求:
1、方法名保持一致;
2、参数列表保持一致;
3、返回类型保持一致;
4、重写后的该方法访问修饰符不能比重写前小;
方法重写很重要,是面向对象当中构建下一个特征”多态“的基本手段。
重载 与重写
相同的地方:
1、重载与重写都是指的方法,没有属性重载属性重写的说法;
2、他们体现的思想是一样,”相同的行为不同的实现“。
**不同的地方:******
1、方法重载是在一个类里面有多个重名方法,各有各的实现;
方法重写是体现在继承关系当中,父类有一个方法,子类继承后也有这个方法,
但是子类的实现和父类不一样;
2、方法重载的语法要求:
方法名必须一样,参数列表必须不一样,与返回类型,访问修饰符无关;
方法重写的要求见上面,比重载要高得多。
在场景设计当中去区分它们,比如:
1、程序员都有写代码的行为,Java程序员书写Java代码,前端程序员书写JS代码。
这是重写! 程序员、Java程序员、前端程序员,都有写代码的行为,但是不同的程序
员子类各有各的实现
```java
class程序员{
public void codeing(){
}
}
class Java程序员 extends 程序员{
@Override
public void codeing(){
用Java代码实现
}
}
class 前端程序员 extends 程序员{
@Override
public void codeing(){
用JS代码实现
}
}
2、程序员都有书写代码的功能,给他笔记本就在笔记本上写,给他纸就在纸上写,什么都
不给就在沙地上画
这是重载!只有一个类型程序员,行为都是写代码,根据外部传入的参数类型或个数的不
同,各有各的实现
```java
class 程序员{
public void codeing(){
沙地上画
}
public void codeing(纸 ){
纸上写
}
public void codeing(电脑){
电脑上写
}
}
3、人都有吃饭的行为,中国人用筷子,美国人用刀叉,印度人用手
4、人都有吃饭的行为,给我筷子我夹着吃,给我勺子我挖着吃
继承的层次结构
继承可以从上往下顺序继承,这个层次结构理论上可以有无限层。
直接继承关系,上层的叫父类,下层的叫子类;
非直接的继承关系,上层的叫“基类” 或 “超类”; 下层的叫“派生类”。
这是“纵向”的结构。
生活中,每个人除了有父,还有母,我们是从他们两个同时继承而来的。这种情况,我们把
它叫做“多继承”。
但是,Java语言在设计的时候没有采纳“多继承”,而是使用的“单继承”,也就是说每个类
能且只能有一个父类。不存在:
```java
//报错
class 类 extends 父类, 母类{
}
```
在面向对象的设计思想当中,其实是没有限制只能做“单继承”的,有些编程语言(C++)选
择了“多继承”,有些编程(Java)选择了“单继承”。因此,常常能看到要求对“单继承”还
是“多继承”做比较。
“多继承”的好处:具有更好的丰富度!
不好: 类结构会出现网状结构,增加了复杂度。
“单继承”的好处:类继承层次结构简单,都是树形结构
不好:灵活性不够,丰富度不够。
不同编程语言有不同的设计出发点,Java只不过是选择了“单继承”。Java里面设计的另外
一个类型---接口,来弥补没有“多继承”缺失掉的丰富度。