要知道程序员使用Java面向对象编程代码,是离不开面向对象程序的三大特性的:封装、继承、多态。
那么在这里我们首先回顾下Java的三大特性是什么:
- 封装:指的是隐藏了类的内部实现机制,可以在不影响使用者的前提下修改类的内部结构,同时保护了数据。
- 继承:是指类与类的一种关系,是一种“is-a-kind of”关系,即一般与特殊的关系。集成实现了父类代码的重用。子类继承父类就拥有了父类的成员。继承是多态的基础。
- 多态(Polymorphism):是不同事物具有不同表现形式的能力,即不同的对象面对同一个行为,呈现出不同执行效果。
什么是多态?
多态用一句话概括是:同一操作(方法)作用于不同的对象时,可以有不同的解释,产生不同的执行结果。
多态的实现依赖这些技术:重载、继承、重写、父类引用子类对象和动态绑定等。
===>
动态绑定(dynamic binding):
是指在执行期间判断所引用对象的实际类型,根据其实际类型调用其相应的方法。
父类句柄引用子类对象:
当没有继承关系时,一个类的句柄只能引用该类的对象。句柄是声明为某类的变量,此变量为引用类型。以下代码将Animal对象赋值给父类的句柄animal。
Animal animal = new Animal();
当类之间存在继承时,父类的句柄除了可以引用该类的对象之外还可以引用该类的所有子类对象。
Animal animal = new Rabbit();
上面代码,是将子类Rabbit对象赋值 给父类句柄animal。
===>
父类的句柄为什么可以引用子类的对象呢?
这是由继承关系保证的。父类 和子类的关系是一般和特殊的关系,子类is-a-kind of父类。声明为父类的句柄当然可以指向它的一种特殊子类,这也称之为“向上转型”。
===>
这样做的意义:
由于子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特。定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。
- 父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,父类引用是无法调用的。
- 如果子类重写了父类的某些方法,并且父类句柄指向了子类对象。那么运行时,是运行父类中的方法,还是子类重写后的方法呢?回答这个问题需要了解方法
方法绑定
public class Pencil{
private String type;
public Pencil(){}
public Pencil(String type){
this.type = type;
get/set方法…//省略
public void write (String s){
System.out.print(“使用铅笔书写:”+s)
}
}
}
public class TestPencil{
public static void main(String[] args){
Pencil pen = null; //声明Pencil类的句柄
//创建句柄的引用对象
pen = new Penciil("20");
//调用Pencil的方法
pen.write("现在开始写今天的家庭作业!");
}
}
综上 说白了多态就是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图
【注:图片借鉴自菜鸟教程】
故,多态就是对象的多种表现形式的体现
就好比
按下 F1 键这个动作:
- 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
- 如果当前在 Word 下弹出的就是 Word 帮助;
- 在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。
多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象
【注:当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。】
综上举例:
//子类Penguin
package com;
class Penguin extends Animal{
public void eat(){
System.out.println("吃小鱼");
}
public void work(){
System.out.println("在水里游泳");
}
}
//子类Dogs
package com;
class Dogs extends Animal{
public void eat(){
System.out.println("啃骨头");
}
public void work(){
System.out.println("等主人回家");
}
}
//父类Animal
package com;
abstract class Animal{
abstract void eat();
}
//在AnimalTest中分别对子类向上转型、对父类向下转型
package com;
public class AnimalTest {
public static void main(String[] args){
show(new Penguin()); //以Penguin对象调用show方法
show(new Dogs()); //以Dogs对象调用show方法
Animal animal = new Penguin(); //向上转型
animal.eat(); //调用的是Penguin的eat
Penguin animal1 = (Penguin)animal; //向下转型
animal1.work(); //调用的是Penguin的work
}
public static void show(Animal animal){
animal.eat();
//类型判断
if(animal instanceof Penguin){ //猫做的事
Penguin animal1 = (Penguin) animal;
}else if (animal instanceof Dogs){ //狗做的事
Dogs animal1 = (Dogs)animal;
animal1.work();
}
}
}
输出结果:
吃小鱼
啃骨头
等主人回家
吃小鱼
在水里游泳