概述
Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致(多为父类引用指向子类对象),就可能出现所谓的多态。
有些情况下程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 实现的 eat(将父类实现)
Cat c = (Cat)a; // 向下转型(转的都是父类的引用,而不是父类对象)
c.work(); // 调用的是 Cat 的特有方法catchMouse(父类没有)
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
向上转型:
Animal a = new Cat();
此处引用变量a 编译时类型是Animal,运行时类型是Cat,调用的是Cat的eat方法。Java允许把一个子类对象直接赋给一个父类引用变量,无需任何类型转换,由系统自动完成。
这样做存在一个非常大的好处,在继承中我们知道子类是父类的扩展,它可以提供比父类更加强大的功能,如果我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能。
但是向上转型存在一些缺憾,那就是它必定会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了
向下转型:
Cat c = (Cat)a;
使用Cat的特有方法,强制将父类的引用转成子类类型
自始至终都是子类对象在做着变化
多态中成员函数的特点:
在编译时:参阅引用型变量所属的类中是否有调用的方法,有,则编译通过,没有则编译失败
在运行时:参阅对象所属的类中是否由调用的方法
特殊的:静态成员函数无论编译和运行,都参考引用型变量所属的类
多态中成员变量的特点:
无论编译和执行,都参考引用型变量所属的类
实例:
电脑依赖主板运行,同时主板又可以拓展出其他功能
public interface PCI {
public void open();
public void close();
}
public class Mainboard {
public void run(){
System.out.print("Mainboard run");
}
public void PCI_run(PCI p){
//接口型引用指向自己的子类对象 相当于PCI p=new Netcard()或者PCI p=new Soundcard()
if(p!=null){
p.open();
p.close();
}
}
}
public class Netcard implements PCI{
public void open(){
System.out.print("Netcard run");
}
public void close(){
System.out.print("Netcard close");
}
}
public class Soundcard implements PCI{
public void open(){
System.out.print("Soundcard open");
}
public void close(){
System.out.print("Soundcard close");
}
}
public class Test {
public static void main(String[] args){
Mainboard mb=new Mainboard();
mb.run();
mb.PCI_run(null);
mb.PCI_run(new Netcard());
}
}
分析:其他功能是拓展出的,为了降低其与主板的耦合性,增强主板的可拓展性,可以使用接口的方式。而在主板中也要使用接口,并且通过改变传入的参数,实现相应的功能,这里的接口型引用指向自己的子类对象,体现着多态