Java基础知识——继承的基础知识(超级详细)

1、继承的基础知识:

1.1、为什么要继承?

       Java中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是现实世界错综复杂,事物之间可能会存在一些关联,那在设计程序是就需要考虑。就比如说猫和狗,他们之间可能存在某种相同的特点,就如毛色、相同时间点吃饭等。而继承就是将这个相同特点提取出来从而实现代码的复用。

1.2、继承的基础概念:

       继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。

用代码来举例子的话:

public class dog {
    String name;
    int age;
    String color;
    public void bark() {
        System.out.println(this.name + "正在汪汪叫");
    }
}
public class bird {
    String name;
    int age;
    String color;

    public void bark() {
        System.out.println(this.name + "正在蹄蹄叫");
    }
}
public class text {
    public static void main(String[] args) {
         bird  bird = new bird();
         dog  dog = new dog();
         bird.name = "小鸟";
         bird.age = 10;
         bird.color = "红的";
         dog.name = "小狗";
         dog.age = 10;
         dog.color = "红的";
         bird.bark();
         dog.bark();
    }
}

       由这段代码可以看出不使用继承的时候,如果需要用相同的代码则需要不断的重复去定义,这样显得特别的麻烦。

1.3、继承的语法:

继承就是一个is-a的关系。怎么来具体的去理解这句话呢?

用一段代码来举例子:

public class Annimal{
    String name;
    int age;
    String color;
}

public class dog extends Annimal{
    public void bark()
    {
        System.out.println(super.name + "正在往往叫");
    }
}
public class text {
    public static void main(String[] args) {
         dog  dog = new dog();
         dog.name = "小狗";
         dog.age = 10;
         dog.color = "红的";
         dog.bark();
    }
}

       这段代码中出现了super、extends关键字这个我们放到后面具体讲解,这里就主要说一下is - a关系。这里我们封装了一条狗和动物的对象,哪对于is - a是不是就是dog is a annimal呢?这样是不是更加的好理解一些呢?所以我在这里为了更加形象的表示出dog与animal的关系就将其表示为is - a的关系。

       然后我们又看,通过这样封装的方式将会更加好的去理解代码,不用再写很多重复的代码,极大的提高了代码的可读性,让代码更加精炼。

       对于继承的语法结构public class 名字1 extends 名字2{};在这个语法结构中,我们将名字1称为子类,将名字2称为父类。当在继承关系当中,父类和子类出现了同样的成员变量的时候,如果不做指令的话,默认返问为子类自己的。当子类当中没有该成员变量时,才去父类查找。(子类优先访问)方法的执行规则也是一样。

注意事项: 1. 子类会将父类中的成员变量或者成员方法继承到子类中了

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

1.4、父类的成员访问:

       在子类方法中或者通过子类对象访问成员时:如果访问的成员变量子类中有,优先访问自己的成员变量。如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。如果访问的成员变量与父类中成员变量同名,则优先访问自己的。成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。

用一段代码举例子:

public class Annimal{
    String name;
    int age;
    String color;
    public void bark()
    {
        System.out.println(this.name + "正在汪汪叫");
        System.out.println("父类被调用了");
    }
}
public class dog extends Annimal{
    String name;
    int age;
    String color;
    public void bark()
    {
        System.out.println(this.name + "正在汪汪叫");
        System.out.println("子类被调用了");
    }
}
public class text {
    public static void main(String[] args) {
         dog  dog = new dog();
         dog.name = "小狗";
         dog.age = 10;
         dog.color = "红的";
         dog.bark();
    }
}

从这里可以看出在子类和父类同名的时候会优先调用父类。

2、super关键字

       由于设计不好,或者因场景需要,子类和父类中可能会存在相同名称的成员,如果要在子类方法中访问父类同名成员时,该如何操作?直接访问是无法做到的,Java提供了super关键字,该关键字主要作用:在子类方法中访问父类的成员。

       super关键字的许多用法都与this关键字的用法相似。super.名字表示的是父类的成员变量或者是父类的成员方法。

如代码所示:

public class Annimal{
    String name;
    int age ;
    String color;
    public void bark()
    {
        System.out.println(this.name + "正在汪汪叫");
        System.out.println("父类被调用了");
    }
}
public class dog extends Annimal{
    String name;
    int age;
    String color;
    public void bark()
    {
    //    System.out.println(this.name + "正在汪汪叫");
        System.out.println("子类被调用了");
    }
    public void print()
    {
        super.age = 10;
        super.name = "小狗";
        super.color = "yellow";
        System.out.println("姓名: " + this.name + " 年龄: " + this.age + " 颜色: " + this.color);
    }
}
public class text {
    public static void main(String[] args) {
         dog  dog = new dog();
         dog.name = "小狗";
         dog.age = 10;
         dog.color = "红的";
         dog.print();
    }
}

       其中可以看出super是调用父类的成员方法或者成员变量。当然super只是一个关键字,提高了代码的可读性而已。如果我们非要访问与子类同名的在父类的方法我们就用super关键字。super.age等来访问父类的成员变量,super.func来访问父类的成员方法,其中会发现super与this非常像。this()来专门调用构造方法,而super也存在着super()来专门调用构造方法。这个等会在将构造方法时会详细解释。

