【JavaSE系列】第八话 —— 继承和它的边角料们

2年前 (2022) 程序员胖胖胖虎阿
212 0 0

☕目录☕

 🍕思维导图

  🍟一、引出继承

  🍔二、继承的概念

  🧇三、继承的语法

  🌭四、父类成员访问

              🍿🍿4.1 子类中访问父类的成员变量

              🥞🥞4.2 子类访问父类的成员方法

  🍞五、super 关键字

              🥐🥐5.1 super.成员变量

              🧀🧀5.2 super.成员方法

              🍖🍖5.3 super.构造方法

  🥩六、继承方式

  🍱七、final关键字

  🍰八、继承与组合

 🍚写在最后


思维导图

【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们


一、引出继承

       Java中 使用类 对 现实世界中的实体进行描述;

       类经过实例化以后的产物 对象,则可以用来表示现实中的实体;

       但是,在现实生活中,某些实体与实体之间 具有相同的属性;

【JavaSE系列】第八话 —— 继承和它的边角料们      【JavaSE系列】第八话 —— 继承和它的边角料们

       比如说,上面的小猫和小狗,就具有一个共性:它们都是动物;

       如果用Java语言来描述小猫和小狗,那么就可以这样来设计:

//定义一个Cat类

class Cat {
    public String name;
    public  int age;
    public String sex;

    public void eat() {
        System.out.println(this.name+"吃饭");
    }
    public void mew(){
        System.out.println(this.name+"喵喵叫");
    }
}

//定义一个Dog类

class Dog {
    public String name;
    public  int age;
    public String sex;

    public void eat() {
        System.out.println(this.name+"吃饭");
    }
    public void bark(){
        System.out.println(this.name+"汪汪叫");
    }
}

       很明显,Cat类 和 Dog类 有许多一样的属性;

       那么,能不能将这些共性给抽取出来呢?

       在面向对象的过程中,提出了 继承 的概念;

       专门用来进行 共性抽取,实现 代码复用。

【JavaSE系列】第八话 —— 继承和它的边角料们


二、继承的概念

继承机制:

       是面向对象程序设计 是代码可以复用的最重要的手段;

       它允许程序员在保持原有类的特性 的基础上 进行扩展,增加新功能,这样产生新的类,称为 派生类;

       继承体现了 面向对象程序设计的层次结构,体现了由简单到复杂的认知过程;

       继承 主要解决的问题是:共性的抽取,实现代码复用。

       例如,上面的小猫和小狗的例子,我们可以把它们的共性抽取出来,然后把这些抽取出来的共性重新放到一个类当中:

 public String name;
    public  int age;
    public String sex;

    public void eat() {
        System.out.println(this.name+"吃饭");
    }

 此时,可以通过 关键字extends 构成一个继承关系:

【JavaSE系列】第八话 —— 继承和它的边角料们

 【JavaSE系列】第八话 —— 继承和它的边角料们

 【JavaSE系列】第八话 —— 继承和它的边角料们


三、继承的语法

//修饰符可以省略,也可以不用省略

[修饰符] class 子类 extends 父类 {
        //继承的成员变量或方法
}

【注意】

  1. 子类 会将父类中的成员变量或者成员方法 给继承到子类中;
  2. 子类继承父类之后,需要添加自己特有的成员,体现出与父类的不同,否则就没有必要继承了。 

       所以,对上面的例子 可以使用 继承 的方式来设计:


class Animal {
    public String name;
    public  int age;
    public String sex;

