| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> Java 类和对象——继承、多态 -> 正文阅读 |
|
[Java知识库]Java 类和对象——继承、多态 |
一、继承有些类在设计上是有关联的,比如我们定义了一个动物类:
在定义一个猫类:
? ? 我们发现:这两个类有很多的部分是重叠的。那么,能不能降低重叠的部分,把Animal类中的直接拿过来在Cat类中使用呢?面向对象思想中提出了继承的概念。 1、继承的概念? ? 继承:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了 由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。简单来说,继承是is--a的关系:猫是一个动物。 2、定义继承Java中要表示类的继承关系,需要extends(扩展)关键字。Cat如何继承Animal: ? ? 类只有两种访问修饰限定符:public和什么都不加的默认权限访问。一个Java文件中只能只能有一个public类。由于main方法所在的类有一个public,所以其他的类都是默认的访问修饰限定符。这里的Cat是子类(或者派生类),Animal是父类(或基类、超类)。中间的extends表示扩展、继承。 那么上面的两个类就可以写为:
现在我们以Base类(基类)和Derived类(派生类)来举例。
访问子类和父类的属性或方法: 发现:实例化子类对象,红色的框中出现子类继承过来父类的一些属性。? 3、super关键字? ? 现在在子类中写一个derivedBaseSameNameAttribute()方法表示出现子类和父类中变量名同名的情况,在Base类中加一个data5=51;Derived类中加一个data5=50,然后在这个方法中访问。 打印的是子类中的data5。要访问父类的data5,需要加super关键字。super表示父类对象的引用。 ? ? super和this关键字的使用差不多。super和this一样有三种使用方法:super.data,表示调用父类的属性、super.func()表示调用父类的方法、super()表示调用父类中的构造方法。这里的super.data5就表示调用父类的属性。 如果是成员方法名相同:在Base类和Derived类中加一个derivedBaseSameNameMethod()方法。 ? ? 打印的是子类的derivedBaseSameNameMethod()方法。在main方法中要打印父类的同名方法,加一个super是不行的(同名属性也不行)。要么在子类中写一个方法来间接调用、要么将父类的derivedBaseSameNameMethod()方法和子类的方法形成重构、要么实例化父类对象访问。 这里的参数没有意义,只是为了调用父类的构造方法。但是最好不要这样写没有意义的参数。 总结: (1)在子类中,如果想要明确来访问父类中的成员时,需要super关键字就可以了。父类和子类中不重名的时候也可以使用this。 (2)重名的时候,编译器采用就近原则。先去子类中找,找不到就去父类(不能从父类到子类)。还找不到就报错。 (3)通过子类对象访问父类与子类同名方法时,如果父类和子类同名方法构成重载,根据调用方法适传递的参数选择合适的方法访问,如果没有则报错;如果父类和子类同名方法相同(方法名、参数列表等)则只能访问到子类的,父类的会被覆盖掉(构成重写),无法通过子类对象直接访问到。 (4)super关键字只能在非静态方法中使用。在子类方法中访问父类的成员。 super和this比较,相同点: (1)都是Java中的关键字,只能在类的非静态方法中使用。 (2)用在构造方法中,都要放在相对的第一行。也就是说它们不能同时存在。 不同点: (1)this是当前对象的引用,super是子类对象从父类中继承下来的成员的引用。也就是说,this一般用来访问子类的方法和属性,super用来访问父类的方法和属性。 (2)this是非静态成员方法的一个隐藏参数,super不是隐藏的参数。 (3)构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有。 4、子类构造方法? ? 在没有继承的时候,对类中的成员变量进行初始化,有就地初始化、默认初始化,代码块初始化等、最重要的是用构造方法进行初始化。那么一个类被继承后,有没有什么变化呢? 在父类写出它的带参数的构造方法。 给子类也加一个构造方法。 ? ? 我们知道,子类是继承了父类的。所以子类在进行构造的时候,应该要给父类也进行构造。所以子类在构造的时候,要先帮助父类进行构造,在调用子类的构造方法。使用super()就可以了。 带参数的构造方法: 不带参数的构造方法: ?总结: (1)若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法。 (2)如果父类构造方法是带有参数的,此时编译器不会再给子类生成默认的构造方法,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。 (3)super()和this()相似,都要放在构造方法中的第一行。也就是说,super()和this()不能同时使用。 5、protected关键字? ? 当父类中的属性被private修饰的时候,只能在父类中使用。子类虽然是继承了父类,但是访问不到这个属性。 只需要将这个private改为protected(受保护的)权限就可以了。 ? ? 我们知道,Java中权限有四种:private、默认、protected和public。private表示只能在当前类中使用。默认表示只能在同一个包中使用。protected是继承权限,范围比默认的要大,可以在不同的包中访问到。public是公共权限,在哪里都能访问。 ? ? 类要尽量做到封装,隐藏内部实现细节,只留下必要的信息给类的调用者。因此,要使用比较严格的访问权限。能提供private的就不要提供protected权限。 6、继承方式Java支持多种继承方式: ? ? Java不支持一个类继承多个类的继承方式。但是可以使用接口来实现。在继承关系中,一般不要超过三层的继承关系。如果一个类不想被继承,就可以使用final关键字来修饰。final可以用来修饰变量或字段,表示常量(不能被修改);修饰类,表示这个类是一个密封类,不能被继承;修饰方法,表示这个方法不能被重写。 7、组合? ? 继承是一种表达类之间关系的方式,组合也是一种表达类之间关系的方式。组合只是将一个类的实例作为另一个类的字段。 有三个类:学生类、老师类和学校类。要把他们组合起来,就是学校里面有学生,学校里面有老师。 这样创建之后是不能直接访问的,要对学生类和老师类进行实例化后才能访问。 ? ? 其他的就和前面的语法没有什么区别。我们写课后作业的时候的测试类就是一个组合。继承是is--a的关系:猫是一个动物,而组合是has--a的关系:动物有猫这个物种。 二、多态? ? 多态具体一点就是要去完成某个行为,不同的对象去完成,会产生不同的状态。比如考试,学霸考试得到高分,学渣考试得到混合双打,这是一种多态。 1、多态实现的条件(1)必须要在继承的体系下。 (2)子类对父类中的方法进行重写。 (3)通过父类引用去调用子类重写的方法。 多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。下面对这些条件分别做介绍。 2、向上转型和向下转型? ? 向上转型是实现多态的一部分条件,它在继承的体系下。多态中上指的是父类,下指的是子类。向上转型就是子类转型成父类。或者:父类引用,引用子类对象。只要记住父类引用,引用子类对象。这是从小的范围像大的范围转换。
? ? 父类引用了子类对象,但是不能调用子类方法。这个derivedMethod()方法在父类中是没有的。向上转型有三种用法:直接赋值、作为参数传参、作为返回值。 直接赋值: 作为参数传参:在main方法中新写一个方法,用来传参数。 ?作为返回值:写一个方法,返回值是Base类型。 这三种虽然用处不一样,但本质上还是父类引用,引用子类对象。 向上转型能够让代码实现更灵活,缺点是不能调用子类特有的方法。 向下转型是子类引用,引用父类方法。但是这意味着范围的缩小,所以它不安全。 图示: 3、重写方法? ? 重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写,返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法。 定义一个Animal类,Cat类和Dog类继承了Animal类。
? ? 我们知道,猫是可以吃猫粮的,狗是可以吃狗粮的。所以,对父类中的eat()方法能不能改一下呢?可以改,但是不能直接在父类方法中改,并不是所有的动物都是吃猫粮的。为了代码的直观,删去了Cat类中的catchingMice()方法和Dog类中的housekeeping()方法。 ? ? 这个时候,子类和父类的eat方法中:返回值相同、方法名相同、方法参数列表相同。这就构成了方法的重写:子类的eat()方法对父类的eat()方法进行了扩展或覆盖。我们在用向上转型去调用子类的eat()方法。? 发现这里的结果是调用了子类的eat()方法。为了让重写显着更清楚,可以加上@Override。 这样,不仅可以显示更清楚,而且如果变量名等写错,就可以提示出来。? ? ? 在编译的时候,eat()调用应该是父类的方法,结果运行的时候,调用的是子类的方法。这种情况是在运行的时候发生的,叫运行时绑定(动态绑定)。 ? ? 动态绑定,也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用哪个类的方法。 重写要注意的几个点: (1)子类在重写父类的方法时,一般必须与父类方法原型一致:修饰符 返回值类型 方法名(参数列表) 要完全一致。 (2)返回值可以不同,但是要形成父子关系,叫协变类型。 (3)子类的重写方法访问权限不能比父类低。如果父类时protected,子类就不能是?默认或private;如果父类是public,子类只能是public。 (4)父类静态的,private修饰的,final修饰的方法都不能重写。 (5)和重载的区别 方法的重载是一个类的多态的体现,方法的重写是子类和父类多态的体现。 ? ? 现在,在主类中写一个方法,传进去不同的对象,?调用父类的eat()方法,显示因为传进去猫这个对象,打印吃猫粮,传进去狗这个对象,打印吃狗粮。
4、使用多态的优缺点优点: (1)提高了代码的可读性,避免了使用大量的if-else。 (2)可扩展能力更强。 比如,打印不同的图形,这样,使用多态直接扩展就可以了。
缺点:代码的运行效率低,而且,不能使用子类的方法。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 7:29:08- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |