当前位置: 首页 > article >正文

【Java SE 】继承 与 多态 详解

 🔥博客主页🔥:【 坊钰_CSDN博客 】

欢迎各位点赞👍评论✍收藏⭐

目录

1. 继承

1.1 继承的原因

1.2 继承的概念

1.3 继承的语法

2. 子类访问父类

2.1 子类访问父类成员变量

2.1.1 子类与父类不存在同名成员变量

2.1.2 子类与父类存在同名成员变量

2.2   子类访问父类成员方法

2.2.1 子类和父类成员方法同名

3. super 关键字

3.1 子类的构造方法

3.2 super 和 this 的异同

3.3 代码的执行顺序

 4. 继承方式

4.1 final 关键字

4.1.1 final 修饰成员

4.1.2 final 修饰方法

4.1.3 final 修饰类

5. 多态

5.1 多态的概念

5.2 实现多态条件

5.3 向上转型和向下转型

5.3.1 向上转型

5.3.1.1  直接赋值

5.3.1.1  方法传参

5.3.1.1  方法返回

5.3.2 向下转型

5.4. 方法的重写

5.5 实现多态性

5.6 多态的优缺点

6. 小结


1. 继承

1.1 继承的原因

Java 是一种纯面向对象的编程语言,当我们用类来描述多个实体时,那么可能有几个类之间会存在一些关系,那么在设计时就需要考虑一下

比如:学生工人

我们用 Java 语言来描述

//学生类

public class Student {
    
    String name;   //姓名
    int age;       //年龄
    float weight;  //体重

    public void sleep() {
        System.out.println("睡觉......");
    }

    //学生的工作
    public void study() {                 
        System.out.println("在教室学习......");
    }

}

//工人类

public class Worker {

    String name;   //姓名
    int age;       //年龄
    float weight;  //体重

    public void sleep() {
        System.out.println("睡觉......");
    }

    //工人的工作
    public void work() {
        System.out.println("在工地工作......");
    }

}

虽然,学生和工人的类定义出来了,但是他们类中有很多重复代码 

我们想一想,如果把这些相同的共性提取出来,就可以实现代码的复用 

1.2 继承的概念

一句话:继承是使代码具有复用性的手段,允许了在原有类的基础上进行扩展,添加新内容

继承好处:提取了共性,实现代码复用,那么我们可以在建一个类用来存放这些共性,就不必重复的写代码,只是需要时调用即可

1.3 继承的语法

Java 中用关键字 extends 来表示继承关系

修饰符 class 子类 extends 父类 {
    ......
}

上述代码进行优化

//父类

public class People {

    String name;   //姓名
    int age;       //年龄
    float weight;  //体重

    public void sleep() {
        System.out.println("睡觉......");
    }

}

//子类---学生

public class Student extends People {  //继承

    public void study() {
        System.out.println("在教室学习......");
    }

}

//子类---工人

public class Worker extends People  {  //继承

    public void work() {
        System.out.println("在工地工作......");
    }

}
  •  子类会将父类中成员变量和方法都继承到子类中
  • 继承后,子类必须有新的变量或方法,否则就没有继承的必要了

2. 子类访问父类

在继承好了之后,子类就可以访问父类各种成员了

2.1 子类访问父类成员变量

2.1.1 子类与父类不存在同名成员变量

//父类

public class TestClassFather {
    
    int a;    //父类变量
    int b;
    
}

//子类

public class Son extends TestClassFather {
    
    int c;   //子类变量
    
    public void Fun() {    //直接使用即可
        a = 100;
        b = 200;
        c = 300;
    }
    
}

2.1.2 子类与父类存在同名成员变量

//父类

public class TestClassFather {
  
    //父类变量  
    int a;   
    int b;
    
}

//子类

public class Son extends TestClassFather {
    
    //子类变量

    int b;    //与子类相同
    int c;   
    
    public void Fun() {    //直接使用即可

        a = 100;
        b = 200;   //优先访问自己的变量
        c = 300;

    }
    
}

注意事项

  • 子类与父类存在同名成员变量时,优先访问自己的
  • 访问的成员,子类没有,那就访问父类的,如果都没有,则报错

2.2   子类访问父类成员方法

//父类

public class TestClassFather {

    int a;
    int b;

    public void Fun() {
        System.out.println("哈哈");
    }

}

//子类

public class Son extends TestClassFather {

    int c;
    
    public void method() {
        Fun();   //直接访问即可
    }


}

