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

来源:互联网 发布:uv淘宝论坛 编辑:程序博客网 时间:2024/05/19 23:17

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


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


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


首先先从最基本的解起:


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


A a;//创建父类A对象的引用aa = 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







原创粉丝点击