二、Java面向对象(9)_面向对象——多态思想

2018-05-02

 

多态思想

 

多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:

 

 

多态性是对象多种表现形式的体现。

现实中,比如我们按下 F1 键这个动作:

  • 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
  • 如果当前在 Word 下弹出的就是 Word 帮助;
  • 在 Windows 下弹出的就是 Windows 帮助和支持。

同一个事件发生在不同的对象上会产生不同的结果。

--------------------------------------------------------------------------------------------------

 

 比如你是一个酒神,对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒,从外面看我们是不可能知道这是些什么酒,只有喝了之后才能够猜出来是何种酒。你一喝,这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下:

      酒 a = 剑南春  //此时a表示剑南春类型的形态

      酒 b = 五粮液  //此时b表示剑南春类型的形态

      酒 c = 酒鬼酒  //此时c表示剑南春类型的形态

      …

      这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类,我们只是通过酒这一个父类就能够引用不同的子类,这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象

 

对象(a/b/c)具有两种类型:

  编译类型:声明变量的类型,酒

  运行类型:对象的真实类型,剑南春/五粮液/酒鬼酒

编译类型必须是运行类型的父类(向上转型)或者和运行类型相同(向下转型),多态就是编译类型是运行类型的父类(多态是怎样产生的)。

 

在上面的喝酒例子中,酒(Win)是父类,剑南春(JNC)、五粮液(WLY)、酒鬼酒(JGJ)是子类。我们定义如下代码:

      JNC a = new  JNC();

      对于这个代码我们非常容易理解无非就是实例化了一个剑南春的对象嘛!但是这样呢?

      Wine a = new JNC();

      在这里我们这样理解,这里定义了一个Wine 类型的a,它指向JNC对象实例。由于JNC是继承与Wine,所以JNC可以自动向上转型为Wine,所以a是可以指向JNC实例对象的。

   这样做存在一个非常大的好处,在继承中我们知道子类是父类的扩展,它可以提供比父类更加强大的功能,如果我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能。

----------------------------------------------------------------------------------------------------------------------------------------------------

 

多态的实现条件:

1、要有继承(类与类)或接口(接口和实现类)关系

2、子类要覆盖(重写)父类方法

3、父类引用指向子类对象(向上转型)

 

原则:当超(父)类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法(即由子类对象的类型决定调用谁的方法),

   但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

----------------------------------------------------------------------------------------------------------------------------------

 

多态的特点:

  父类引用指向子类对象,在运行时期会表现具体的子类特征。

  指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。

  如果子类重写了父类中的某些方法,在调用这些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。(即将会调用子类中的这些方法。)

  特殊情况:如果子类隐藏了父类中的某些方法,在调用这些方法的时候,将会调用父类中的这些方法。(隐藏就是子类和父类存在相同的静态的方法(使用static修饰),此时不叫覆盖)

 

参考:http://www.cnblogs.com/chenssy/p/3372798.html

 

 --------------------------------------------------------------------------------------------------------------------------------------

 

多态的优点:

当父类引用指向子类对象时,可以屏蔽不同子类对象的差异性,从而实现代码的可重用性。

-------------------------------------------------------------------------------

 

多态时的调用问题(本质就是前面所讲的多态的特点):

情况1:某方法存在于父类,而子类不存在,此时调用的是父类方法(由于有继承或接口和向上转型)。

情况2:子类某方法覆盖(重写)了父类方法,此时调用的是子类方法。

情况3:子类特有的方法,父类中并不存在此方法,此时编译错误。(这种情况并不满足多态的3个实现条件)

情况4:子类隐藏了父类的某些方法(子类和父类都存在此方法,但该方法为静态方法(使用static修饰),此时称之为隐藏而不是覆盖),此时调用的是父类方法。

 

不管是哪一种情况(情况4除外),父类引用指向子类对象时都是先从编译类型(父类)中寻找是否存在该方法,再去运行类型(子类)中寻找是否存在该方法。

如果,编译类型中不存在该方法,那么此时编译错误(情况3)。如果编译类型存在此方法,且运行类型不存在或运行类型存在,那么分别对应情况1和情况2。

 

静态方法的调用只需要使用类名调用即可,如果使用对象来调用静态方法,其实使用的是对象的编译类型来调用(情况4),通过反编译可以看到。(面试可能会考到)

静态是类级别的,多态是对象级别的。

-------------------------------------------------------------------------

 

字段不存在多态特征:

  通过对象调用字段,在编译时期就已经决定调用哪一块的内存空间的数据。

  字段不存在覆盖的概念,因此不能有多态的特征(在运行时期体现子类特征)。

  只有方法才有覆盖的概念。

  当子类和父类存在相同的字段,无论修饰符是什么(即使是private也不例外),都会在各自的内存空间存储数据。

 

 (其中 SuperClass是SubClass的父类)

 

posted @ 2018-05-02 11:48  sunNoI  阅读(239)  评论(0编辑  收藏  举报