一般说道多态,也离不开封装与继承。按我的理解,Java中的封装,就是把一些属性与方法打包成一个类,用来描述一个对象的状态与动作。Java中的继承,则是通过继承一个通用类来得到一个一个更具体的类。两者都是能帮助我们更好地进行建模的代码格式。
理解多态的概念也离不开封装与继承。多态的字面意思就是多种形式、多种形态。例如,几何图形可以是圆、三角形、矩形或任意不规则的图形。为了将这种抽象的关系体现在Java上,我们可以先定义一个几何图形的通用类,再通过继承得到圆、三角形这些子类。在使用过程中,不必先定义某一个子类引用,在把一个子类实例传递给它,因为每个子类的实例都是父类的特殊化,因此总是可以将子类的实例传给需要父类型的参数,大大提升了编程的灵活性。
class Animal { public void animalSound() { System.out.println("The animal makes a sound"); } } class Pig extends Animal { @Override public void animalSound() { System.out.println("The pig says: wee wee"); } } class Dog extends Animal { @Override public void animalSound() { System.out.println("The dog says: bow wow"); } }
下面用父类型引用来指向子类型实例
class Animal { public void animalSound() { System.out.println("The animal makes a sound"); } } class Pig extends Animal { public void animalSound() { System.out.println("The pig says: wee wee"); } public void display() { System.out.println("Pig"); } } class Dog extends Animal { public void animalSound() { System.out.println("The dog says: bow wow"); } } class Main { public static void main(String[] args) { Animal myAnimal = new Animal(); // Create a Animal object Animal myPig = new Pig(); // Create a Pig object Animal myDog = new Dog(); // Create a Dog object myAnimal.animalSound(); myPig.animalSound(); myDog.animalSound(); //myPig.display(); 编译错误 Pig p = (Pig)myPig; p.display(); } }
Java中,总是可以将一个子类的实例转换为一个父类的变量,称为向上转换(upcasting)。但要注意转换后的父类引用不能调用子类有而自身没有的方法,像上面的myPig.display()就会出现编译错误。为了解决这一问题,要用到向下转换(downcasting),也就是把父类实例转换为子类变量。这时必须用转换标记“(子类名)”进行显示转换,向编译器表明你的意图,于是就可以调用子类的特殊方法,结果如下
The animal makes a sound The pig says: wee wee The dog says: bow wow Pig
下面介绍一个多态的应用场景。假设有三次考试,每次的分数制都不一样,第一次采用五级计分制第二次采用两级计分制,第三次采用五级计分制。若要显示每次考试的成绩,如果采用一般的思路,要对三次考试分别建模,并编写不同的getScore方法,再分别调用。而在Java中,可以让这三次考试都继承自一个通用类(GradeActivity),并分别重写各自的getScore方法,最后用循环依此调用getScore方法,即使test中有上百个实例,每个实例的计分方法都不同,也可以用循环来实现。
public static void main(String[] args) { GradedActivity[] tests = new GradedActivity[3]; // 第一次考试采用五级计分制,考了75 tests[0] = new GradedActivity(); tests[0].setScore(75); // 第二次考试采用二级计分制(P或者F)。总共20题,每题分值相同,考生答错5题。 // 通过的最低分数线是60分 tests[1] = new PassFailExam(20, 5, 60); // 第三次是期末考试也采用五级计分制. 总共50题,每题分值相同,考试答错7题 tests[2] = new FinalExam(50, 7); // 显示每次考试的分数和等级 for(int i=0; i<tests.length; i++){ showValue(tests[i]); } } public static void showValue(GradedActivity exam){ System.out.println("Score: " + exam.getScore()+ "\t" + "Grade: " + exam.getGrade()); }
与其说多态是一种代码格式,不如说多态是一种写代码的技巧。能否利用好多态的机制取决于对需求的理解,如果能利用好其特性,能在实际的应用场景中减轻工作量,提升程序的灵活性。