一、多态的简单介绍。
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
通过代码来更加清晰地了解这个特性。
public class Person {
public void fun1(){
System.out.println("This is Person的fun1方法!");
}
public void fun2(){
System.out.println("This is Person的fun2方法!");
}
}
public void fun1(){
System.out.println("这是Son的fun1方法,该方法为重写的方法!");
}
public void fun2(String str){
System.out.println("这是Son的fun2方法,该方法为重载方法!");
}
}
public class Test {
public static void main(String[] args) {
Person p = new Person();
Son s = new Son();
Person p_s = new Son();
p_s.fun1();
p_s.fun2();
//p_s.fun2("00");
}
}
输出结果为:
这是Son的fun1方法,该方法为重写的方法!
This is Person的fun2方法!
此处定义了一个Person类型的p_s,他指向Son的对象实例,因为Son是继承Person的,因此Son会自动向上转型为Person类型。这里由于Son类重写了父类的fun1()方法,因此根据多态性,这里的p_s对象调用的是子类重写了父类的这个方法,这就意味着子类对父类功能进行了扩展;而Son类对父类的fun2方法进行了重载,重载就意味着是一个新的方法,因为这个方法是在子类中定义的,在父类中并不能找到这个方法,因此父类类型的引用不可以调用这个重载的方法。
这里有一个别人总结的结论很好用:父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了。
分析:
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。
二、多态的实现。
1、多态的实现需要依赖三个条件:继承、方法的重写、对象向上转型。
即多态需要有存在继承关系的子类和父类,在子类中对父类中已存在的方法进行重写,而后子类的实例对象向上转型为父类类型之后通过父类引用类型来调用方法。在这里调用方法的时候是引用类型(即子类类型)决定了调用谁的成员方法,但是要调用的方法必须是父类中定义过,即在子类中进行了重写的方法!
2、多态的实现有两种形式:继承和接口
public class Person {
private String position;
public Person() {
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public String showPosition() {
return "My job is:" + getPosition();
}
/**
* 重写了toString方法
*/
public String toString() {
return null;
}
}
-----------------------
public class Teacher extends Person{
public Teacher(){
//这里是继承了父类的setPosition方法
setPosition("Teacher");
}
/**
* 这里重写了父类的showPosition方法
*/
public String showPosition(){
return "My job is:"+getPosition();
}
/**
* 重写toString方法
*/
public String toString(){
return "Position name is:"+getPosition();
}
}
---------------
public class Farmer extends Person{
public Farmer(){
//这里是继承了父类的setPosition方法
setPosition("Farmer");
}
/**
* 这里重写了父类的showPosition方法
*/
public String showPosition(){
return "My job is:"+getPosition();
}
/**
* 重写toString方法
*/
public String toString(){
return "Position name is:"+getPosition();
}
}
--------------------------
测试代码:
Person teacher = new Teacher();
Person farmer = new Farmer();
System.out.println(teacher.toString()+"————"+teacher.showPosition());
System.out.println(farmer.toString()+"————"+farmer.showPosition());
执行结果:
Position name is:Teacher————My job is:Teacher
Position name is:Farmer————My job is:Farmer
这里Teacher、Farmer对象都执行的是相同的操作:获取职位名称并把工作名称打印出来。但是通过多态实现,就可以让他们各自使用自己的实现方法来做这些操作。所以基于继承的多态,就是同种操作,多种状态(各自不同的职位)。
如果父类是抽象类,那么子类必须要实现父类中所有的抽象方法,这样该父类所有的子类一定存在统一的对外接口,但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的统一接口来处理该层次的方法。
相比于继承,因为只能继承一个,所以只能为同一种类提供一致的服务口。而如果使用接口就可以实现多继承,可以将不同的服务组合到一起来使用,更加灵活。
继承:继承关系是is-a的关系。例如猫是动物的子类,老师是人的子类。继承一般是指继承了父类的属性,如:哺乳动物,年龄,性别等;
接口:接口关系是can-do的关系。例如猫可以实现动物接口,动物接口中指定了动物的行为:奔跑,即猫可以奔跑。接口是可以进行组合的,比如老师既实现了人这个接口可以吃饭睡觉看书,又实现了老师接口可以教书育人,还实现了父母接口可以管教孩子。
参考:http://www.cnblogs.com/chenssy/p/3372798.html
补充一个多态的例子:http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx