首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >继承与多态

继承与多态

作者头像
景画
发布2025-12-19 13:50:42
发布2025-12-19 13:50:42
2220
举报

一.继承

1.解释

继承--顾名思义,承接上一辈的,继续扩大发展,因此,当你的子类没有拓展或改变父类的功能,是没必要继承的,关键字extends

需要继承的类被称为子类/派生类,被继承的类成为父类/基类/超类,继承就是对所有子类中共性的抽取,从而放入一个父类,需要时可以直接调用父类的成员变量和方法

代码语言:javascript
复制
class Student extends Person{
    public void study() {
        System.out.println(this.name + " 正在学习!!!");
    }
}
class Teacher extends Person{
    public void teach() {
        System.out.println(this.name + " 正在授课!!!");
    }
}
public class Person {
    public String name;
    public int age;
    public void speak() {
        System.out.println(this.name + " 正在说话");
    }
}
class Test {
    public static void main(String[] args) {
        Student student = new Student();
        student.name = "小玉";
        student.speak();

        Teacher teacher = new Teacher();
        teacher.name = "严老师";
        teacher.speak();
    }
}

2.super关键字及一些注意点

(1)

当父类与子类成员变量名一致时,this调用的是子类自己的成员变量就近原则

代码语言:javascript
复制
public class Person {
    public String name;
    public int age = 10;
    public void speak() {
        System.out.println(this.name + " 正在说话");
    }
}

class Teacher extends Person{
    public int age = 11;
    public void teach() {
        System.out.println(this.name + " 正在授课!!!");
    }
    public void fac() {
        System.out.println(this.age);
    }
}

(2)

如果在子类方法中非要调用父类的同名成员变量,则应引用super关键字

代码语言:javascript
复制
class Teacher extends Person{
    public int age = 11;
    public void teach() {
        System.out.println(this.name + " 正在授课!!!");
    }
    public void fac() {
        System.out.println("子类的年龄: " + this.age);
        System.out.println("子类的年龄: " + super.age);
    }
}

(3)

父类中没有构造方法时或者只有无参数的构造方法时,子类的构造方法会默认用super关键字调用父类无参数的构造方法

代码语言:javascript
复制
public class Person {
    public String name;
    public int age = 10;

    public Person() {
        System.out.println("父类的无参数构造方法!!!");
    }
    public void speak() {
        System.out.println(this.name + " 正在说话");
    }
}

class Teacher extends Person{
    public void teach() {
        System.out.println(this.name + " 正在授课!!!");
    }
}