注意事项:1、super不能在静态方法内使用,只能在非静态方法内使用。

2. 在子类方法中,访问父类的成员变量和方法。其只能指代当前类的父类不能指代父类的父类甚至更“远”

当然在子类方法中,如果想要明确访问父类中成员时,借助super关键字即可。

3、子类的构造方法:

       父子父子,先有父再有子,即:子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

例如代码:

public class Annimal{
    String name;
    int age ;
    String color;
    public void bark()
    {
        System.out.println(this.name + "正在汪汪叫");
        System.out.println("父类被调用了");
    }
    public Annimal()
    {
        System.out.println("Annimal()");
    }
}
public class dog extends Annimal {
    String name;
    int age;
    String color;

    public void bark() {
        System.out.println("子类被调用了");
    }
    public dog()
    {
       // super();   // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
       // 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
       // 并且只能出现一次
        System.out.println("dog()");
    }
public class text {
    public static void main(String[] args) {
         dog  dog = new dog();
         dog.name = "小狗";
         dog.age = 10;
         dog.color = "红的";
    }
}

       当用户没有编写super()时,编译器会自动添加但不显示出来,但当用户编写后,编译器变不再添加。

注意: 1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法。

2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。

3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。

4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现。

4、super关键字与this关键字的区别:

4.1 相同点:

(一) 都是Java中的关键字。

(二) 只能在类的非静态方法中使用,用来访问非静态成员方法和字段。

(三)在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在。

4.2 不同点:

(一)this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成 员的引用。

(二)在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性。

(三)在构造方法中:this(...)用于调用本类构造方法,super(...)用于调用父类构造方法,两种调用不能同时在构造 方法中出现 。

(四)构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有 。

而this关键字与super关键字所指向的范围也正如图所示:

5、再谈初始化:

这里我们先复习一下前面所学习的代码块的内容:

(一)父类静态代码块优先于子类静态代码块执行,且是最早执行。

(二)父类实例代码块和父类构造方法紧接着执行。

(三)子类的实例代码块和子类构造方法紧接着再执行。

(四)第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行。

6、 protected关键字:

       谈到protected关键字就不得不提到另外3个关键字:public、private、default。哪他们之间的关系是什么呢?

NO范围privatedefaultprotectedpublic
1同一个包中的同一类
2同一个包中的不同类
3不同包中的子类
4不同包中的非子类

       不同包中的子类当中可以通过super访问或者通过子类对象来访问。不可以通过父类对象访问。在不同的包中如若需要调用它,则需要用import关键字来进行调用。例如import java.util....(包名字)。

7、final关键字

final关键字的主要作用:

(一)修饰变量之后,变成了常量。

(二)修饰类,表示当前类不能被继承。

(三)修饰方法,表示方法不能被重写。

final public class Annimal{
    String name;
    int age ;
    String color;
    public void bark()
    {
        System.out.println(this.name + "正在汪汪叫");
        System.out.println("父类被调用了");
    }
    public Annimal()
    {
        System.out.println("Annimal()");
    }
}
final public class dog extends Annimal{

}//不能该类被继承
public class text {
    public static void main(String[] args) {

        final int a = 5;  //使用了final就类似于c++中的const
    }
}

8、继承方式:

       继承方式有单继承、多层继承、不同类继承同一类、多继承,但在java中不支持多继承这种方式。

9、继承与组合:

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。

组合并没有涉及到特殊的语法 (诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段。

继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物 组合表示对象之间是has-a的关系,比如:汽车。

// 轮胎类
class Tire{
    // ...
}
 
// 发动机类
class Engine{
    // ...
}
 
// 车载系统类
class VehicleSystem{
    // ...
}

class Car{
    private Tire tire;          // 可以复用轮胎中的属性和方法
    private Engine engine;      // 可以复用发动机中的属性和方法
    private VehicleSystem vs;   // 可以复用车载系统中的属性和方法
    
    // ...
}
 
// 奔驰是汽车
class Benz extend Car{
    // 将汽车中包含的:轮胎、发送机、车载系统全部继承下来
}

组合和继承都可以实现代码复用,应该使用继承还是组合,需要根据应用场景来选择,一般建议:能用组合尽量用组合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值