• 带你深入理解面向对象三大特性 - 继承,多态


    目录

    前言:

    继承

    示例

    子类中访问父类成员变量

    变量名字不同

    变量名字相同

    子类中访问父类成员方法

    方法名字不同

    方法名字相同

    super关键字

    子类构造方法

    super和this

    再谈初始化

    继承方式:

    单继承

    多继承

    不同类继承同一类

     final关键字

    final修饰成员变量

    final修饰成员方法

    final修饰类

    继承与组合

    多态

    多态的条件

    重写

    方法重写的规则

    示例

    静态绑定

    动态绑定

    向上转型

    向下转型

     小结:


    前言:

       为了实现代码的复用,让代码看起来不在冗余,将两个类相同的部分提取出来,用子类去继承父类就可以达到这样的效果。

        多态字面意思就是多种状态,这是一种思想,在Java中理解:一个引用调用同一个方法,产生的行为不一样。

    继承:

    😯被继承的类称为,父类、基类或者超类。继承的类称为子类或者派生类。

    示例

    1. class Person {
    2. private int age;
    3. private String name;
    4. public void eat() {
    5. System.out.println(name + "在吃饭");
    6. }
    7. public int getAge() {
    8. return age;
    9. }
    10. public void setAge(int age) {
    11. this.age = age;
    12. }
    13. public String getName() {
    14. return name;
    15. }
    16. public void setName(String name) {
    17. this.name = name;
    18. }
    19. }
    20. class Student1 extends Person {
    21. boolean sleep;
    22. public void fun() {
    23. System.out.println("在睡觉");
    24. }
    25. }
    26. class Student2 extends Person {
    27. public void fun() {
    28. System.out.println("在学习");
    29. }
    30. }
    31. public class Test7 {
    32. public static void main(String[] args) {
    33. Student1 stu1 = new Student1();
    34. stu1.setAge(21);
    35. stu1.setName("www");
    36. System.out.println(stu1.getName() + stu1.getAge());
    37. }
    38. }

    🐵继承使用关键子extends,继承之后子类可以复用父类的成员,但必须要保证子类中有特有的属性或者行为,否则就没有必要去继承了。

    子类中访问父类成员变量:

    变量名字不同

    🎈在子类中就正常访问父类中的成员。

    变量名字相同

    🎈就近原则,优先访问子类中的成员变量,如果想要访问父类中的成员变量,需使用super关键字(后续介绍)。

    子类中访问父类成员方法:

    方法名字不同

    😯和访问变量原则一样,直接访问就行。

    方法名字相同

    😯就近原则,优先访问子类中的成员方法,如果想要访问父类中的成员方法,也需super关键字。与变量的访问规则对比着去理解。

    super关键字

    😊super的存在,解决了在子类中访问父类中相同的成员变量和方法。

    1. class Person3 {
    2. int a;
    3. int b;
    4. public void fun() {
    5. System.out.println("aaaa");
    6. }
    7. }
    8. class Student3 extends Person3{
    9. int a;
    10. int b;
    11. int c;
    12. public void fun() {
    13. System.out.println("bbbb");
    14. }
    15. public void func() {
    16. a = 0;
    17. super.a = 10;
    18. super.b = 20;
    19. super.fun();
    20. fun();
    21. System.out.println(super.a);
    22. System.out.println(a);
    23. }
    24. }
    25. public class Test8 {
    26. public static void main(String[] args) {
    27. Student3 stu = new Student3();
    28. stu.func();
    29. }
    30. }

    🎉 可以清楚的看见通过super访问到了父类中的成员变量和方法。

    注意:super只能在非静态方法中使用,因为静态方法是属于类的,它不属于某一个对象。

    子类构造方法

    🪖首先不同类的构造方法肯定在不同类中,虽然子类继承了父类,但在用子类实例化对象时需要调用父类的构造方法,完成父类中成员的构造,接下来调用子类的构造方法,完成子类成员的构造。父类构造方法需先调用,然后再调用子类的构造方法。这是用子类实例化对象的必要条件

    示例

    1. class Person8{
    2. int age;
    3. String name;
    4. public Person8(String name) {
    5. age = 21;
    6. System.out.println(name + this.age);
    7. }
    8. }
    9. class Student8 extends Person8{
    10. boolean sleep;
    11. public Student8() {
    12. //必须在第一句
    13. super("www");
    14. sleep = false;
    15. System.out.println(sleep);
    16. }
    17. }
    18. public class Test9 {
    19. public static void main(String[] args) {
    20. Student8 stu = new Student8();
    21. }
    22. }

     💎可以清楚看见先调用父类构造方法然后调用子类构造方法

    注意:

    🎄如果父类定义了无参构造方法,或者没有定义构造方法,则在子类中构造方法第一句默认super()调用了父类构造方法。

    🎄子类调用父类构造方法必须在子类构造方法中第一句

    🎄super和this不能同时存在,因为this调用构造方法也得放在第一句。

    super和this

    相同点:

    🧢都是关键字

    🧢只能在非静态方法中使用,访问非静态成员变量或者方法。

    🧢构造方法调用时只能在第一句,且不能同时存在

    不同点:

    🎉this是当前对象的引用,super可以理解为是子类中所继承父类对象的引用。

    🎉在非静态方法中,this用来访问本类的成员和方法,super用来访问父类的成员和方法。

    🎉在构造方法中,this()调用本类构造方法,super()调用父类构造方法。

    🎉子类构造方法中一定存在super(),程序员没有写编译器也会增加,但是this()不写则没有。

    再谈初始化

    😆继承关系下,静态代码块,示实例代码块,构造方法的执行顺序?

    1. class Person8{
    2. int age;
    3. String name;
    4. static {
    5. System.out.println("Person8的静态代码块");
    6. }
    7. {
    8. System.out.println("person8的实例代码块");
    9. }
    10. public Person8() {
    11. System.out.println("Person8的构造方法");
    12. }
    13. }
    14. class Student8 extends Person8{
    15. boolean sleep;
    16. static {
    17. System.out.println("Student8的静态代码块");
    18. }
    19. {
    20. System.out.println("Student8的实例代码块");
    21. }
    22. public Student8() {
    23. super();
    24. System.out.println("Student8的构造代码块");
    25. }
    26. }
    27. public class Test9 {
    28. public static void main(String[] args) {
    29. Student8 stu = new Student8();
    30. System.out.println("------------------");
    31. Student8 stu2 = new Student8();
    32. }
    33. }

     🤨首先执行父类静态代码块,然后执行子类静态代码块,接下来执行父类实例代码块和构造方法,再然后执行子类实例代码块和构造方法。父类和子类静态代码块执行一次,它们在类的加载时就执行了。实例代码块和构造方法只要实例化对象就会执行。

    继承方式:

    单继承

    B ----> A      B类继承A类

    多继承

    B ----> A ----> C  A类继承C类,B类继承A类

    不同类继承同一类

    B ----> A   C ----> A  B类继承A类,C类也继承A类。

    🐵我们不希望继承层次太过于复杂,继承层次一般不能超过三层

    注意:Java中不支持多继承,一个类同时继承多个类。

    final关键字:

    🤨final可以用来修饰成员变量,成员方法以及类。。

    final修饰成员变量

    🤨该变量为常量,不可以被修改,存储在JVM中的方法区

    final修饰成员方法

    🤨该方法不能被重写。(多态中详解)

    final修饰类

    🤨该类不能被继承。

    继承与组合

    🪖继承是一种联结类与类的层次模型,子类继承父类,可以增加自己的功能,是一种is - a的关系。

    🪖组合是在新类中产生现有类的对象,因此新的类是由现有类的对象所组成,可以复用现有类中的属性和方法。是一种has - a的关系。

    示例

    1. lass Person9 {
    2. int age;
    3. String name;
    4. public void fun() {
    5. name = "www";
    6. System.out.println(name + "在学习");
    7. }
    8. }
    9. class Student9 {
    10. Person9 stu = new Person9();
    11. Person9[] stu2 = new Person9[10];
    12. public Student9(int age, String name) {
    13. stu.age = age;
    14. stu.name = name;
    15. }
    16. public void fun() {
    17. System.out.println(stu.name + stu.age);
    18. stu.fun();
    19. }
    20. }
    21. public class Test10 {
    22. public static void main(String[] args) {
    23. Student9 stu = new Student9(21, "www");
    24. stu.fun();
    25. }
    26. }

    多态 

    😉多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。(可能不是很容易理解,下面会体现这种思想)

    多态的条件(缺一不可)

    😊必须在继承关系下。

    😊子类必须要对父类的方法进行重写

    😊通过父类的引用调用重写的方法。

    重写

    😆这个是建立在继承关系上的,子类对继承父类的一些方法不是很满意,自己再去写一遍这个方法,这个就是实现多态的首要条件。

    😆重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。核心代码重写

    方法重写的规则

    😯形参列表不能改变,形参的顺序,个数,类型都不能改变。

    😯返回值需相同,或者具有父子关系。

    😯方法权限只能大于或者等于被重写的方法。

    😯父类被static、private或者构造方法都不能重写。

    注意:

     🎈方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

     🎈父类被private修饰的方法或者属性虽然被继承了,但是子类中是无法访问的。

    示例

    1. class Person6 {
    2. int age;
    3. String name;
    4. public void eat() {
    5. name = "www";
    6. System.out.println(name + "吃米饭");
    7. }
    8. }
    9. class Student6 extends Person6{
    10. boolean sleep;
    11. public void eat() {
    12. name = "w";
    13. System.out.println(name + "吃鱼");
    14. }
    15. }
    16. class Student7 extends Person6 {
    17. public void eat() {
    18. name = "ww";
    19. System.out.println(name + "吃肉");
    20. }
    21. }
    22. public class Test11 {
    23. public static void fun(Person6 stu) {
    24. stu.eat();
    25. }
    26. public static void main(String[] args) {
    27. Student6 stu1 = new Student6();
    28. Student7 stu2 = new Student7();
    29. fun(stu1);
    30. fun(stu2);
    31. }
    32. }

     😯多态的体现:同一个引用(对象不同),调用同一个方法,产生的行为却不同

    静态绑定

    🐵也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表方法重载

    动态绑定

    🐵也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。(编译看左边,运行看右边)

    向上转型

    😉概念:创建一个子类对象,被父类所引用。

    1. class W2 {
    2. int a;
    3. public void fun() {
    4. a = 10;
    5. System.out.println(a);
    6. }
    7. }
    8. class W3 extends W2 {
    9. int b;
    10. public void fun() {
    11. System.out.println("aaaaa");
    12. }
    13. }
    14. public class Test12 {
    15. public static void main(String[] args) {
    16. //向上转型
    17. W2 stu = new W3();
    18. stu.fun();
    19. //向下转型
    20. //确保stu引用了W3这个对象
    21. if(stu instanceof W3) {
    22. W3 stu2 = (W3) stu;
    23. //访问子类中特有成员
    24. System.out.println(stu2.b);
    25. }
    26. }
    27. }

    注意:向上转型,最后运行时原理就是动态绑定,让代码更加灵活。

    向下转型

    代码(W2父类    W3子类)

        W2 stu = new W3();

        W3 stu2 = (W3) stu;(向下转型)

    🤨向上转型,只能访问子类中父类被子类重写的方法、被继承父类中的属性和父类中没有被子类重写的方法。无法访问子类中特有的方法或者属性。

    🤨向下转型,可以访问子类中特有的方法或者属性。

    注意:向下转型不是很安全,需保证其可以正常还原。

     小结:

    🐵理解是学习首当其冲进行的,需大量练习才能提高我们的代码能力,坚持下去会有不一样的收获。

  • 相关阅读:
    高效擦除/移除(Erase–remove idiom)std::vector元素
    C++ || 浅拷贝 深拷贝
    全方位介绍工厂的MES质量检验管理系统
    基于QT使用OpenGL,加载obj模型,进行鼠标交互
    一、excel转pdf格式jacob.jar
    SAP 灵活工作流邮件通知
    睿趣科技:抖音开一家网店大概什么时候回本
    C语言学习记录(三)之操作符
    2022年湖北省能源领域首台(套)重大技术装备申报条件、流程及有关要求
    SpringCloud——Gateway(使用redis做限流、跨域)
  • 原文地址:https://blog.csdn.net/weixin_62353436/article/details/126379094