类的继承和多态细思

类的继承和多态细思

一、前言

  类的继承和多态光靠概念和想象是不够的,我们需要编码去分析之,因此我使用代码来说明一些很难分清的东西。

二、分析代码

A类代码:

package zyr.study.poly;

public class A {
    public A(){
        System.out.println("初始化A...");
    }

    public String show(A obj) {
        return ("A and A");
    }   

    public String show(B obj) {
        return ("A and B");
    }   

    public String show(D obj) {
        return ("A and D");
    }
}

B类代码:

package zyr.study.poly;

public class B extends A{
    public  B(){
        System.out.println("初始化B...");
    }

    public String show(A obj){
        return ("B and A");
    }   

    public String show(B obj){
        return ("B and B");
    }
}

C类代码:

package zyr.study.poly;

public class C extends B{
    public C(){
        System.out.println("初始化C...");
    }
}

D类代码:

package zyr.study.poly;

public class D extends B{
    public D(){
        System.out.println("初始化D...");
    }
}

main函数:

 1 package zyr.study.poly;
 2
 3
 4 public class Main {
 5
 6     public static void main(String[] args) {
 7         A a1 = new A();
 8         System.out.println("-----------------");
 9         A a2 = new B();
10         System.out.println("-----------------");
11         B b = new B();
12         System.out.println("-----------------");
13         C c = new C();
14         System.out.println("-----------------");
15         D d = new D();
16         System.out.println("-----------------");
17
18         System.out.println("1--" + a1.show(a1));  // a and a
19         System.out.println("2--" + a1.show(a2));  // a and a
20         System.out.println("3--" + a1.show(b));   // a and b
21         System.out.println("4--" + a1.show(c));   // a and b
22         System.out.println("5--" + a1.show(d));   // a and d
23
24         System.out.println("-----------------");
25
26         System.out.println("1--" + a2.show(a1));  // b and a
27         System.out.println("2--" + a2.show(a2));  // b and a
28         System.out.println("3--" + a2.show(b));   // b and b
29         System.out.println("4--" + a2.show(c));   // b and b
30         System.out.println("5--" + a2.show(d));   // a and d
31
32         System.out.println("-----------------");
33
34         System.out.println("1--" + b.show(a1));  // b and a
35         System.out.println("2--" + b.show(a2));  // b and a
36         System.out.println("3--" + b.show(b));   // b and b
37         System.out.println("4--" + b.show(c));   // b and b
38         System.out.println("5--" + b.show(d));   // a and d
39     }
40 }  

运行结果:

初始化A...
-----------------
初始化A...
初始化B...
-----------------
初始化A...
初始化B...
-----------------
初始化A...
初始化B...
初始化C...
-----------------
初始化A...
初始化B...
初始化D...
-----------------
1--A and A
2--A and A
3--A and B
4--A and B
5--A and D
-----------------
1--B and A
2--B and A
3--B and B
4--B and B
5--A and D
-----------------
1--B and A
2--B and A
3--B and B
4--B and B
5--A and D

  下面我们仔细分析这个程序和运行结果。

  首先我们定义了一个类,命名为A,这是一个超类或者叫做基类。在这个类中,使用了函数级别的多态或者说是重载,分别能识别的类型为A类、B类(A类的子类),D类(B类的子类,A类的孙类);

  然后我们定义了B类,继承自A类,同时重写了A类和B类;

  之后我们定义了C类,继承自B类,无操作;

  然后我们定义了D类,继承自B类,无操作;

  在函数体中,我们使用了各自的类定义了对象,并且有一个特殊的,那就是A类的引用指向了B类的对象,这就是多态了,这样的结果就是,A a2=new B();a2所指的函数中因为B继承自A,除了B中重写A中的方法之外,B中其他的方法都是不可见的,并且A中除了被重写的方法之外的方法是可见的。

  让我们看第一批分析:

1         System.out.println("1--" + a1.show(a1));  // a and a
2         System.out.println("2--" + a1.show(a2));  // a and a
3         System.out.println("3--" + a1.show(b));   // a and b
4         System.out.println("4--" + a1.show(c));   // a and b
5         System.out.println("5--" + a1.show(d));   // a and d

  对于第一行,a1的定义是A类的引用,并且指向A的对象,因此可见范围为A类中的A,B,D,因此,只有在A中的方法才能被选择,所以本身作为参数A,则选A and A;对于第二行,a2的定义还是A类的,只不过包含的东西多了一点而已(其实也不多,只是包含了B中重写A中的方法,而不包含A中被重写的方法),因此底子里还是A类的,只会认A,结果为A and A;对于第三行,b是货真价实的,则选择A and B;对于第四行,C的对象就看关系的远近了,在符合条件的所有方法中,找一个距离C血缘关系最近的类,那就是B类了,因为A中没有C类的方法,因此A and B;对于第五行,A中正好有D类的方法,因此血缘关系肯定是最近了,选择自身A and D。

  再来看第二批函数:

