疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java基础编程之多态


 

 
这一章节我们来简单讨论一些多态,java三大特性的最后一个。
 
1.概念
 
多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。
 
说白了,就是父类引用子类对象。
 
(1)调用的时候使用类型的多种状态
 
我们下面引入一个接口类Person
 
[java] view plaincopy
package com.ray.ch01;  
  
public abstract class Person {  
    public abstract void eat();  
  
    public abstract void sleep();  
  
}  
 
 
下面的Boxer和Singer都是继承Person这个父类。
 
 
[java] view plaincopy
package com.ray.ch01;  
  
public class Boxer extend Person {  
  
    public void fight() {  
  
    }  
  
    @Override  
    public void eat() {  
        System.out.println("boxer is eatting");  
    }  
  
    @Override  
    public void sleep() {  
        System.out.println("boxer is sleeping");  
    }  
  
}  
 
[java] view plaincopy
package com.ray.ch01;  
  
public class Singer extend Person {  
  
    public void sing() {  
  
    }  
  
    @Override  
    public void eat() {  
        System.out.println("singer is eatting");  
    }  
  
    @Override  
    public void sleep() {  
        System.out.println("singer is sleeping");  
    }  
  
}  
 
 
测试类Test:
[java] view plaincopy
package com.ray.ch01;  
  
public class Test {  
    public static void main(String[] args) {  
        Person boxer = new Boxer();  
        boxer.eat();  
        boxer.sleep();  
        Person singer = new Singer();  
        singer.eat();  
        singer.sleep();  
    }  
}  
 
测试输出:
boxer is eatting
boxer is sleeping
singer is eatting
singer is sleeping
 
从上面的代码可以看出,boxer和singer对象都是Person类,他们都不知道实际需要调用那个版本的eat和sleep方法,但是为什么最后的结果是我们需要的呢?下面我们会给出结论。
(2)参数使用类型的多种状态
 
我们继续沿用Person、Boxer和Singer这三个类,但是我们修改一下测试类Test
 
[java] view plaincopy
package com.ray.ch01;  
  
public class Test {  
      
    private void test(Person person) {  
        person.eat();  
        person.sleep();  
    }  
      
    public static void main(String[] args) {  
        Test test = new Test();  
        Person boxer = new Boxer();  
        test.test(boxer);  
        Person singer = new Singer();  
        test.test(singer);  
    }  
}  
 
上面的代码,我们把Person作为参数传到test里面去,然后person调用各自的方法。
同样的问题,在参数传进去之前,person根本就不知道指向那个实现版本。
 
测试输出:
 
boxer is eatting
boxer is sleeping
singer is eatting
singer is sleeping
 
 
 
(3)返回值使用多态。
 
我们再一次使用Person、Boxer和Singer这三个类,然后修改一下测试类Test
 
[java] view plaincopy
package com.ray.ch01;  
  
public class Test {  
  
    private Person test(Person person) {  
        return person;  
    }  
  
    public static void main(String[] args) {  
        Test test = new Test();  
        Person boxer = new Boxer();  
        test.test(boxer).eat();  
        test.test(boxer).sleep();  
        Person singer = new Singer();  
        test.test(singer).eat();  
        test.test(singer).sleep();  
    }  
}  
 
测试输出:
boxer is eatting
boxer is sleeping
singer is eatting
singer is sleeping
 
 
 
为了演示给大家看,我把测试类的代码绕了一下,通过一个方法,返回Person类,然后调用各自的方法。
 
 
 
那么,java是怎样做到呢?在这里我简单说一下,然后在后面的章节我们会详细展开。
 
其实eat和sleep都是泛化之后的方法,他们都面对调用哪个实际版本的问题。
 
对于一般非oop语言,他们会使用前期绑定的方法,也就是一开始就已经绑定方法的内存地址。
 
但是java它是使用后期绑定(运行时绑定),它通过一段特殊的代码,计算执行方法的内存地址,当然这段代码在编译器里面,我们是看不见的,在运行的时候绑定计算出来的内存地址。