Java中的继承与多态(继承篇)

在这里插入图片描述

🎉🎉🎉写在前面:
博主主页:🌹🌹🌹戳一戳,欢迎大佬指点!
博主秋秋:QQ:1477649017 欢迎志同道合的朋友一起加油喔💪
目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个小菜鸟嘿嘿
-----------------------------谢谢你这么帅气美丽还给我点赞!比个心-----------------------------

在这里插入图片描述



🌈一,继承

🌟1.1,为什么要继承

首先,我们已猫和狗两个类进行下对比,我们就可以发现,它们两个类有共同的地方,那既然是公有的,为什么不进行抽离呢?这样就不用写两遍了,这其实就是继承的思想。
在这里插入图片描述

class Animal{//动物类
    public String name;
    public int age;
}
class Dog extends Animal{
    public void bark(){
        System.out.println(this.name + "正在汪汪汪");
    }
}
class Cat extends Animal{
    public void miao(){
        System.out.println(this.name + "正在miaomiao");
    }
}

当我们进行共性的抽取之后,就得到了如上的代码,其中extends表示是继承的关系。

在这里插入图片描述

总结而言,继承的作用就是为了实现共性的抽离,进而实现代码的复用


🌟1.2,继承的语法

访问修饰符 class 子类名 extends 父类名{}
class Animal{
    public String name;
    public int age;
}
class Dog extends Animal{
    public String color;
    public void bark(){
        System.out.println(this.name + "正在汪汪汪");
    }
}

看这段代码,Dog类继承了Animal类,那可能有同学要问了,现在如果说new一个dog对象,它的内存图是怎么样的呢?

在这里插入图片描述

🚩注意:

🌖1,子类会将父类中的成员变量或者成员方法继承到子类中了

🌖2,子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了


🌟1.3,父类成员的访问

1.3.1,子类访问父类中的成员变量

🌖1,子类与父类不存在同名成员变量
class Father{
    public int date1 = 1;
    public int date2 = 2;
}
class Son extends Father{
    public int date3 = 3;
    public int date4 = 4;

    public void func(){
        System.out.println(this.date1);
        System.out.println(this.date2);
        System.out.println(this.date3);
        System.out.println(this.date4);
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Son son = new Son();
        son.func();
    }
}

程序运行截图:

在这里插入图片描述

内存布局:

在这里插入图片描述

当我们的子类继承父类后,子类的对象里面不仅仅存储着自己特有的成员属性,也有从父类那里继承过来的成员属性,所以通过子类的对象引用this都是可以访问到的。


🌖2,子类与父类存在同名的成员变量
class Father{
    public int date1 = 111;
    public int date2 = 2;
}
class Son extends Father{
    public int date1 = 1;
    public int date3 = 3;
    public int date4 = 4;

    public void func(){
        System.out.println(this.date1);
        System.out.println("父类同名成员" + super.date1);
        System.out.println(this.date2);
        System.out.println(this.date3);
        System.out.println(this.date4);
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Son son = new Son();
        son.func();
    }
}

程序运行截图:

在这里插入图片描述

内存布局:

在这里插入图片描述

当我们存在同名的成员变量时,你通过子类对象的引用this去访问的话,它肯定默认是优先访问子类的同名成员变量,如果我们想访问父类的同名成员变量的话,要用 super.变量名 去访问才行,,super代表的是从父类继承过来的属性的引用,有的书上也说super是父类的引用,但是这种说法其实是不准确的


🚩总结:

当我们在子类方法或者通过子类对象进行访问成员变量的时候,遵循就近原则,优先访问子类自己的,如果没有就去父类中找,父类中也没有那就编译报错。针对同名的成员变量,this只能访问子类自己的,要访问父类的同名成员变量,用super去访问。


1.3.1,子类访问父类中的成员方法

🌖1,子类父类不存在同名方法
class Father{
    public void fatherMethod(){
        System.out.println("父类方法");
    }
}
class Son extends Father{
    public void sonMethod(){
        System.out.println("子类方法");
    }
    public void func(){
        this.fatherMethod();
        this.sonMethod();
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Son son = new Son();
        son.func();
    }
}

程序运行截图:

在这里插入图片描述

既然子类是继承了父类的,所以通过子类当前对象的引用this就可以都调用到。


🌖2,子类和父类存在同名的方法
class Father{
    public void MethodA(int val){
        System.out.println("父类方法MethodA " + val);
    }
    public void MethodB(){
        System.out.println("父类方法MethodB");
    }
}
class Son extends Father{
    public void MethodA(){
        System.out.println("子类方法MethodA");
    }
    public void MethodB(){
        System.out.println("子类方法MethodB");
    }
    public void func(){
        this.MethodA(10);
        this.MethodA();
        this.MethodB();
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Son son = new Son();
        son.func();
    }

程序运行截图:

在这里插入图片描述

当子类和父类存在同名的成员方法的时候,依然是就近原则,优先访问子类的,注意,对于同名的方法,是有可能发生重载的,重载不一定是发生在同一个类里面,比如这里的MethodA父类子类就发生了重载,对于这种的话,虽然是同名,我们通过this依然是能够精确访问到的,但是如果同名方法发生的是重写的话(名字,返回值,参数列表都一样),那这个时候就只会优先访问子类自己的方法了,要访问父类的只能用关键字super。


🌟1.4,super关键字

super关键字的作用:

🌖1,super.成员名 访问父类的成员

🌖2,super.方法名 访问父类的方法

🌖3,super() 调用父类的构造方法


🚩注意:和this一样,只能在非静态方法里面使用。


🌟1.5,子类的构造方法

class Animal{
    public String name;
    public int age;