    public void eat() {
        System.out.println(this.name+"吃饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}

//Cat类
class Cat extends Animal{
    public void mew(){
        System.out.println(this.name+"喵喵叫");
    }
}

//Dog类
class Dog extends Animal{
    public void bark(){
        System.out.println(this.name+"汪汪叫");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.name = "喵喵";
        cat.eat();
        cat.mew();

        Dog dog = new Dog();
        dog.name = "汪汪";
        dog.sleep();
        dog.bark();
    }
}

【JavaSE系列】第八话 —— 继承和它的边角料们


四、父类成员访问

       在继承体系中,子类将父类中的方法和字段继承下来了;

       那在子类中能否直接访问 父类中继承下来的成员呢?

4.1 子类中访问父类的成员变量

1.子类和父类 不存在 同名成员变量


class Base{
    public int a = 1;
    public int b = 2;
}

class Derived extends Base {
    public int c = 3;
    public int d = 4;

    public void test(){
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.test();
    }
}

画图示例:

【JavaSE系列】第八话 —— 继承和它的边角料们

结果示例:

【JavaSE系列】第八话 —— 继承和它的边角料们

2.子类和父类 成员变量存在同名情况

class Base3{
    public int a = 1;
    public int b = 2;
}

class Derived3 extends Base3 {
    public int a = 3;
    public int d = 4;

    public void test(){
        System.out.println("a = "+a);
        System.out.println("b = "+b);
        System.out.println("d = "+d);
    }
}
public class TestDemo3 {
    public static void main(String[] args) {
        Derived3 derived3 = new Derived3();
        derived3.test();
    }
}

结果示例:

【JavaSE系列】第八话 —— 继承和它的边角料们

【结论】

       由图可以看出,父类和子类都有相同的成员变量a,而最终打印的结果是 子类成员变量a 的值;

       这就说明:如果 子类和父类的成员变量重名,那么 优先访问子类的成员变量;

       这也可以理解,继承嘛,当自己的意志和父类的意志有冲突的时候,优先考虑一下自己的意志嘛!

       那么,如果实在想访问父类的成员变量,很简单,使用关键字super;

       这个会在下面详细的介绍。

【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们

4.2 子类访问父类的成员方法

1.子类和父类 成员方法 不存在同名的情况

class Base3{
    
    public void method(){
        System.out.println("Base3:method");
    }
}

class Derived3 extends Base3 {

    public void method2(){
        System.out.println("Derived3:method2");
    }

    public void test(){
        method();
        method2();
}

public class TestDemo3 {
    public static void main(String[] args) {
        Derived3 derived3 = new Derived3();
        derived3.test();
    }

结果示例:

【JavaSE系列】第八话 —— 继承和它的边角料们

【总结】成员方法没有同名时,子类优先访问;如果子类没有所需的成员变量和成员方法,而父类也没有,那么程序将会报错。 

2. 子类和父类 成员方法 存在同名的情况


class Base3{

    public void method(){
        System.out.println("Base3:method");
    }
}

class Derived3 extends Base3 {

    public void method(int a){
        System.out.println("Derived3:method2 "+a);
    }

    public void test(){
        method();
        method(100);
    }
}
public class TestDemo3 {
    public static void main(String[] args) {
        Derived3 derived3 = new Derived3();
        derived3.test();
    }
}

结果示例:

【JavaSE系列】第八话 —— 继承和它的边角料们

【说明】

  1. 通过子类对象访问父类与子类中 不同名方法时,优先在子类中找,找到则访问;否则在父类中找,找到则访问;否则程序编译报错;
  2. 通过 子类 访问 父类与子类同名方法时,如果父类和子类 同名方法的参数列表不同(重载),根据调用方法 适传递的参数选择合适的方法访问,如果没有则报错;如果父类和子类 同名方法的原型一致(重写-后面会介绍的),这只能访问到子类的,父类的无法通过子类对象直接访问到。 

 【JavaSE系列】第八话 —— 继承和它的边角料们


五、super 关键字

       由于设计不好,或者因场景需要,子类和父类 可能会存在相同名称的成员;

       如果要在子类中访问父类同名成员时,那么应该怎么访问呢?

       直接访问是无法做到的;

       Java中提供了super关键字,该关键字的主要作用:在子类方法中访问父类的成员。

5.1 super.成员变量

【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们

5.2 super.成员方法

【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们

5.3 super.构造方法

 下面请看一段代码:

package Demo1;

class Animal {
    public String name;
    public int age;

    public void eat() {
        System.out.println(this.name + "正在吃饭");
    }
}

class Cat extends Animal {
    public String hair;
    public void mew() {
        System.out.println(this.name + "正在叫");
    }
}
public class Test {
    public static void main(String[] args) {
        Cat cat1 = new Cat();
        cat1.name = "咪咪";
        cat1.mew();
        cat1.eat();
    }
}

代码运行结果: 【JavaSE系列】第八话 —— 继承和它的边角料们

       当我们把 name和age的访问权限修改成private以后,子类就不去能访问了(注意是不能访问了,而不是没有被继承):

【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们

       那么,此时可以去提供 getter和setter方法,再对代码进行修修改改:

package Demo1;

class Animal {
//    public String name;
    private String name;
//    public int age;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void eat() {
        System.out.println(this.name + "正在吃饭");
    }
}

class Cat extends Animal {
    public String hair;
    public void mew() {
        //System.out.println(this.name + "正在叫");
        //System.out.println(this.getAge());
    }
}

public class Test {
    public static void main(String[] args) {
        Cat cat1 = new Cat();
        //cat1.name = "咪咪";
        cat1.setName("咪咪");
        cat1.mew();
        cat1.eat();
    }
}

       于是,这些成员就被赋初值了:

【JavaSE系列】第八话 —— 继承和它的边角料们

       当然,我们曾经介绍过,赋初值的方法 除了setter和getter方法以外,还可以使用构造方法:

可是,当我们就直接加上构造方法的时候,代码就会报错啦:

【JavaSE系列】第八话 —— 继承和它的边角料们

       这是为什么呢?

       ——原来,当构造子类的时候,一定要先帮助父类构造,再帮助子类构造。

       所以说,还需要创建子类的构造方法,同时,要想先帮助父类构造,那可以用super关键字来进行调用:

【JavaSE系列】第八话 —— 继承和它的边角料们

 【注意】

  1. 在调用构造方法的时候,和this一样,super必须放在第一行;
  2. 父子父子,先有父再有子,在子类当中可以通过super关键字来调用父类的构造方法;
  3. super不能在 静态方法中使用:【JavaSE系列】第八话 —— 继承和它的边角料们

当然,我们也可以这样来写代码:

package Demo1;

class Animal {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void eat() {
        System.out.println(this.name + "正在吃饭");
    }

    public Animal() {

    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Cat extends Animal {
    public String hair;
    public void mew() {
        System.out.println(this.getName() + "正在叫");
    }
    public Cat() {
        super();
    }

    public Cat(String name,int age,String hair){
        super(name, age);
        this.hair = hair;
    }

}

public class Test {
    public static void main(String[] args) {
        Cat cat1 = new Cat("咪咪",8,"black");
        cat1.mew();
        cat1.eat();
    }
}

 代码编译结果:【JavaSE系列】第八话 —— 继承和它的边角料们

【JavaSE系列】第八话 —— 继承和它的边角料们


六、继承方式

       在现实生活中,事物之间的关系是非常复杂、灵活多样的,比如:

【JavaSE系列】第八话 —— 继承和它的边角料们

       但是,在Java中,只存在以下几种继承方式:

【JavaSE系列】第八话 —— 继承和它的边角料们

 

【注意】Java是不支持多继承的,即:不支持 一个子类有多个父类。

       从上面来看,父类一层一层的被继承下去;

       但是,如果不想被继承了,那到底该怎么做呢?

       很简单,这就需要又引出了final关键字......

【JavaSE系列】第八话 —— 继承和它的边角料们


七、final关键字

当一个类被final关键字修饰以后,这个类就不能继承了:

【JavaSE系列】第八话 —— 继承和它的边角料们

【注意】

       被final修饰的类,我们把它叫做密封类(说明 当前的类不能被继承);

       以前也介绍过,被final修饰的成员不能被修改(变成了常量);

       当然,final还可以修饰方法...... 

 【JavaSE系列】第八话 —— 继承和它的边角料们


八、继承与组合

       和继承类似,组合也是一种表达类之间关系的方式,也是可以达到代码复用的效果;

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

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

       组合 表示对象之间是 has-a 的关系,比如:汽车;

【JavaSE系列】第八话 —— 继承和它的边角料们

       汽车和其轮胎、发动机、方向盘、车载系统 等的关系就应该是组合,因为汽车就是由这些零部件组成的。

// 轮胎类
class Tire{
    // ...
}

// 发动机类
class Engine{
    // ...
}

// 车载系统类
class VehicleSystem{
    // ...
}

class Car{
    private Tire tire; // 可以复用轮胎中的属性和方法
    private Engine engine; // 可以复用发动机中的属性和方法
    private VehicleSystem vs; // 可以复用车载系统中的属性和方法 // ...
}

// 奔驰是汽车
class Benz extend Car{
    // 将汽车中包含的:轮胎、发送机、车载系统全部继承下来 
}

       组合和继承都可以实现代码复用;

       应该使用继承还是组合,需要根据应用场景来选择;

       一般建议:能用组合尽量用组合。 

       如果大家对这个有很大兴趣的话,可以点击这个传送门:

深入理解Java中的组合和继承-传送门时刻准备中......

【JavaSE系列】第八话 —— 继承和它的边角料们

写在最后

       那么,现在 Java的第二个特性——继承 也到此告一段落了;

       由于博主水平有限,可能会出现一些表达不清楚,或者出现一些其他的情况,

       欢迎各位铁汁们指出来,让博主一起改正,

       一起努力,共同进步;

       好了,如果这篇博客对铁汁们有帮助的话,可以送一个免费的 赞 嘛;

       当然,顺手点个关注是再好不过的了......

【JavaSE系列】第八话 —— 继承和它的边角料们

相关文章

暂无评论

暂无评论...