类和对象进阶 - 继承

1. 继承

1.1 什么是继承

什么是继承?为什么需要继承 ?

观察下面两个类定义

通过观察发现,这Dog cat这两个类具有一些共性 

比如 有两个相同的成员变量name age 和一个成员方法eat

那么 是否可以将这些共性抽取出来 放到另一个类中?然后 让Dog和Cat类与另一个类共用成员变量和方法 ? 结论是可以 观察下面这个例子

class Animal {
    public String name;
    public int age;

    public void eat() {
        System.out.println(this.name + "在吃");
    }
}
class Dog extends Animal {

    String color;

    public void bark() {
        System.out.println(this.name + "在狗叫");
    }
}
class Cat extends Animal {

    public void miao() {
        System.out.println(this.name + "在喵叫");
    } 
}
public class TestDemo {
    public static void main(String[] args) {
        Dog d1 = new Dog();
        d1.name = "abc";
        d1.eat();
    }
}

再来总结 上面这个例子中出现的重点

1. 如何表示两个类的继承关系 ?

        使用extends关键字:

        class 子类名 extends 父类名

2. 子类继承父类什么 ?

        子类继承父类的成员变量和方法

        注意:子类无法继承父类的静态成员变量

3. 子类实例化出的对象是如何存储的 ?

回到最初的问题  什么是继承?为什么需要继承 ? 

继承 从实现上回答 使用extends关键字定义类之间的继承关系,子类继承父类的成员变量和方法,从而 实现对代码的复用

1.2 访问父类成员

接下来需要讨论的问题是 子类与父类存在同名的变量的情况下 this引用访问的是 子类自己的成员变量还是访问继承自父类的成员 ?

首先回顾 子类与父类不存在同名的变量,如图

this.a 访问子类自己的成员变量a

this.b 访问父类继承的成员变量b

this.c 访问父类继承的成员变量c

如果 子类与父类存在同名变量 会是什么情况

this.a 访问子类自己的成员变量a

this.b 访问子类自己的成员变量b

this.c 访问子类自己的成员变量c

根据上面两个例子 可得出结论: 当子类与父类存在同名变量时,优先访问子类的成员变量,如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。

1.3 super关键字

子类中访问父类成员变量

如何指定访问父类的成员变量 ?

可以使用super关键字 对父类成员变量指定访问 如图

为什么super关键字能指定访问父类的成员 ?

子类中访问父类成员方法

与访问父类成员变量相同,当子类与父类存在同名成员函数时,优先访问子类的成员函数,如果访问的成员方法子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。

如果子类与父类存在同名成员函数 需要用super指定访问父类成员方法

子类与父类存在同名成员函数时,优先访问子类的成员函数

如果访问的成员方法子类中无,则访问父类继承下来的

子类与父类存在同名成员函数时 需要用super指定访问父类成员方法

需要注意的是 super关键字不能出现在静态方法中

1.4 子类调用构造方法

问题引入

代码为什么会报错 ? 

子类继承父类后 在子类初始化自己成员之前,必须先使用super() 调用父类的构造方法 对父类的成员进行初始化,如下例

class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "在吃");
    }
}

class Dog extends Animal {

    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 d1 = new Dog("大黄",2,"黄色");
        d1.eat();
    }
}

接下来的问题是 为什么不写构造方法 程序没有报错 ?

已知 如果自己没有写构造方法 编译器会自己生成一个无参的默认构造方法 (默认构造中不会有内容)  现在Dog子类继承于父类Animal  如果默认构造中没有内容 不会对父类成员进行初始化 为什么不会报错 ?

实际上 编译器也会在父类中生成默认构造 然后在子类成员初始化前 调用父类构造首先对父类成员进行初始化

1.5 super关键字总结与注意事项

总结:

1. super用来在子类中 指定访问父类成员变量和方法 因为this引用优先访问子类自己的成员

2. super加点号 访问父类成员变量和方法

3. super(..) 访问父类的构造方法

注意事项:

1. super只能在非静态方法中使用

2. 在子类构造方法中调用super(...)初始化父类成员,必须放在第一行

1.6 super与this 相同点和不同点

相同点:

1. 都是Java中的关键字

2. 只能在类的非静态方法中使用

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

不同点:

1. this是当前对象的引用  —— super 是从父类继承下的部分成员变量的引用 如图

2.  在非静态成员方法中,this优先访问子类自己的成员变量和属性 如果找不到子类成员 再去访问父类成员 —— super 指定访问父类的成员

3. 在子类构造方法中,this(...)用于调用子类自己的构造方法,super(...)用于调用父类构造方法,两种调用不能同时在构造方法中出现 因为this() super()都需要占用第一行

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

1.7 protected 关键字

protected是一个访问修饰限定符 可以让不同包的子类可以访问父类成员

但是 不能在类外使用子类对象的引用去访问父类protected修饰成员 

必须在子类中 使用this/super 进行访问

package a;

public class Test {
    protected int a = 1;
}
import a.Test;

// 2. 复习protected 关键字
class Test2 extends Test {
    // Test2子类继承了 Test父类中的成员变量a
    // Test父类中的成员变量a由protected关键字修饰 表示不同包的子类可以访问父类成员
    public void print() {
        System.out.println(this.a);
        System.out.println(super.a);
    }
}
public class Main {

    public static void main(String[] args) {
        Test2 test2 = new Test2();
        System.out.println(test2.a);
        //test2.print();

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值