1         System.out.println("1--" + a2.show(a1));  // b and a
2         System.out.println("2--" + a2.show(a2));  // b and a
3         System.out.println("3--" + a2.show(b));   // b and b
4         System.out.println("4--" + a2.show(c));   // b and b
5         System.out.println("5--" + a2.show(d));   // a and d

  首先,a2是个变态,经过了一定的改变,按照上面的分析,我们知道此时函数的可见性是A and D;B and A;B and B;

  因此第一行,找距离A类血缘最近的,肯定是B and A了;第二行,a2本质上还是A的引用,因此依旧是B and A;第三行,B找到自己血缘关系最近的B and B;第四行,C依旧寻找距离自己关系最近的,B and B;第五行,D寻找到了A and D;

  最后看看第三批函数:

1         System.out.println("1--" + b.show(a1));  // b and a
2         System.out.println("2--" + b.show(a2));  // b and a
3         System.out.println("3--" + b.show(b));   // b and b
4         System.out.println("4--" + b.show(c));   // b and b
5         System.out.println("5--" + b.show(d));   // a and d

  可见性:B是货真价实的,因此A and D;B and A;B and B。对于第一行,A类血缘最近的是B and A;第二行,a2也是A,因此B and A;第三行,b选择B and B;第四行,C选择血缘最近的B and B;第五行,D选择A and D。

  下面我们将B类里面加入一个C的函数,其他的不变,可见性会发生改变,我们分析一下结果:

 1 package zyr.study.poly;
 2
 3 public class B extends A{
 4     public  B(){
 5         System.out.println("初始化B...");
 6     }
 7
 8     public String show(A obj){
 9         return ("B and A");
10     }
11
12     public String show(B obj){
13         return ("B and B");
14     }
15
16     public String show(C obj){
17         return ("B and C");
18     } 
19 }

   对于第一批函数,因为可见性的原因,B的修改不能影响结果;对于第二批函数,多了一个C函数,可是我们知道多态的性质,a2所指的函数中C函数依旧是不可见的,因此不影响最终结果。对于第三批函数,可见性也发生了改变,在原有基础上多了C函数,因此第三批第四行中结果变成B and C,这从侧面上证明我们的分析是正确的。

运行结果如下:

初始化A...
-----------------
初始化A...
初始化B...
-----------------
初始化A...
初始化B...
-----------------
初始化A...
初始化B...
初始化C...
-----------------
初始化A...
初始化B...
初始化D...
-----------------
1--A and A
2--A and A
3--A and B
4--A and B
5--A and D
-----------------
1--B and A
2--B and A
3--B and B
4--B and B
5--A and D
-----------------
1--B and A
2--B and A
3--B and B
4--B and C
5--A and D

  对于构造函数的初始化,我们可以看到都是先初始化最超类,然后次超类,一直到自身的,如果将超类的构造函数设为私有,将提示错误,否则没问题。

三、总结

  在编程中,我们要注意定义中引用所指对象的可见性,先分析可见性,分析的时候要注意重载(override)和重写(overwrite)的区别,重写就是覆盖,重载有可能被排除在外,一定要记得。还有函数的初始化以及变量的可见性,都是值得分析的,如果再加上静态变量,静态函数,一切都变得有意思了。

原文地址:https://www.cnblogs.com/zyrblog/p/9219011.html

时间: 2024-10-28 17:36:50

类的继承和多态细思的相关文章

python之7-2类的继承与多态

类的继承的意思就如同父子关系一样,这个儿子继承了父亲的一切,但是在某些地方(属性)相同的时候,儿子的属性大于老子的属性(覆盖),最底层类,总会继承最接近它的那个类的属性init 类的多态总是和继承相连的,没有继承,就没有多态一说.一个子类的实例,它即属于这个子类,也属于父类,比如:父亲A和儿子B,儿子B即属于儿子类,也属于人类,但是它不属于父亲类 多态是面向对象语言的一个基本特性,多态意味着变量并不知道引用的对象是什么,根据引用对象的不同表现不同的行为方式.在处理多态对象时,只需要关注它的接口即