2.2.1 子类和父类成员方法同名

//父类

public class TestClassFather {

    int a;
    int b;

    public void Fun() {
        System.out.println("哈哈");
    }

    public void Fun(int a) {
        System.out.println("哈哈");
    }

}

//子类

class Son extends TestClassFather {

    int c;

    public void Fun() {
        System.out.println("呵呵");
    }

    public void method() {
        Fun();     //访问子类
        Fun(10); //访问父类
    }
    
}
  • 同名时,优先在子类中寻找,子类没有,在去父类中寻找
  • 也可根据方法的参数进行寻找,如果都没有,则报错

3. super 关键字

在编程中,可能会遇到,当子类和父类的成员变量或方法同名时,又想访问父类成员,该怎么做呢?这时,Java 提供了 super 关键字,用来在子类中访问父类的成员

//父类

public class TestClassFather {

    int a =  10;

    public void Fun() {
        System.out.println("父类:Fun()");
    }

}

//子类

class Son extends TestClassFather {

    int a = 20;

    public void Fun() {
        System.out.println("子类:Fun()");
    }

    public void pirnt() {
        System.out.println(a);           //子类
        System.out.println(super.a);     //父类
        Fun();                           //子类
        super.Fun();                     //父类
    }

}

运行结果:

这就是 super 的用法

3.1 子类的构造方法

俗话说,父子父子,先有父,在有子

在执行子类构造方法时,需要先执行父类的构造方法,然后在执行子类的构造方法

public class A {
    public A() {
        System.out.println("父类构造方法......");
    }
}

class B extends A {
    public B() {
        System.out.println("子类构造方法......");
    }

    public static void main(String[] args) {
        B b = new B();           
    }
}

运行结果:

  • 若父类中无构造方法,编译器会自动添加一个无参构造方法,若果有,则不加
  • 若父类定义无参或默认的构造方法,在子类构造方法中第一行,编译器会默认调用 super() 
  • 若父类定义有参数的构造方法,则要为子类也要显示定义构造方法,否则失败
  • super 调用父类时,必须在第一行,否则报错
  • super 只能在子类中出现一次,不能和 this 同时出现

3.2 super 和 this 的异同

 学了 super 和 this 关键字,那他们有什么区别呢?

相同点

  • 都是 Java 的关键字
  • 都不能在静态方法中使用
  • 在构造方法中使用时,都只能在第一行,且不能同时存在

不同点

  • this 用于本类中的方法和属性的引用,而 super 用于访问父类继承下来的方法和属性、
  • 调用构造方法时,this 用于调用本类的构造方法,super 用于调用父类的构造方法
  • 构造方法中一定会存在 super 的调用,不写编译器自动调用,this 不写就没有

 3.3 代码的执行顺序

先看下面代码,思考一下运行结果是什么?为什么?

public class A {

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

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

    public A() {
        System.out.println("父类构造方法......");
    }
}

class B extends A {

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

    {
        System.out.println("子类实例代码块......");
    }
    
    public B() {
        System.out.println("子类构造方法......");
    }

    public static void main(String[] args) {
        B b = new B();
        System.out.println("===========");
        B b1 = new B();

    }
}

运行结果

通过结果分析,总结顺序规律:

  • 父类的静态代码块优先于子类的静态代码块
  • 父类的实例代码块和构造代码块接着执行
  • 子类的实例代码块和构造代码块接着执行
  • 第二次在实例化时,父类和子类的静态代码块不在运行,他们只执行一次

 4. 继承方式

Java 中的类只能单继承,不支持多继承,如果想从语法上限制继承,我们可以用 final 关键字来修饰

4.1 final 关键字

final 可以修饰 成员、类、方法

4.1.1 final 修饰成员

被 final 修饰的成员,成员的值不可以被修改

final int a = 10; //不可以被修改

4.1.2 final 修饰方法

被 final 修饰的方法,方法不可以被重写

public final void study() {  //不可以被重写

    System.out.println("在教室学习......");
}

4.1.3 final 修饰类

被 final 修饰的类,类不可以继承

public  final class A {
   ......
}

5. 多态

5.1 多态的概念

多态就是多种形态,对于某个行为,不同对象去完成会产生不同的状态

一句话:同一种方法,不同对象对应的结果不同

5.2 实现多态条件

  • 必须在继承条件下进行
  • 存在子类向父类的向上转型
  • 子类必须要对父类的方法进行重写
  • 通过父类调用重写的方法

