多态性是面向对象编程一个至关重要的特性,这个性质可以很明显的降低类之间的耦合度,并且可以支持类的扩展,通过子类扩展现有的类可以不需要改变父类的内容,大大减少了代码的修改量。
举个例子,一个人养了很多动物,每天需要喂这些动物,那么程序可能是这样写的:
class Animal{
void eat(){}
}
class Cat extends Animal{
void eat(){
System.out.println("Cat eat");
}
}
class Dog extends Animal{
void eat(){
System.out.println("Dog eat");
}
}
class FeedMan{
void feedDog(Dog dog){
dog.eat();
}
void feedCat(Cat cat){
cat.eat();
}
}
public class test{
public static void main(String [] args){
Cat cat = new Cat();
Dog dog = new Dog();
FeedMan man = new FeedMan();
man.feedDog(cat);
man.feedCat(dog);
}
}
但是这样会有一个问题,如果哪一天又多出一种动物的话,那么FeedMan这个类里面又要加一种对应的喂的方法,这样的话,类之间的耦合度,利用多态这种特性可以降低,FeedMan这个类可以这样写:
class FeedMan{
void feed(Animal animal){
animal.eat();
}
}
public class test{
public static void main(String [] args){
Cat cat = new Cat();
Dog dog = new Dog();
FeedMan man = new FeedMan();
man.feed(cat);
man.feed(dog);
}
}
这样不管如何增加动物,都不需要改FeedMan这个类的代码,极大的降低了类之间的耦合度。
static方法和类的变量是不能覆盖的。覆盖的只是方法。
一个问题:
我们知道在一个对象的创建过程,是父类对象先建立,然后再建立子类,这样做的原因是子类的变量初始化可能会用到父类的变量,所以要先初始化父类对象。那么若是在父类的构造函数里面调用了子类的方法会怎么样?这时候子类对象还没有构建起来。
一般来讲,不太会这样,因为若要在父类里面调用子类的方法,首先就要在父类里面构造子类对象,像这样:
class A{
B b = new B();
A(){
}
}
class B extends A{
void draw(){
System.out.println("B");
}
}
这样首先就会出现递归定义对象的问题,从而导致栈满,出现错误。
因为要构造一个B就要先构造父类A,而A中又需要构造B,这样一直循环,最后栈满。
那有什么方法可以使得在父类构造函数里面调用子类的方法呢?利用多态。
下面这个例子:
class A{
A(){
draw();
}
void draw(){
System.out.println("A draw");
}
}
class B extends A{
void draw(){
System.out.println("B");
}
}
public class test{
public static void main(String [] s){
B b = new B();
}
}
这个例子的打印结果是B
因为在A的构造函数中调用了draw这个函数,但是draw这个函数被子类覆盖了,因此调用的是子类的draw。
在这种情况下,就会得到意想不到的情况,因此最好不要在构造函数里面调用非static和非final的方法。