1.多态的几个必要条件
1.有继承关系
2.有方法的重写
3.父类引用指向子类对象
2.多态中类成员的变现情况
父类:
class Father{
public int num = 10;
public String print(){
return "Father的print()方法!";
}
public static String staticprint(){
return "Father的staticprint()方法";
}
}
子类:
class Son extends Father{
public int num = 20;
public String print(){
return "Son的print()方法";
}
public static String statocprint(){
return "Son的staticprint()方法";
}
}
测试类:
public class Main {
public static void main(String[] args) {
Father f = new Son(); //父类引用指向子类对象
System.out.println("f的num值是:" + f.num);
System.out.println("f的print()调用输出是:" + f.print());
System.out.println("f的staticprint()调用输出是:" + f.staticprint());
}
}
测试类输出结果:
f的num值是:10
f的print()调用输出是:Son的print()方法
f的staticprint()调用输出是:Father的staticprint()方法
这里面涉及到子类父类中的成员变量,成员方法,与静态方法的关系,一一进行解释。
成员变量:
可以看到在成员变量中,如果一个引用是Father类型的,那么他在指向堆中对象的时候只能看到Father对象中的变量情况(num = 10),看不到Son对象中的变量情况(num = 20),因此输出f.num的时候输出的时输出的就是Father类中的num值。
成员方法:
在成员方法之中,父类引用指向子类对象之后,要访问成员方法的时候,编译的时候对象指向的是父类的方法区,但是运行的时候指向的是子类的方法区域。因此输出结果的时候输出的是子类的方法结果,但是因为编译的时候会指向父类的方法区,因此如果父类中没有print()这一方法,则程序在编译过程中就会报错!
静态方法:
静态方法,即可以用类名进行引用的方法,显而易见的取决于你的引用类型,该程序中引用类型是Father,因此输出的结果肯定是父类Father中的静态方法,与Father.staticprint()的输出结果是一致的。
总而言之,成员变量,成员方法与静态方法在多态中编译时与运行时候的关系就是:
(Father f = new Son())
成员变量:编译看左边(Father),运行看左边(Father);
成员方法:编译看左边(Father),运行看右边(Son);
静态方法:编译看左边(Father),运行看左边(Father);
3.多态中的向上转型和向下转型
Father f = new Son(); //父类引用指向子类对象
父类引用指向子类对象就是向上转型,即将当前的概念提升为一个更宽泛的概念。
但是现在的f只能使用Father中有的方法,但是如果我们需要使用Son中特有的方法呢?
就需要向下转型:
Son s = (Son)f;
即将f专为一个更加具体的类型。
通过了解向下转型和向上转型,就会发现多态的一个弊端,即不能直接使用子类特有的方法,必须得向下转型。
4.多态的好处和弊端
弊端:不能使用子类特有的属性和行为。
好处:提高了代码的可维护性(继承保证)和可扩展性(多态保证)。
提高维护性是指因为继承的特性,使得我们只需要对父类进行修改就可以影响到继承于它的所有子类。
可扩展性:
public class Main {
public static void main(String[] args) {
method(new Cat());
method(new Dog());
}
public static void method(Cat c){
c.eat();
}
}
class Animal{
public void eat(){
System.out.println("动物吃饭");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public void catchmouse(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃肉");
}
public void lookhome(){
System.out.println("看家");
}
}
显然以上代码method(new Dog());这个语句是错误的,因为method()方法中传入的参数是Cat类型的,而这一个句子传入的参数是Dog类型的,很明显我们并不能说狗是猫,因此我们如果也想用这种静态方法的方式来调用Dog中的eat()方法,一种方式就是在重新写一个method()方法:
public static void method(Dog d){
d.eat();
}
但是这样看上去就会显得代码十分的多于重复,为了两个类型定义两种方法,那如果有很多种类型的对象,我们就需要定义许多十分相似的方法,这显然是不允许的,因此我们可以使用多态,因为Dog和Cat的父类都是Animal,因此我们可以只使用以下一个方法即可:
public static void method(Animal a){
a.eat();
}
其实就是这个使用了多态的这两条语句:
Animal a = new Cat();
Animal a = new Dog();
这显然是合理的,也是一种更简洁的做法。这也是多态在实际操作中最经常被运用的情况。