一、多态的含义
多态顾名思义就是多种形态。指当给某个对象发消息的时候,这个对象可以自行决定采用哪种行为来响应这个消息,在具体的使用中构成多态的3个条件分别是封装、继承和向上转型(在笔者上一篇文章中对向上转型作了比较详细的阐述)。
二、多态的实现
多态可以有效的提高代码的可重用性以及降低模块之间的耦合度。用行话来说这种依赖关系就叫:高内聚,低耦合。这是什么意思呢?我们通过下面的例子来给出解释。
package demo;
//父类(抽象类)
public class Animal {
void eat() {
System.out.println("Animal needs to eat.");
}
void shout() {
System.out.println("Animal can shout!");
}
}
//子类继承父类
public class Dog extends Animal{
//对父类eat方法的重写
void eat() {
//super.eat(); //这里如果没有注释指的是在子类的方法里直接调用父类的eat()方法
System.out.println("Dog likes to eat bone");
}
//对父类shout方法的重写
void shout() {
System.out.println("Dog shouts louder than other animals.");
}
void run() {
System.out.println("running!");
}
}
package demo;
public class main {
public static void main(String[] args) {
Animal a = new Dog(); //向上转型,将子类的实例化对象赋值给父类对象,寓意为狗是一只动物
a.eat(); //这里调用的eat()是Dog类重写之后的方法
a.shout(); //这里调用的shout()是Dog类重写之后的方法
a.run(); //ERROR! run()是Dog类特有的方法,Animal类中没有这个方法,此时的对象是动物,不
//是狗,动物是宽泛的概念不能狭义化为狗,不能调用Dog的方法是合乎逻辑的
Dog dog = (Dog) a; //向下转型,此时的Animal对象已被强制转换为Dog,故可以调用狗特有的方法
dog.run(); //可以成功调用,输出“running”
}
}
在上面这个例子中我们可以看出子类Dog实现了对父类的继承、重写,以及在main方法中实现了向上转型,这就是多态的3个必要条件的实现。而如果这里还有一个叫Cat的类也继承了Animal,那么Animal的代码就可以被重复利用到,提高了代码的利用率。且不同的类继承了父类之后可以分别实现自己相关的功能,将各个模块之间的耦合度降低,避免因为某一部分代码的修改导致大量返工的情况出现。
三、抽象类和抽象方法的使用
抽象类是上述的子类继承父类功能的一种更加具体的表现方式,这里的父类更加的抽象,使用了abstract作为类的关键字,或者说一个类中只要有抽象方法,那么这个类就一定事抽象类。使用方法和上面是类似的,唯一的不同就是抽象类中不能实现抽象方法,但是当方法不是抽象方法(方法前面没有abstract关键字)时仍然可以像普通的类那样对方法进行定义。并且,抽象类也能使用向上转型和向下转型。
package demo;
//含有抽象方法的类一定是抽象类
public abstract class Shape {
String name = "shape"; //非抽象成员变量仍然可以正常赋值
abstract double area(); //不能在类中实现抽象方法
void say() {
System.out.println("hehe");
}
}
//子类(必须要实现抽象类中的抽象方法)
public class Rectangle extends Shape{
String name ="矩形";
double longSide;
double shortSide;
//构造方法
public Rectangle(double Longside,double ShortSide) {
this.longSide = Longside;
this.shortSide = ShortSide;
}
//对Shape中的抽象方法进行实现,这里如果没有对area()方法进行实现就会报错
double area() {
return longSide*shortSide;
}
}
package demo;
public class main {
public static void main(String[] args) {
Shape sh = new Shape(); //ERROR! 抽象类不能直接实例化对象,除非添加匿名内部类来实现其中
//的抽象方法
Shape sh = new Rectangle(3, 5); //仍然可以实现向上转型
System.out.println(sh.area());
Rectangle re = (Rectangle) sh; //仍然可以实现向下转型
}
}
小结:抽象类的使用和一般的子类继承父类是相似的,唯一的区别就是,抽象类中的抽象方法在子类中时必须要实现的。如果你需要在主方法中实例化抽象类的对象那么就要通过内部类或者匿名内部类实现抽象类中的所有抽象方法才可以实例化抽象类的对象。同时,值得注意的是抽象类同样可以使用向上、下转型,也是多态的一种重要体现。