目录

一.引子:

二.什么是继承?

三.为什么要使用继承?

四:继承的基本语法

五.方法的重写

六.super关键字

七.构造器初始化顺序

八.访问控制符对继承的影响

九.final关键字对继承的限制

十.. 继承与组合的选择

十一.小结与实战演练


一.引子:

       假设你要写一个动物管理程序:有猫、狗、鱼……它们都有名字、年龄,都会吃饭、睡觉。
如果给每个动物类都重复写 nameage 和 eat()sleep(),代码会变得又臭又长,修改一个地方就得改十几个类。
这时候,Java 的继承就能帮我们“偷懒”——把公共部分抽到一个父类里,让子类自动拥有这些属性和方法。
今天我们就来搞懂 Java 继承的方方面面。

        首先我们先来看什么是继承:

二.什么是继承?

        继承 是面向对象三大特性(封装、继承、多态)之一。

        简单说,它允许我们定义一个新的类(称为子类或派生类),这个新的类可以直接获取现 有的类(属性和方法)的属性和方法。在设计继承的时候,我们把具有相同逻辑的属性或行为打包,管理,分类。

        举个例子,小猫,小狗,鱼,鸭子,这些都是动物,都具有运动的特性,那么我们就可以在动物类中可以添加公共的属性和行为,如姓名和运动,让这些新的类继承动物类。抽象出来,就是子类继承父类后,可以复用父类的属性和方法。子类和父类是"is-a"的关系。

三.为什么要使用继承?

        1.代码复用。继承可以实现属性和方法的共享,提高代码的复用性。我们在父类中定义的属性和方法,可以被子类继承过来使用。

        2.利于代码的修改。我们只需要在父类中修改代码即可。

        3.层次分明,逻辑清晰。通过继承关系,我们可以清楚的观察到各类之间的逻辑关系,         例如:狗是一种动物

        

四:继承的基本语法

        1.extends关键字:在子类中标明父类是谁,例如狗类继承动物类:

class Animal{
    public String name;
}

class Dog extends Animal{//Dog类中虽然没有任何东西,但是直接继承了动物类中的name属性
}

        2.继承的大原则:就近原则,字段或行为重名时,子类有就访问子类的,子类没有就访 问父类的,如果都没有就报错。

        3.注意事项:

        (1).子类会将父类中的成员变量成员方法继承到子类中。

        (2).子类继承父类后,必须添加自己的成员变量或成员方法,不然继承没有意义。

        (3).当父类和子类有同名的成员变量的时候,会优先访问子类自己的成员变量。在子类         中只能通过super关键字(后面会讲)访问父类继承过来的成员

        (4).继承的类叫做子类派生类,被继承的类叫做父类基类超类

        (5).当两个类的关系是is a的关系的时候,我们就可以把他设计成继承。

        (6).Java中的继承是单继承,即一个类只能继承一个父类,但是一个父类可以被多个类         继承

        

        (7).如果父类中有构造方法,那么子类在构造方法中的第一行必须使用super()方法先调         用父类的构造方法,给父类的属性赋值。

        (8).Java中可以多层继承,例如猫咪可以继承猫科动物类,猫科动物类可以继承动物类

public class Animal {
    String name;

    public void run() {
        System.out.println(this.name + " is running");
    }
}


public class Feline extends Animal {
}


public class Cat extends Feline {
}

        

五.方法的重写

        1.为什么需要方法的重写:父类的方法不适合子类,例如鱼也是动物,也可以继承动物         类,但是鱼的运动方式是游泳,而不是跑

        2.重写的规则:重写是指在父类和子类中,方法名,返回值,参数列表都相同,用注解          @overread标注。

        

        3.返回值类型也可以是原类型的子类

public class Animal {
    public String name;

    public Animal func(){
        return null;
    }
}

public class Fish extends Animal{
    @Override
    public Fish func(){
        return null;
    }
}

         4.重写的注意事项:

        (1).静态的方法不能重写,因为静态的方法属于父类本身,而不是父类的对象。

        (2).使用final标记的方法不能重写,final关键字本身就是不能改变的意思。
        (3).子类中重写的方法的访问权限必须大于等于父类中的重写的方法。

        (4).被private修饰的方法不能重写

        

        5.@override的作用:可以辅助我们进行编译检查。如果我们在重写的时候哪里写错         了,@override就会进行报错。例如,还是上面的代码,我们在子类的方法中加入一个         参数:

         