class Test {
    public static void main(String[] args) {
        Student student = new Student();
        student.name = "小玉";

(4)

而当父类只有带参数的构造方法时,必须手动在子类构造方法第一行加上super对应的参数构造方法

代码语言:javascript
复制
public class Person {
    public String name;
    public int age = 10;

    public Person(String name, int age) {
        System.out.println("父类的含有参数构造方法!!!");
    }
    public void speak() {
        System.out.println(this.name + " 正在说话");
    }
}

class Teacher extends Person{
    public Teacher(String name, int age) {
        super(name,age);
    }
    public void teach() {
        System.out.println(this.name + " 正在授课!!!");
    }
}

3.不可继承的修饰符

(1)final

final意为"最终的",被final修饰的最终类不能被继承

1.代码:

代码语言:javascript
复制
final class Person{
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

2.图片

(2)private

private在类与对象中详细解释过,意为"私有的",只能在当前类使用,所以即使子类继承了父类所有的属性,但是私有属性仍没有办法使用

1.代码

代码语言:javascript
复制
class Person{
    public String name;
    public int age;
    
    private int tall;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student extends Person{

    public Student(String name, int age) {
        super(name,age);
        super.tall = 10;
        super.name = "小明";
    }

}

2.图片


二.super与this的比较

我么们知道,this代表当前类super代表父类,都能调用构造方法,和成员变量,那么有什么相同点和区别呢? 请看下表: this与super的比较 thissuperthis调用构造方法时,必须写在第一行super调用父类构造方法时,必须写在第一行不可以在普通成员方法中使用this调用构造方法不可以在子类普通成员方法中使用super调用父类构造方法this()可调用当前类不带参数的构造方法,得手动添加,不写的时候不会默认调用super()可调用父类不带参数构造方法,不写的时候子类当中默认调用当前类中构造方法可以不相互调用子类中必须调用父类的构造方法,并且当父类只有带参数的构造方法时,子类的所有构造方法必须手动添加使用super(x,y,...)来调用父类的构造方法,以此来给父类成员变量初始化this可调用当前类的成员方法与成员变量super可调用父类的成员方法与成员变量this+点号引用当前类成员变量与方法只能在非静态方法中使用super+点号引用父类的成员变量与方法只能在非静态方法中使用this不能调用当前类静态成员方法super不能调用父类静态成员方法this是当前对象的引用super可以理解为子类从父类继承下来的引用


三.子类与父类代码块执行顺序

在上一篇类与对象当中,我们学习了不同代码块的执行速度,即静态代码块执行速度 > 实例代码块执行速度 > 构造方法执行速度

那么,在父类与子类中都存在这三个时,执行顺序又是什么呢?

1.代码

代码语言:javascript
复制
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 32309
 * Date: 2025-06-06
 * Time: 22:42
 */
class Person{
    public String name;
    public int age;

    private int tall;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("父类构造方法!!!");
    }
    static {
        System.out.println("父类静态代码块!!!");
    }

    {
        System.out.println("父类实例代码块!!!");
    }
}

class Student extends Person{
    public Student(String name, int age) {
        super(name,age);
        super.name = "小明";
        System.out.println("子类构造方法!!!");
    }

    static {
        System.out.println("子类静态代码块!!!");
    }

    {
        System.out.println("子类实例代码块!!!");
    }
}
public class Test {
    public static void main(String[] args) {
        Student student = new Student("1",10);
    }
}

2.图片

3.分析

当实例化子类时,父类与子类的静态代码块在加载过程中先被执行,然后子类的构造方法调用super调用父类的构造方法,初始化父类成员变量,父类的实例代码块与构造方法先后执行,接着是子类的实例代码块与构造方法先后执行


四.多态

1.解释

多态是不同生物对同一种行为的不同表现形式,比如,有的人难受的时候会偷偷哭一场来释放自己的情绪,有的人则会选择吃甜品来缓解心情,更有的人会憋在心里慢慢消化... 正所谓对一本书的解读,一千个读者有一千个哈姆雷特,等等种种表明,万物多态构成了形形色色的世界,而Java当中也正是利用多态来实现丰富的动作

2.多态的条件

1. 必须实现继承 2. 通过父类的引用调用重写的方法 3. 子类必须要重写父类的方法 4.实现向上或向下转型

3.向上转型(动态绑定)

向上转型是动态绑定的一种,即将子类对象赋给父类,父类引用变量引用的是子类的对象,该父类引用变量调用不了子类特有的方法,向上转型有三种形式: 1.直接赋值 2.将父类类型作为参数 3.将父类类型作为返回值

(1)直接赋值

1.直接将子类对象赋值给父类类型的引用

2.代码及效果图:

代码语言:javascript
复制
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 32309
 * Date: 2025-06-06
 * Time: 22:42
 */
class Person{
    public String name;
    public int age;

    public void resolveSad() {

    }
}

class Girl1 extends Person {
    public Girl1(String name) {
        this.name = name;
    }
    public void resolveSad() {
        System.out.println(this.name + " 通过吃甜甜的奶糖来缓解悲伤");
    }
}
class Girl2 extends Person {
    public Girl2(String name) {
        this.name = name;
    }

    public void resolveSad() {
        System.out.println(this.name + " 攥紧拳头默默忍受慢慢消化悲伤");
    }
}
public class Test {
    public static void fib(Person person) {
        person.resolveSad();
    }
    public static void main(String[] args) {
        Person person1 = new Girl1("小樱");
        Person person2 = new Girl2("小洛");
        person1.resolveSad();
        person2.resolveSad();
    }
}
(2)将父类类型作为参数

1.在测试类中,将子类对象对位参数传递,将父类对象作为形式参数接受

2.代码及效果图:

代码语言:javascript
复制
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 32309
 * Date: 2025-06-06
 * Time: 22:42
 */
class Person{
    public String name;
    public int age;

    public void resolveSad() {

    }
}

class Girl1 extends Person {
    public Girl1(String name) {
        this.name = name;
    }
    public void resolveSad() {
        System.out.println(this.name + " 通过吃甜甜的奶糖来缓解悲伤");
    }
}
class Girl2 extends Person {
    public Girl2(String name) {
        this.name = name;
    }

    public void resolveSad() {
        System.out.println(this.name + " 攥紧拳头默默忍受慢慢消化悲伤");
    }
}
public class Test {
    public static void fib(Person person) {
        person.resolveSad();
    }
    public static void main(String[] args) {
        fib(new Girl1("小樱"));
        fib(new Girl2("小美"));
    }
}
(3)将父类类型作为返回值

1.在一个方法中,满足条件return一个子类给父类

2.代码及效果图:

代码语言:javascript
复制
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 32309
 * Date: 2025-06-06
 * Time: 22:42
 */
class Person{
    public String name;
    public int age;

    public void resolveSad() {

    }
}

class Girl1 extends Person {
    public Girl1(String name) {
        this.name = name;
    }
    public void resolveSad() {
        System.out.println(this.name + " 通过吃甜甜的奶糖来缓解悲伤");
    }
}
class Girl2 extends Person {
    public Girl2(String name) {
        this.name = name;
    }

    public void resolveSad() {
        System.out.println(this.name + " 攥紧拳头默默忍受慢慢消化悲伤");
    }
}
public class Test {
    public static Person fib(int num) {
            if (num == 1) {
                return new Girl1("小樱");
            } else {
                return new Girl2("小洛");
            }
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextInt()) {
            int num = scanner.nextInt();
            Person person = fib(num);
            person.resolveSad();
        }
    }
}

4.向下转型(动态绑定)

向下转型也是动态绑定的一种,指的是将父类对象强制转化为子类类型的引用,强制转换后

子类引用可调用该子类特有的方法

(1)代码及演示图:
代码语言:javascript
复制
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 32309
 * Date: 2025-06-06
 * Time: 22:42
 */
class Person{
    public String name;
    public int age;

    public void resolveSad() {

    }
}

class Girl1 extends Person {
    public Girl1(String name) {
        this.name = name;
    }
    public void resolveSad() {
        System.out.println(this.name + " 通过吃甜甜的奶糖来缓解悲伤");
    }
    public void eatCandy() {
        System.out.println(this.name + " 爱吃奶糖");
    }
}
class Girl2 extends Person {
    public Girl2(String name) {
        this.name = name;
    }

    public void walk() {
        System.out.println(this.name + " 正在散步");
    }
    public void resolveSad() {
        System.out.println(this.name + " 攥紧拳头默默忍受慢慢消化悲伤");
    }
}
public class Test {
    public static void main(String[] args) {
        Person person = new Girl1("小樱");
        Girl1 girl1 = (Girl1) person;
        girl1.resolveSad();
    }
}
(2)注意点:

向下转型的强制转换存在风险,不能同时转换两个不同子类对象,意为每个人都有自己独特的行为方式与属性

1.代码及效果图:

代码语言:javascript
复制
        Person person = new Girl1("小樱");
        Girl1 girl1 = (Girl1) person;
        girl1.resolveSad();

        Girl2 girl2 = (Girl2) person;
        girl2.walk();

2.ClassCastException

我们可以发现当同时强制转换两个对象会爆ClassCastException异常,这是类型转换异常,所以说类型转换存在风险

5.静态绑定

静态绑定是指在编译阶段发生的多态,典型的就是重载


五.重写

1.什么是重写?

当在父类中所实现的方法不满足于子类的需求时,那么这就需要重写,而重写则就是动态绑定发生的先决条件

2.需要重写的情况

1.当子类继承父类时,可以选择重写对应相同的方法 2.当子类重写抽象类,需要重写抽象类中所有的抽象方法 3.当一个类实现接口时,需要重写接口当中所有方法(抽象类与接口在下一篇博客会讲解)

3.重写的条件

1.重写的方法返回值必须相同 (子类继承父类时,返回值构成父子关系也可以) 2.重写的方法参数列表必须相同 如参数个数,参数类型,顺序都要一致

3.子类重写方法的权限必须大于等于父类的权限

4.一些特殊修饰符限定的方法不可重写

1.static

2.private

3.final

六.重写与重载的区别

重写

重载

重写方法的返回值类型,参数列表必须相同

重载方法的返回值类型不做要求,参数列表的参数个数,参数类型,顺序必须有一个不同

子类重写的方法权限必须大于等于父类方法

重载方法权限不做要求

被static,private,final修饰的方法不能重写

被任何修饰符修饰都能重载

abstract修饰的抽象方法必须被重写

没有必须被重载的方法

重写时发生动态绑定的基础

重载时发生静态绑定的基础

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.继承
    • 1.解释
    • 2.super关键字及一些注意点
    • 3.不可继承的修饰符
      • (1)final
      • (2)private
  • 二.super与this的比较
  • 三.子类与父类代码块执行顺序
  • 四.多态
    • 1.解释
    • 2.多态的条件
    • 3.向上转型(动态绑定)
      • (1)直接赋值
      • (2)将父类类型作为参数
      • (3)将父类类型作为返回值
    • 4.向下转型(动态绑定)
      • (1)代码及演示图:
      • (2)注意点:
    • 5.静态绑定
  • 五.重写
    • 1.什么是重写?
    • 2.需要重写的情况
    • 3.重写的条件
    • 4.一些特殊修饰符限定的方法不可重写
  • 六.重写与重载的区别
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档