Java---继承
(一). 继承的概念
继承是对每个类的共性进行了抽取
好处:提高了代码的复用性
首先,我们通过一个例子来引出什么是继承

我定义了两个类,一个是小猫的类,一个是小狗的类,它们都有名字和年龄,并且他们都会吃饭,它俩唯一不同的就是一个“汪汪叫”,一个“咪咪叫”。
那么它俩是不是就有很多代码是类似的啊,比如成员变量name,age和成员方法eat,那么是否可以将它们一样的部分进行抽取呢?
这就引入了继承。
现在我又定义了一个Animal的类

那么我现在用继承的思想来完成代码的复用

可以看到,我在Cat类 类名和Dog类 类名的后面使用了extends关键字,那么现在这段代码的说明就是,我Cat这个类和Dog这个类分别都继承Animal这个类
简单来说,Animal中有什么,Dog/Cat就继承什么
此时Dog和Cat这个类就称为子类/派生类,Animal这个类就叫做父类/基类/超类
注意,一旦发生了继承,子类会将父类的成员变量和成员方法继承到子类中。
子类和父类发生了继承关系后,那么子类一定要有自己特有的成员变量或成员方法,即能够体现出出与父类的不同,否则就没必要发生继承了。
(二).成员访问
1.子类访问父类成员变量

通过上面的代码可以看出,ClassB是继承了ClassA的,由于子类会将父类的成员变量和成员方法继承到子类中,所以在子类ClassB的func1中是可以访问父类ClassA中的成员变量a的。
2.子类的成员变量和父类重名时的访问

通过图片中的代码,可以看出,ClassB继承于ClassA,同时,ClassA中有成员变量a=3,ClassB中有成员变量a=20,然后我在func1中写输出a的值。
我又创建了test类,然后通过类ClassB 实例化了一个classB这个对象,然后通过classB来调用func1这个方法
结果显而易见,输出的是20,所以我们可以想到,func1中的a是子类ClassB中的成员变量a
所以,当子类和父类中有重名的成员变量的时候,通过子类的引用,优先调用子类的成员变量
3.访问成员方法


通过图片中的代码和运行结果可以看出,虽然子类和父类都有func1,但是子类去调用的时候,调用的是子类的func1,但是当子类调用func2的时候,程序输出的结果是父类的成员方法func2
通过上面的例子我们可以看出
当子类调用子类和父类同名的成员方法的时候,子类调用的是子类自己的成员方法
当子类调用子类没有的成员方法的时候,子类会现在子类中找,如果没有,则去父类中找,如果找到了,此时调用的就是父类的成员方法,如果没找到,则返回错误信息
(三).super关键字
前面,我们说,当子类访问子类和父类重名的成员变量时,我们访问的是子类的成员变量,那么我问题来了,我如果想要访问父类的重名成员变量应该如何访问?
答:使用super关键字
super关键字的作用:使用super关键字可以访问子类继承过来的父类成员
下面这个例子会让你明白super关键字的作用


当我在子类的func1中打印a的时候,我们可以看到打印的是子类的a,那么如何访问父类的a?
就要用到super关键字了


通过程序的运行结果,我们可以看到,我们确实用到了super关键字来访问我们父类的成员变量a
注意:super只能指当前类的父类不能指代父类的父类
当使用super关键字时,必须放在第一行,同样的,this关键字也必须放在第一行,也就说,二者不能共存
(四).子类的构造方法
1.当你没有提供构造方法时,java会默认给你提供一个不带任何参数的构造方法,但是一旦你写了任何一个构造方法,那么java就不会给你提供构造方法了
2.当子类继承父类之后,子类需要显示调用父类的构造方法,要先帮助父类的成员进行初始化
这句话具体是什么意思呢?我们通过一个例子来看

通过上面的代码,我们可以看出,父类ClassA有自己的构造方法,子类ClassB也有自己的构造方法,那么为什么会报错呢?
这就是我们刚才说的了,当子类继承父类之后,子类需要显示调用父类的构造方法,要先帮助父类的成员,所以我们需要通过super关键字对a父类中的a进行初始化

当父类有无参的构造方法或者没有构造方法的时候,在子类构造方法第一行默认会有隐含的super()调用,即调用父类构造方法
当父类有 有参的构造方法时,子类的构造方法必须先调用父类的构造方法,帮助父类进行初始化,否则会编译出错
(五).继承与代码块之间的代码执行顺序

首先我创建了Animal类,里面有成员变量name,age 和 eat方法,并且有静态代码块,实例代码块,构造代码块
我又创建了Dog类和Cat类,它俩分别都继承了Animal类,然后它俩的类中分别都提供了构造方法,都提供了静态代码块,实例代码块,构造代码块
那么现在我在test类中,通过Dog类实例化了一个dog对象,然后通过dog对象调用Dog类里面的bark()方法,程序的运行结果如下

通过程序的运行结果我们可以看出,先调用的父类的静态代码块,然后调用的子类的静态代码块,再调用父类的实例代码块和构造代码块,最后调用了子类的实例代码块和构造代码块

当我通过Dog类实例化了两个对象的时候,代码的运行结果是

我们可以看出,静态代码块在第二个对象调用的时候没有执行,所以更加验证了我们之前说的
静态代码块只会在类加载的时候才会执行,并且只会执行一次
(六).访问修饰限定符protected
在封装的那一节,我们了解到了访问修饰限定符
那么我们来看看他们的具体区别是怎样的吧

private:只能在当前包当前类中使用
deault:只要是在同一个包底下的就能访问
protected:同一个包底下的是可以使用的,不同包的只有子类才能使用
public:任何地方都能使用
(七).java所支持的继承方式

在java中只支持这三种继承方式
Java不支持多继承

(八).密封类
关键字final
如果一个类不想被继承,那么可以通过加一个关键字final来修饰这个类,此时,这个类就叫做密封类

通过图片上的代码我们可以看出,当我对Animal类用final修饰后,原本继承于Animal类的Dog类和Cat类都出现了编译错误,通过上面的例子我们可以看出
被final修饰的类无法被继承
同样,不光类是这样,当我对成员变量用final修饰的时候,也是无法修改的,此时成员变量变为了常量

此时,被final修饰的变量的值无法被修改
(九).继承 和 组合
继承通常表示为 is - a 的关系(例如:狗是动物,猫是动物)
组合可以表示为 has - a 的关系,也可以表示为 a part of 的关系,例如,发动机是车的一部分


我们可以这样理解,奥迪车是车,所以奥迪车继承了车,同时,轮胎又是车的一部分,所以车和轮胎之间可以通过组合建立联系。
更多推荐


所有评论(0)