【游戏开发】在Lua中实现面向对象特性——模拟类、继承、多态

一.简介 Lua是一门非常强大.非常灵活的脚本语言,自它从发明以来,无数的游戏使用了Lua作为开发语言.但是作为一款脚本语言,Lua也有着自己的不足,那就是它本身并没有提供面向对象的特性,而游戏开发是一项庞大复杂的工程,如果没有面向对象功能势必会为开发带来一定的不便.不过幸好Lua中有table这样强大的数据结构,利用它再结合元表(metatable),我们便可以很方便地在Lua中模拟出类.继承和多态等面向对象编程具有的特性. 二.前提知识 按照惯例,我们还是先来熟悉一下必要的前提知识,以便方便

综合运用类、继承、多态,完成一个公司人员管理类层次结构(未完待续)

1.Target /*综合运用类.继承.多态等技术,完成一个公司人员管理类层次结构,用来描述人员信息等, 重载各种运算符,完成数据库内容的赋值.添加.工资增长等.*/ 2.Code #include <iostream> #include <cstring> #include <string> #include <cstdio> #include<cstdlib> #define TECH const string name, const int

实验6:类的继承和多态

南京信息工程大学实验报告 实验名称 类的继承和多态 实验日期 2018-5-29 得分 指导教师 耿学华 系 计软院 专业 计嵌+软嵌 年级 2017 级 班次 (1) 姓名 施昊阳 学号 20161334026 一.实验目的 理解类的继承和派生机制 掌握派生类的定义和使用 掌握派生类成员的标识与访问中同名覆盖原则.二元作用域分辨符和虚基类的用法 掌握派生类构造函数和析构函数的定义及调用次序 理解运算符重载的目的,掌握运算符重载函数的编写方法 二.实验准备 类的继承和派生 请结合第 7 章课件和

python类的继承和多态

python类的继承和多态 现在属于是老年人的脑子,东西写着写着就忘了,东西记着记着就不知道了.之前学C++的时候就把类.对象这块弄得乱七八糟,现在是因为很想玩python,所以就看看python的类和对象. 就像说的,类有三个特征:封装.继承.多态. 1.封装:类封装了一些方法,可通过一定的规则约定方法进行访问权限. C++中的成员变量有public.private.ptotected. 在python中,默认的成员变量都是public的,如果成员变量前面是加两个下划线,表示该成员变量是私有的

TypeScript笔记【2】类、继承、多态

和C++,C#那些可以面向对象的语言那样,TS也可以面向对象. 与JS相比,TS更像传统的面向对象语言(如Java,C#).所以,TS有类. 一.类 定义一个类,要用关键字[class]. class Animai {     name: string     eat(): void {         alert(this.name + '吃');     }     sleep(): void {         alert(this.name + '睡觉')     }     breat

【JAVA零基础入门系列】Day13 Java类的继承与多态

继承是类的一个很重要的特性,什么?你连继承都不知道?你是想气死爸爸好继承爸爸的遗产吗?(滑稽) 开个玩笑,这里的继承跟我们现实生活的中继承还是有很大区别的,一个类可以继承另一个类,继承的内容包括属性跟方法,被继承的类被称为父类或者基类,继承的类称为子类或者导出类,在子类中可以调用父类的方法和变量.在java中,只允许单继承,也就是说 一个类最多只能显示地继承于一个父类.但是一个类却可以被多个类继承,也就是说一个类可以拥有多个子类.这就相当于一个人不能有多个父亲一样(滑稽,老王表示不服). 话不多

零基础入门学习java第十三节:Java类的继承与多态

继承是类的一个很重要的特性,什么?你连继承都不知道?你是想气死爸爸好继承爸爸的遗产吗?(滑稽) 开个玩笑,这里的继承跟我们现实生活的中继承还是有很大区别的,一个类可以继承另一个类,继承的内容包括属性跟方法,被继承的类被称为父类或者基类,继承的类称为子类或者导出类,在子类中可以调用父类的方法和变量.在java中,只允许单继承,也就是说 一个类最多只能显示地继承于一个父类.但是一个类却可以被多个类继承,也就是说一个类可以拥有多个子类.这就相当于一个人不能有多个父亲一样(滑稽,老王表示不服). 话不多

python6.3类的继承与多态

class Animal(object): def __init__(self,color): self.color=color def eat(self): print("动物在吃!") def run(self): print("动物在跑!") class Cat(Animal):#继承Animal类 def eat(self): print("猫在吃鱼!") class Dog(Animal): def __init__(self,name