都说面向对象有三大特性:封装、继承、多态。前两个在 Python 中很常见,也一直再用,就不特别整理了。但是在多态这个地方就跟 Java 有点不同。我们仔细研究一下看看。
多态 Polymorphism 分为两种,编译时多态,就是函数重载啦(overload)注意与下面的 override 区别一下。还有一个是运行时多态,我们今天主要研究研究这个。
要想理解好多态,我们得先知道 emmm 很多事情,,,,让我一件一件来说。
1. 强制类型转换
首先就是 Java 中的类型转换,其实这个没啥可说的,只是需要注意一件事情,类型转换数据本身没有变化。比如下面这段代码,变量 a 一直都是一个 char 类型的变量,只是将它暂时作为 int 型的变量使用一下。
class Hello{
public static void main(String [] args){
char a = 'a';
int num = a;
System.out.print(num);
}
}
2. 覆写
在继承关系中,子类如果定义了一个与父类方法完全相同(函数名、参数列表、返回值类型)的方法,被称为覆写(Override)。
注意与重载(Overload)进行区分,重载是指一个类中的两个方法函数名和返回值一样,但是参数列表不同。
另外:方法名相同,方法参数相同,但方法返回值不同,也是不同的方法。在Java程序中,出现这种情况,编译器会报错。
3. 程序绑定
绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来。分为静态绑定和动态绑定。
直接举个动态绑定的例子吧,比如说有人结婚邀请你家去参加婚礼,但是具体谁去还不一定,有可能是你妈妈,有可能是你,有可能是你妹妹,这要看当时你们家谁有空(说不定后来你们家来了个亲戚,婚礼的时候你们都没空,就让他去了)。要是静态绑定呢,指定是谁,就必须是谁,而且编译的时候这个人必须已经存在。
比如我对于静态绑定(像 C 语言),指定使用哪个对象就是哪个对象,指定哪个属性,这个属性就必须存在。
对于动态绑定(比如 Python 支持的动态绑定),调用一个对象的方法,如果这个方法里使用到了一个属性,但是我的这个类还没有这个属性,它是在运行过程中产生的。也不用管这个属性属于哪个对象,这个属性是啥时候才有的,只要在我执行这个方法的时候这个对象里面有我想要的属性就 ok 。
Java 是一个比较折衷的语言,java 当中的方法只有 final,static,private 和构造方法是静态绑定,剩下的都是动态绑定。
4. 上转型对象
然后就是上转型对象,简单点来说,上转型对象就是对象级别的强制类型转换。这是一个 引用变量的声明类型与其实际类型不符 的例子。
将子类对象赋值给一个父类的引用类型变量,(将子类理解为一个父类使用,没有转化!!)这个父类引用所指向的对象就叫上转型对象。

上转型对象的特点:
- 父类引用不能访问子类新增的成员(属性和方法);
- 父类引用访问父类中被隐藏属性时访问的是子类继承(父类)的属性。
- 父类引用调用被子类覆写的父类方法时调用的是子类覆写后的方法
(有没有想起来 C++ 中的虚函数)
上转型对象就是动态绑定的一个体现,比如在使用父类引用调用被子类重写的方法的时候,我不去管这个对象是哪个类的,只要里面有我要的方法就行,自然这样调用的就是被子类重写的方法。
我们先来看一个例子:
public class Area{
public static void main(String[] args){
Animal dog1 = new Dog();
dog1.run();
System.out.println(dog1.age);
}
}
class Animal{
public int age = 0;
public void run(){
System.out.println("动物跑。。。");
}
}
class Dog extends Animal{
public int age = 100;
@Override
public void run(){
System.out.println("狗跑。。。");
}
}
## 狗跑。。。
## 0
注意这个结果,方法可以被覆写,所以使用的是覆写之后的方法,但是属性没有覆写这一说,所以使用的就还是父类继承下来的属性。
还有在子类里面可以使用装饰器 @Override 标识一个覆写函数,这样解释器就可以帮我们检查是否真的是覆写。
不同的子类覆写的方式也不同,这样调用相同的父类方法,对于不同的子类,所得到的结果就不同,这就是多态的效果。
5. 多态
正如上文所说,多态就是 同样的行为(同一段代码)作用于不同对象时产生不同的效果。
多态想要解决的问题主要是:设计和实现的分离,这样修改设计,修改实现都非常容易。另外这样写的话代码量也会比较少,也比较容易阅读。
比如看下面这个代码:
public class TestPolymorphism{
public static void main(String [] args){
Dog dog = new Dog();
Cat cat = new Cat();
Bird bird = new Bird();
dog.saySomething();
cat.saySomething();
bird.saySomething();
}
}
class Dog{
public void saySomething(){
System.out.println("汪汪汪......");
}
}
class Cat{
public void saySomething(){
System.out.println("喵喵喵......");
}
}
class Bird{
public void saySomething(){
System.out.println("啾啾啾......");
}
}
这个例子太经典了....
下看一下使用多态的实现
class TestPolymorphism{
public static void animalSaySomthing(Animal an){
an.saySomething();
}
public static void main(String [] args){
Dog dog = new Dog();
Cat cat = new Cat();
Bird bird = new Bird();
animalSaySomthing(dog);
animalSaySomthing(cat);
animalSaySomthing(bird);
}
}
class Animal{
public void saySomething(){}
}
class Dog extends Animal{
public void saySomething(){
System.out.println("汪汪汪......");
}
}
class Cat extends Animal{
public void saySomething(){
System.out.println("喵喵喵......");
}
}
class Bird extends Animal{
public void saySomething(){
System.out.println("啾啾啾......");
}
}
当我们不光想要动物叫还想让他们做其他事情的时候,多态的好处就显现出来了,比如说我还想增加跑,吃,上树的方法,按照第一个的话那就需要为每一个都增加一个方法,然后每一个调用一遍,但是使用多态的话我们只需要在Animal 类中增加相应的接口,然后在子类中实现它。
额,,看到这里你一定会说这不是更麻烦了嘛,,,emmm,对于这个例子来说确实是这样,在实际生产环境中,也就是对于大型程序,多态主要是用在接口中,那个时候才能真正体现 Polymorphism 的作用。
网友评论