前言
在了解完类和对象之后,想必大家对Java又有了新的认识,今天我们来介绍继承,接下来的学习我们将步入Java语法阶段的重点和难点,加油宝儿们!!!
继承
继承
1.为什么需要继承
- Java中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是现实世界错综复杂,事物之间可能会存在一些关联,那么在设计程序中就需要进行考虑如何将代码进行简化呢?
- 比如:猫和狗,它们都是动物,我们可以把它们共有的属性、方法拿出来——这就叫继承。接下来,我会带你们细细分析“继承”
2.继承的概念
能否对猫和狗的共性进行抽取呢?面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用
继承机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行拓展,增加新功能,这样产生新的类,称为派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程,继承主要解决的问题是:共性的抽取,实现代码复用
例如:猫和狗都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用。
画图理解如下
3.继承的语法
在Java中如果要表示类之间的继承关系,需要借助extends
关键字
修饰符 class 子类 extends 父类{
……
}
对上述场景用代码实现
class Animal{
String name; int age; String sex;
public void greet(){
System.out.println(name+"大家好!!!");
}
public void sleep(){
System.out.println(name+"在睡觉!!!");
}
public void drink(){
System.out.println(name+"在喝水!!!");
}
}
class Cat extends Animal{
public void eat(){
System.out.println(name+"吃猫粮!!!");
}
}
class Dog extends Animal{
public void eat(){
System.out.println(name+"吃狗粮!!!");
}
}
上述图示中,Dog和Cat都继承里Animal类,其中Animal类称为父类(基类或超类),Dog和Cat可以成为Animal的子类(派生类),继承之后。子类可以复用父类中的成员,子类在实现时只需关心自己新增加的成员即可。
继承成员方法和成员变量,达到了代码复用的效果
4.父类成员访问(重点!!!)
在继承体系中,子类将父类中的方法和字段继承下来了,那在子类中能否直接访问父类中继承下来的成员呢?
(1)子类和父类不存在同名成员变量
子类和父类不存在同名成员变量时,只需要extends
关键字就可以在子类中直接访问
代码如下
class Base{
int a;
int b;
}
class Derived extends Base{
int c;
public void method(){
a = 10;//访问从父类中继承下来的a
b = 20;//访问从父类中继承下来的b
c = 30;//访问自己子类的c
}
}
(2)子类和父类成员变量同名!!!
引入
super
关键字
由于设计不好或者因场景需要,子类和父类中可能会存在相同名称的成员,如果要在子类方法中访问父类同名成员时,该如何操作?直接访问是无法做到的,Java提供了super
关键字,该关键字的作用:在子类方法中访问父类的成员。
理解
super
和this
的区别!!!
1.当子类和父类是同名的成员变量时,在子类当中访问这个同名的成员变量,访问的是子类自己的
2.this
既可以访问父类的成员变量,也可以访问子类的成员变量,this
访问父子同名变量时遵循子类优先
3.super
只能访问从父类中继承过来的成员变量
4.super
只是一个关键字,提高代码的可读性,让别人看到这样访问就知道访问的是父类
画图理解
super
和this
的效果
代码理解(访问成员变量)
class Base{
int a; String b;
}
class Derived extends Base{
int a; String b; int c;
public void method(){
super.a = 10;//访问从父类中继承下来的a
this.a = 20;//访问子类中的a,等价于a = 20;
super.b = "abc";//访问从父类中继承下来的b
this.b = "def";//访问子类中的b ,等价于b = "def";
c = 30;//访问自己子类的c
}
}
代码理解(访问成员方法)
class text{
public void fun(){
System.out.println("打印父类的成员方法");
}
}
class text2 extends text{
public void fun(){
System.out.println("打印子类的成员方法");
super.fun();
}
}
public class text1 {
public static void main(String[] args) {
text2 text = new text2();
text.fun();
}
}
//输出结果///
打印子类的成员方法
打印父类的成员方法
Process finished with exit code 0
【说明】
- 通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错
- 通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错
super.data
访问父类成员变量
super.fun()
访问父类成员方法
super()
访问父类构造方法
5.子类构造方法
父子父子,先有父后有子
当子类继承父类后,要先帮助父类(只能在子类中调用父类的构造方法)进行构造,然后在构造自己
代码理解
class Method{
public Method(){
System.out.println("打印父类的构造方法");
}
}
class Met extends Method{
public Met(){
//super();
//注意子类构造方法中默认会调用父类的无参构造方法
//用户没有写时,编译器会自动增加,而且super()必须是子类构造的第一条语句
System.out.println("打印子类的构造方法");
}
}
public class lyn1 {
public static void main(String[] args) {
Met met = new Met();
}
}
///输出结果//
打印父类的构造方法
打印子类的构造方法
Process finished with exit code 0
【注意】
- 若父类显式定义无参或默认的构造方法,在子类构造方法第一行默认有隐含的
super()
语句,即调用父类构造方法 - 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败
- 在子类构造方法中,
super()
调用父类构造时,必须是子类构造函数中的第一条语句 super()
只能在子类构造方法中出现一次,并且不能和this
同时出现,因为二者都必须是构造方法中的第一条语句,并且不能同时存在
6.继承关系上的执行顺序
代码理解
class Person{
public Person(){
System.out.println("Person构造方法执行");
}
{
System.out.println("Person实例代码块执行");
}
static {
System.out.println("Person静态代码块执行");
}
}
class Student extends Person{
public Student(){
System.out.println("Student构造方法执行");
}
{
System.out.println("Student实例代码块执行");
}
static {
System.out.println("Student静态代码块执行");
}
}
public class lynnn {
public static void main(String[] args) {
Person person = new Person();
System.out.println("==================");
Student student = new Student();
}
}
///输出结果
Person静态代码块执行
Person实例代码块执行
Person构造方法执行
==================
Student静态代码块执行
Person实例代码块执行
Person构造方法执行
Student实例代码块执行
Student构造方法执行
Process finished with exit code 0
通过分析执行结果,得出以下结论:
- 父类静态代码块优先于子类静态代码块执行,且是最早执行
- 父类实例代码块和父类构造方法紧接着执行
- 子类实例代码块和子类构造方法紧接着再执行
- 静态代码块只执行一次
7.Java中支持的继承方式总结
单继承
class A{
/
}
class B extends A{
/
}
多层继承
class A{//......}
class B extends A{//......}
class C extends B{//......}
不同类继承同一个类
class A{//......}
class B extends A{//......}
class C extends A{//......}
8.final
关键字
final
关键字可以来修饰变量、成员方法以及类,一个类不想被继承时,使用关键字final
用来修饰变量或字段,表示常量(不能被修改)
final int a = 10;
a = 20;//编译出错
修饰类:表示此类不能被继承
final class Animal{
///......
}
class Bird extends Animal{
///...
}//编译出错
9.继承与组合
和继承类似,组合也是一种表达类之间关系的方式,也是能够达到代码重用的效果。组合并没有涉及到特殊的语法,仅仅是将一个类的实例作为另一个类的字段
继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物
组合表示对象之间是has-a(a part of)的关系,比如:汽车和发动机,方向盘,轮胎等关系就应该是组合,因为汽车是由这些部件组成的
代码理解
//轮胎类
class Tire{
/
}
//发动机类
class Engine{
}
class Car{
private Tire tire;//可以复用轮胎中的属性和方法
private Engine engine;//可以复用发动机中的属性和方法
}
//奔驰是汽车
class Benz extends Car{
//将汽车中包含的轮胎,发动机等全部继承下来
}
组合和继承都可以实现代码复用,应该使用组合还是继承,需要根据应用场景来选择,一般建议:能用组合尽量使用组合。