Java多态——向上转型与向下转型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/EchoYY/article/details/74499426

Java的转型之前一直处于似是而非的状态。


其中尤其是向上转型,大概意思谁不懂啊,A  a  =  new  B()  嘛,然而往细了抠就有点蒙蔽,尤其是面对考卷里出现的那种贼JB恶心的多态题,简直要哭了。


翻阅了几篇大佬们写的博客,整理一下思路总结如下。


首先先从最基本的解起:


向上转型即A a = new B()  也就是父类的引用指向了子类的对象


A a;	//创建父类A对象的引用a
a = new B()	//new了一个子类对象B被父类的引用a所指向

这也就是向上转型,此时a指向了一个子类的对象


由于父类引用a指向了子类的对象B,因此可以有B b = (B)a,因为a已经指向了子类所以可以强转成B


但如果引用a指向的是正常的父类对象A,也就是 A a = new A();那么对于B b = (B) a;会运行出错;


这是因为对于第一个例子而言子类的引用当然可以指向子类的对象,而对于第二个例子而言子类的对象妄图去指向父类的对象,越俎代庖?


有了最基本的转型的概念,下面举一个向上转型的小例子:


public class Animal {  
      
    public void eat(){  
        System.out.println("animal eatting...");  
    }  
}  
class Bird extends Animal{  
      
    public void eat(){  
        System.out.println("bird eatting...");  
    }  
      
    public void fly(){  
          
        System.out.println("bird flying...");  
    }  
}  
class Main{  
      
    public static void main(String[] args) {  
          
        Animal b=new Bird(); //向上转型  
        b.eat();   
        //! error: b.fly(); b虽指向子类对象,但此时丢失fly()方法  
    } 
}
结果是bird eatting...


这里子类Birl继承了父类Animal方法同时重写了父类的方法eat(),main方法里父类的引用b指向了子类bird对象因此调用的eat方法是子类的eat方法

而fly方法是子类特有的方法,对应变量b而言由于是父类的引用并不认识子类特有的方法,所以b.fly会报错


简而言之 b实际指向的是子类,因此会调用子类本身的方法。同时向上转型时引用变量b会遗失除与父类对象共有的其他方法,因此fly()不为b所识别。


上面举个向上转型的小例子帮助了解,那么在实际项目中有什么用处呢?


个人感觉提高了代码的复用性,举个小例子;

public class Human {  
    public void sleep() {  
        System.out.println("Human sleep..");  
    }  
}  
class Male extends Human {  
    @Override  
    public void sleep() {  
        System.out.println("Male sleep..");  
    }  
}  
class Female extends Human {  
    @Override  
    public void sleep() {  
        System.out.println("Female sleep..");  
    }  
} 
class Main{  
      
    public static void main(String[] args) {  
          
        dosleep(new Male());  		//传入的参数是子类
        dosleep(new Female());  
    }  
  
    public static void dosleep(Human h) {   		//方法里的参数是父类
        h.sleep();  
    }  
}  
结果:Male sleep…
Female sleep…


为什么说传入的参数是子类的对象而方法里的参数是父类引用呢,是因为只有这样才是向上转型所对应的

Human h = new Male();  Human h = new Female();


可以看到,由于使用的向上转型,那么Main类里只需要一个dosleep方法即可,程序会根据传入的参数自动去调用对应的子类方法。


一般在大型项目开发中,往往是多个类实现了同一个接口或继承同一个父类,如果说不使用向上转型,那么也就是子类每有一个父类方法在父类中都需要书写一个方法

这样会造成整个项目的冗杂,而采用转型的概念后,父类或者接口中只需要有一个方法即可,这样会使上层逻辑抽象,独立清晰方便以后扩展。


结尾在分析一下博客里出现很多的恶心例子来巩固一下

public class A {  
    public String show(D obj) {  
        return ("A and D");  
    }  
  
    public String show(A obj) {  
        return ("A and A");  
    }   
  
}  
  
public class B extends A{  
    public String show(B obj){  
        return ("B and B");  
    }  
      
    public String show(A obj){  
        return ("B and A");  
    }   
}  
  
public class C extends B{  
  
}  
  
public class D extends B{  
  
}  
  
public class Test {  
    public static void main(String[] args) {  
        A a1 = new A();  
        A a2 = new B();  
        B b = new B();  
        C c = new C();  
        D d = new D();  
          
        System.out.println("1--" + a1.show(b));  
        System.out.println("2--" + a1.show(c));  
        System.out.println("3--" + a1.show(d));  
        System.out.println("4--" + a2.show(b));  
        System.out.println("5--" + a2.show(c));  
        System.out.println("6--" + a2.show(d));  
        System.out.println("7--" + b.show(b));  
        System.out.println("8--" + b.show(c));  
        System.out.println("9--" + b.show(d));        
    }  
}  
结果

1--A and A  
2--A and A  
3--A and D  
4--B and A  
5--B and A  
6--A and D  
7--B and B  
8--B and B  
9--A and D  


这个恶心的例子应该不止一次看到,我也来掺一脚给一下我自己的解法

对于前三个而言均是a1的方法调用,变量a1是直接指向对象A的,即最常见的A a = new A()的情况,那么可能的答案就只有A and A 和 A and D两种

对于前两个参数分别是b和c,在A的两个方法里没有直接的指向,因此想到C继承B继承A,所以输出结果既是A and A

对于第三个参数是d,在A中有明确的方法,因此输出A and D (这个应该是最不会出错的)


对于4~6而言均是a2的方法调用,变量a2是父类的引用指向子类对象B,参考前文在转型的过程中会遗失方法show(B obj),又由于方法show(A obj)继承自父类A

因此可能的答案只有B and A 和 A and D两种

所以对于第四个和第五个的参数b和c,由于方法show(B obj)遗失了,因此只能找到最近的show(A obj),又由于这个方法被子类所重写,因此输出的是子类方法中的B and A而非父类的A and A

对于第六个参数是d ,在父类中有该方法,因此输出A and D

对于7~9而言均是b的方法调用,变量b指向的是子类B的对象,而子类B继承了父类A,因此可能的答案为B and B ,B and A ,A and D,父类的A and A被重写了。

因此7~9的输出也不再有什么问题了。


参考博客:http://blog.csdn.net/thinkGhoster/article/details/2307001

    http://blog.csdn.net/mr_jj_lian/article/details/6860845







猜你喜欢

转载自blog.csdn.net/EchoYY/article/details/74499426
今日推荐