六.super关键字

        当父类和子类中存在相同的属性和方法的时候,我们可以使用super关键字在子类中来访问父类的成员变量和方法。

        1.super的三种用法:

        (1).调用父类隐藏的成员变量

        (2).调用父类中被重写的成员方法

        (3).在子类的构造方法中调用父类的成员方法(只能在构造方法的第一行)

        补充:子类一定会默认存在一个编译器生成的隐藏的不带参数的super(),如果我们写了         super(),那么编译器将不再默认生成。

        2.super()的性质:

        (1).直接性:当存在多重继承的时候,super()只能调用当前类直接继承的类的构造方法

        (2).限制性:在构造方法中,super()必须放在第一行

        (3).默认性:即使不写super,编译器也会默认在第一行提供super();

        (4).依赖对象:super()只能在非静态方法中使用

        

        3.super()在内存中的操作原理:

        在创建子类对象的时候,JVM会在堆中分配一块连续的地址空间,存放父类继承下来成员变量和成员方法。super就会在堆中跳过子类的属性,仅访问属于父类的那块内存区域。

七.构造器初始化顺序

        发生继承之后,构造器的初始化顺序为:

        父类静态代码块--->子类静态代码块--->父类实例代码块--->父类构造方法--->子类实例代码块--->子类构造方法

        代码演示如下:父类Animal ,子类Fish

public class Animal {
    public String name;

    public Animal(String name) {
        System.out.println("Animal 中执行了 构造方法....");
        this.name = name;
    }

    static {
        System.out.println("Animal 中执行了 静态代码块....");
    }

    {
        System.out.println("Animal 中执行了 实例代码块....");
    }

    public Animal func(){
        return null;
    }
}

public class Fish extends Animal{

    public Fish(String name) {
        super(name);
        System.out.println("Fish 中执行了 构造方法....");
    }

    static {
        System.out.println("Fish 中执行了静态代码块.... ");
    }

    {
        System.out.println("Fish中执行了实例代码块....");
    }

    @Override
    public Fish func(){//重写父类的方法
        return null;
    }
}

public class Test {
    public static void main(String[] args) {
        Fish fish = new Fish("彩鳞");
    }
}

        运行结果如下:

八.访问控制符对继承的影响

        这里我们回顾一下上篇文章中的各个访问控制符的权限:

        1.由于子类的访问控制符的权限必须比父类的访问控制符的权限高,所以被private修饰         的类不能被继承。

        2.被protected修饰的类可以被跨包继承

        3.private 成员不被继承,但子类对象内存中仍然存在,只是无法直接访问

九.final关键字对继承的限制

        final的三种用法:

        1.修饰变量:被final修饰的变量不能被修改
        2.修饰类:被final修饰的类不能被继承

        3.修饰方法:被final修饰的方法不能被重写

十.. 继承与组合的选择

        我们先来了解一下组合:

        1.组合的意义:组合是把多个类的对象作为自己的成员变量,拼装在一起,从而复用其         功能。例如:汽车包括车轮,发动机,我们就把发动机和车轮的对象作为一个新的类中         的成员变量。代码演示如下:
        

public class Engine {
    void star(){
        System.out.println("发动机启动了");
    }
}

public class Wheel {

    void rotate(){
        System.out.println("车轮在旋转");
    }
}

public class Car {
    Wheel[] wheels = new Wheel[4];//车轮
    Engine engine = new Engine();//发动机

    Car(){
        for (int i = 0; i < 4; i++) {
            wheels[i] = new Wheel();
        }
    }

    void drive(){
        engine.star();

        for(Wheel w : wheels){
            w.rotate();
        }

        System.out.println("汽车在行驶");
    }

}

public class Test {
    public static void main(String[] args) {
        Car car = new Car();
        car.drive();
    }
}

运行结果如下:

        

        

        我们发现:Car并没有继承轮胎和发动机,他是把这两个类的对象当作自己的部件,这就是组合的核心思想。

        

        下面是组合和继承的对比

维度 继承 组合
关系 子类继承父类,is-a 整体包含部分,has-a
关键字 extends
代码复用 自动获得父类的属性和行为 需显式调用被包含对象的方法
耦合度 高(父类改动影响子类) 低(内部改动不影响外部)
灵活性 差(只能单继承) 好(可以创建多个对象)
        

        

    十一.小结与实战演练

                到此为止,我们的继承就介绍完了,各位看官现在可以去使用继承来完成一个实战案例:

        1.动物类为父类,让小狗类,鱼类,鸭子类共同继承动物类

        2.动物类中有姓名,年龄属性,跑动方法。子类中重写跑动方法。(注意,鸭子即可以跑步,         又可以游泳哦~)

        3.父类中使用带参构造,子类在构造方法中使用super()调用父类的构造方法

        期待大家在评论区讨论遇到的问题,发布自己的代码哟!

更多推荐