5.3 向上转型和向下转型

5.3.1 向上转型

子类对象当作父类对象使用

语法格式

父类类型 对象名 = new 子类类型( );

People people = new Student();   //子类对象当作父类对象 

向上转型时通常有三种情况

5.3.1.1  直接赋值
People people = new Student();   //直接赋值
5.3.1.1  方法传参
public class Test {

    public static void Fun(People people) {  //发生了向上转型
        people.work();
    }

    public static void main(String[] args) {
        Student student = new Student();

        Fun(student );   //方法传参时出现了向上转型
    }
}
5.3.1.1  方法返回
//方法返回时发生了向上转型

public static People Fun(Student student) {  
    return student;
}

5.3.2 向下转型

向下转型和向上转型相反,父类对象强转为子类对象使用

语法格式

子类类型 对象名 =(子类类型) new 父类类型( );

//强制类型转换

Student student = (Student) new people();

该转型用的较少,且不安全

5.4. 方法的重写

重写:也称为覆盖,是子类对于父类的方法进行重写编写,返回值、形参都不能改变

//父类

public class People {
    String name;
    int age;
    float weight;

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

    public void work() {
        System.out.println(name+" 在工作......");
    }

}

//子类

public class Worker extends People  {

    public Worker(String name, int age) {
        super(name, age);
    }

    //对父类中的方法进行了重写
    public void work() {  
        System.out.println(name+" 在工地工作......");
    }

}

重写的规则

  • 子类重写父类方法时,返回值和形参必须都一致
  • 重写的方法的返回值可以不同,但前提必须有父子关系
  • 子类方法的访问限制符的范围必须大于等于父类的访问限制符
  • 父类方法被 static 或 private 修饰,则不能重写

前面学习了重载,那他们俩区别是?

5.5 实现多态性

//父类

public class People {
    String name;
    int age;
    float weight;

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

    public void work() {
        System.out.println(name+" 在工作......");
    }

}

//子类---学生

public class Student extends People  {

    public Student(String name, int age) {
        super(name, age);
    }

    //对父类重写
    public void work() {
        System.out.println(name+" 在教室学习......");
    }

}

//子类---工人

public class Worker extends People  {

    public Worker(String name, int age) {
        super(name, age);
    }

    //对父类重写
    public void work() {
        System.out.println(name+" 在工地工作......");
    }

}

//多态性的实现

public class Test {

    public static void Fun(People people) {    //传参进行向上转型
        people.work();
    }

    public static void main(String[] args) {
        People people1 = new Student("张三",20);
        People people2 = new Worker("工人",30);

        Fun(people1);
        Fun(people2);
    }
}

这就是多态性,对于同一个方法 Fun ( ) ,当我们传入不同对象时,它处理的结果不同,多态性级体现出来了

5.6 多态的优缺点

优点

  • 降低了代码的圈复杂度,避免了大量的 if-else
  • 使代码的可扩展性增强

缺点

  • 代码运行效率降低 

6. 小结

以上就是对继承和多态的了解,具体还需宝子们去实践,如果觉得该博客对你有用的话,希望一键三连,点个关注不迷路,谢谢支持 ! 


http://www.kler.cn/news/357996.html

相关文章:

  • leetcode389:赎金信
  • 效果不错的论文介绍:Im2Flow2Act:-跨领域机器人操控技术
  • 101 - Lecture 9
  • Python 多线程学习与使用
  • 《计算机视觉》—— 基于 dlib 库的方法将两张人脸图片进行换脸
  • React Agent 自定义实现
  • 记录 Latex 中 align 环境下, 两个对齐
  • 在Ubuntu上安装Docker以及使用
  • Linux服务器前后端项目部署vue+springboot—搭建服务器上的运行环境(JDK、Redis、MySQL、Nginx)
  • 十四、行为型(观察者模式)
  • Netty无锁化设计之对象池实现
  • C语言(函数)—函数栈帧的创建和销毁
  • 机器学习与神经网络:诺贝尔物理学奖的新纪元
  • tensorRT_Pro自学记录
  • Java_EE 网络编程(TCP与UDP通信)
  • 类与对象(三)
  • 2024-10-16 学习人工智能的Day8
  • 【设计模式】深入理解Python中的适配器模式(Adapter Pattern)
  • Spring Boot中使用FlexyPool动态监控管理数据库连接池
  • 自己用react开发了一张Es6的学习页面(持续更新系列)