    public Animal(String name,int age){//父类构造方法
        this.name = name;
        this.age = age;
    }
}
class Dog extends Animal{
    public String color;
    public Dog(String name,int age,String color){//子类构造方法
        super(name,age);
        this.color = color;
    }
    public void bark(){
        System.out.println(this.name + " 正在汪汪汪");
    }

}

public class TestDemo {
    public static void main(String[] args) {
        Dog dog = new Dog("大黄",4,"黄色");
        dog.bark();
    }
}

在这里插入图片描述

要实例化出子类对象,那首先肯定得有父类对象,先有父才有子,所以在子类的构造方法里面我们得显式的调用父类的构造方法,来对继承过来的属性进行初始化。


🚩注意:

🌖1,如果说父类子类都没有显式的写构造方法,这种情况下,父类子类编译器都会默认提供无参构造方法,并且子类的构造方法默认是给你调用了父类的构造方法的。(在无参构造的情况下,子类父类的构造方法都不写,或者写其中一个都没有问题,因为编译器会我们提供,并且调用父类构造方法)
🌖2,如果说父类的构造方法是有参的,那么这个时候子类的构造方法必须自己写,并且调用父类的这个有参构造。
🌖3,在子类的构造方法中,super()调用父类构造方法,只能放在子类构造方法的第一行。
🌖4,super()在子类构造方法中只出现一次,并且不能与this()同时出现(因为两个都要争着放在第一行,矛盾了)。并且如果父类是无参构造的情况下,super()是隐藏存在的,所以这个时候注意别说没看到super(),然后你去用了this()也是错的。


🌟1.6,super与this

在这里插入图片描述


🌟1.7,初始化问题

在前面的类里面,我们就探讨过在一个类里面的初始化顺序的问题,那现在涉及到继承了,它的初始化顺序又是怎样的呢?

class Animal{
    public String name;
    public int age;
    static{
        System.out.println("Animal的静态代码块");
    }
    {
        System.out.println("Animal的实例代码块");
    }
    public Animal(){
        System.out.println("Animal的构造方法");
    }
}
class Dog extends Animal{
    public String color;
    static{
        System.out.println("Dog的静态代码块");
    }
    {
        System.out.println("Dog的实例代码块");
    }
    public Dog(){
        System.out.println("Dog的构造方法");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println("===========");
        Dog dog1 = new Dog();
    }
}

程序运行截图:

在这里插入图片描述

对于继承当中的初始化顺序,总结来说,就是由父及子,静态先行,并且静态内容只初始化一次。(我们讨论的顺序针对的是成员,代码块以及构造方法的执行顺序,方法都是要调用才会执行)


🌟1.8,protected关键字

在这里插入图片描述

对于protected修饰符,对于在同一个包里面,是没有任何限制的,不管是不是在一个类,但是涉及到继承上,在不同包上,必须是子类才可以访问到。

这里主要说下不同包中的子类,在子类中需要利用super才能访问。

//包demo1下
package demo1;
public class Test {
    protected int a;

    public static void main(String[] args) {

    }
}

//包demo2下
package demo2;
import demo1.Test;
public class Demo extends Test {
    public void func(){
        System.out.println(super.a);
    }
    public static void main(String[] args) {
        //Test test = new Test();
//        System.out.println(test.a);访问方式是错的
        Demo dmo = new Demo();
        dmo.func();
    }
}


🌟1.9,继承的方式

在这里插入图片描述


🌟1.10,final关键字

🌖1,修饰变量,表示这是一个常量,不能被修改

final int a = 10;

🌖2,修饰类,表示该类不能被继承

final class B extends A{};//类B不能在被继承

🌖3,修饰方法,表示该方法不能被重写。


🌟1.11,继承与组合

继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物

组合表示对象之间是has-a的关系,比如:汽车与其各个零部件之间,汽车是由它们组成

class Engine{//引擎类
    
}
class Tire{//轮胎类
    
}
...
class Car{//车类
    public Engine engine;
    public Tire tire;
}

和继承一样,组合也是能够实现代码的复用的,因为对于组合而言,只是将某一个类的实例作为了另外一个类的字段。


最后,今天的文章分享比较简单,就到这了,如果大家觉得还不错的话,还请帮忙点点赞咯,十分感谢!🥰🥰🥰
在这里插入图片描述

  • 35
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力学习.java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值