面向对象的三个基本特征:封装、继承、多态
多态:
- 多态是指允许不同类的对象对同一消息做出响应
- 多态性语句具有灵活、抽象、行为共享、代码共享的优势
多态的定义:
- Java中多态性是指允许不同类的对象对同一消息可以根据发生对象的不同而采用多种不同的行为方式
- 发生消息就是方法调用
- 现实中,关于多态的例子不胜枚举。比如按下F1这个动作,如果当前在IE界面下弹出的浏览器的帮助文档;如果当前在Word下弹出的就是office帮助;在Windows下弹出的就是Windows帮助和支持
- 可见,同一事件发生在不同的对象上会产生不同的结果,因此,多态的主要作用适用于消除类型之间的耦合关系
方法重载overload与方法重写override
- 方法重载:
- 在同一个类中,方法名字相同、但参数列表不同(类型、个数、顺序)、返回类型可以相同或不同、访问权限可以相同或不同的方法
public class Test{
public int a (int x ,int y){
rteturn x + y;
}
public int a (int x ,int y,int z){
rteturn x + y + z;
}
public double a (double x ,double y){
rteturn x + y;
}
}
- 子类不一定总是希望借用父亲提供的数据和行为
- 方法重写:
- 继承的作用就是复用,即子类直接使用父亲的属性和方法
- 然后有些时候。子类希望修改父亲的方法和方法体,这时候我们该咋么做捏
- 第一种做法:
- 子类创还能一个不同名字的新方法,实现新的逻辑,但是,这种做法会导致子类依然包含父类中的那个反复噶,却不应该使用,破坏封装性
- 我们希望子类中依然和父类方法的声明形式一样,但是具体放方法体却不同,这种做法我们称之为 方法覆盖 / 方法重写
- 上面的鸟类 示例中,企鹅和鸵鸟均需要覆盖鸟类的move方法:
- 想要完成方法的覆盖,需要遵守以下规则
- 发生方法覆盖的两个方法的方法名、参数列表必须完全一致(子类重写父类的方法),返回值如果是基本数据类型,则返回值应该保持一致,如果返回值是类,则子类覆盖方法的返回值必须是父类方法返回值或其的子类(协变返回类型)
- 子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常)
- 子类方法的级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)
super关键字在方法覆盖中的使用
- 如果在子类覆盖的方法里或其他地方需要明确的使用父类声明的方法版本,也可以使用之前遇到的super关键字显示调用
- 事实上,子类中也能够声明和父类中的成员变量,此时在子类中通过变量名访问,使用的是子类自己定义的成员,也可以使用super来显示父类成员
- 需要注意,虽然能通过super.function() 的方式调用父类中声明的function方法,但是super和this不同,他不是一个真正意义上的引用,因此不能将其作为参数传递给其他调用者
对象向上造型
- 在继承关系中,继承者完全可以替换被继承者,反之则不可以
- 所谓的向上造型就是父类的引用(栈中)指向子类的对象(堆中)
编译期类型与运行期类型
- 在进行对象造型时,用来声明引用的父类类型我们称之为编译期类型。而实际用于构建子类类型我们称之为运行期间
- 引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法
- 编写Java代码时,引用只能调用编译器类型里包含的成员
- 通过Object p = new Persion()代码定义一个变量 p ,则这个p 只能调用 Object 类的方法,而不能调用Persion类定义的方法
- 对象在满足条件的情况下也能进行向下造型,即显式的将父类引用指向的对象转换为子类类型
- 向下造型的要求是:进行向下造型的对象的运行期间类型必须是子类或以子类为根的继承树中的其他造型:
多态环境下对属性的方法的调用特点
- 在Java代码中的数据和行为(变量和方法)在进行绑定(即通过对象调用成员变量或方法时究竟调用哪个版本,如覆盖后的方法)的时候划分为两种类型:
- 静态绑定
- 动态绑定
- 静态绑定发生在编译时期,动态绑定发生在运行时
- 类的成员变量(属性)都是静态绑定的(编译时),就是说,类中声明的成员变量不能被子类中的同名属性覆盖,通过该列的引用调用成员,始终调用该列自身中的声明的属性(即始终调用编译器类型中的属性)
- 对于Java中的方法而言,除了final、static,private和构造方法是静态绑定外,其他皆为动态绑定
- 这就意味着方法的调用将动态使用运行期类型版本
- 由上所述可以看出:
- 重载方法中具体调用哪个版本是通过静态绑定在编译期就决定了的
- 重写覆盖的方法调用哪个版本是通过动态绑定在运行期决定的
多态参数的使用
- 如果将反复噶的形参参数声明为父类类型,结合前序章节介绍的方法参数的功能(即调用方法代码前会隐式执行形参和实参之间的赋值操作),由于子类的对象赋值给父类的引用是合法的,那么调用方法时,实参就可以是以形参为根的继承树中的任意类型
- 此时形参对应的运行期类型和传过来的实参运行期类型保持一致
instanceof运算符
- 实参可能是形参的任意子孙类,某些时候需要在方法中明确究竟参数的运行期类型是什么,那么instanceof运算符提供了一种解决方案
- 运算符instanceof用来判断对象是否属于某个类的实例,语法为:
- 该表达式为一个boolean表达式,如果对象的类型是后面提供的类或其子类,则返回true,反之返回false
- 示例:
总结:
- 多态在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法
- 多态存在的三个必要条件
- 继承
- 重写覆盖
- 对象向上造型 - 父类引用指向子类对象
- 多态的好处
- 可替换性:
- 多态对已存在的代码具有可替换性
- 可扩充性:
- 多态对代码具有可扩充性。
- 增强新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能
- 接口性:
- 多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或覆盖它而实现的
- 灵活性:
- 在应用中体现了灵活多样的操作,提高了使用效率
- 简化性
- 多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要
- 可替换性: