继承 -- Inherit

212 阅读7分钟

继承的起源

    在很多问题域当中,类与类之间除了has-a\use-a这两种关系之外,还有一种“is-a”。

    从“继承”在生活中的概念,我们能够轻易得到继承是发生在具有上下关系(或者叫父子关
    
    系)当中的,子不需要做任何努力直接就可以得到父所拥有的内容。
    

Java中做继承的语法

    Java里面继承的语法很简单,就是“extends”关键字


    ```java

        public class 子类 extends 父类 {

        //子类的内容

    }

    ```

属性在继承中的表现

    结论:父类中的属性 在继承的情况,是肯定被放入到了子类对象当中。只是由于访问修饰
    
    符的限制,导致某些特殊访问修饰符的属性在子类中不能被直接访问。

访问修饰符

    在Java当中一共提供了3个关键字,4种情况来表现访问修饰;


    本类同包非子类 同包子类 非同包子类 非同包非子类
    
 MySelfMyWifeMySonMyDaughterStranger
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里面设计的另外
    
    一个类型---接口,来弥补没有“多继承”缺失掉的丰富度。