类与接口(五)java多态、方法重写、隐藏

白诗秀儿 关注

收藏于 : 2018-06-01 18:18   被转藏 : 1   

点击上方蓝字关注“好好学java”,添加微信号:sihailoveyan,拉你入微信群,或者加入QQ群:766946816,每日收获不一样的java知识。

 精彩内容 

 

精选java等全套视频教程

精选java电子图书

大数据视频教程精选

java项目练习精选

一、Java多态性

面向对象的三大特性:封装、继承、多态。

多态的类型,分为以下两种

  • 编译时多态: 指的是 方法重载。编译时多态是在编译时确定调用处选择那个重载方法,所以也叫 静态多态,算不上真正的多态。所以,一般说的多态都是运行时的多态。

  • 运行时多态: 由于 方法重写,所以想要确定引用变量所调用的方法的入口,必须根据运行时的引用变量所指向的实例对象来确定。从而使得同一个引用变量调用同一个方法,但不同的实例对象表现出不同的行为。再简单点来说,就是在运行时,可以通过指向基类的指针,来调用实现子类中的方法。

下面讲的多态都是指 运行时的多态。

多态的定义: 指允许不同类的对象对同一消息做出不同的响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用);

上面的定义参考了网上的说法,定义中的不同类,都是由同一个基类扩展而来。

多态的好处:

  • 可替换性(substitutability)。多态对已存在代码具有可替换性。例如,draw函数对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

  • 可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。

  • 接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。

  • 灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。

  • 简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

java的多态性三要素:

  • 继承;

  • 重写;

  • 父类的引用指向子类的引用

多态性的实现: 依靠动态绑定;

绑定: 将一个方法调用与方法主体关联起来。
前期绑定: 在程序执行前绑定,由编译器和链接程序完成,C语言的函数调用便是前期绑定。
动态绑定: 也称 后期绑定。在运行时,根据具体的对象类型进行方法调用绑定。除了static方法、final方法(private方法也是final方法),其他方法都是动态绑定;

二、方法重写 与 隐藏

方法重写: 就是子类中覆盖了从父类继承下来的方法(不是所有的父类方法都可以覆盖),从而使得通过父类的引用来调用重写后的方法。也就是说,父类类型与子类类型只保留重写后的方法。

隐藏: 覆盖是相对重写而言的。当子类中出现与父类相同的方法时,重写是子类与父类只保持一份,但方法隐藏则是子类与父类各自独立保持一份,也就两份。从父类继承下来的成员中,除了部分方法是可以重写外,其余成员都是隐藏,如变量、内部类、静态方法等。

注意: final方法既不能重写,也不能隐藏。

class ParentClass{
   public int a = 5;
   protected final String name = "parentClass";
   public final void finalMethod() {//final方法,子类既不能重写,也不能隐藏
       System.out.println("final方法");
   }
   public static void monday() {//静态方法
       System.out.println("父类ParentClass的monday()方法");
   }
   public void count() {//可继承的成员方法
       System.out.println("父类ParentClass的count()方法");
   }
   class InnerClass{//内部类
       public InnerClass() {
           System.out.println("父类ParentClass的内部类");
       }
   }
}
class ChildClass extends ParentClass{
   public int a = 5;
   protected final String name = "ChildClass";
   /*//编译不通过
    * public final void finalMethod() {
       System.out.println("final方法");
   }*/

   public static void monday() {//静态方法
       System.out.println("子类ChildClass的monday()方法");
   }
   public void count() {//可继承的成员方法
       System.out.println("子类ChildClass的count()方法");
   }
   class InnerClass{//内部类
       public InnerClass() {
           System.out.println("子类ChildClass的内部类");
       }
   }  
}
public class MyTest {
   public static void main(String[] args) {
       ChildClass child = new ChildClass2();
       ParentClass parent = child; //类型上转
       System.out.println("---------------变量的隐藏测试-----------------");
       child.a = 10;
       System.out.println("parent.a: "+parent.a);
       System.out.println("child.a: "+child.a);
       System.out.println("\n---------------静态方法的隐藏测试-----------------");
       parent.monday();
       child.monday();
       System.out.println("\n---------------方法的重写测试-----------------");
       parent.count();
       child.count();
       System.out.println("\n---------------内部类的隐藏测试-----------------");
       ParentClass.InnerClass pa = parent.new InnerClass();
       ChildClass.InnerClass ch = child.new InnerClass();
   }
}

---------------变量的隐藏测试-----------------
   parent.a: 5
   child.a: 10
---------------静态方法的隐藏测试-----------------
   父类ParentClass的monday()方法
   子类ChildClass的monday()方法
---------------方法的重写测试-----------------
   子类ChildClass的count()方法
   子类ChildClass的count()方法
--------------内部类的隐藏测试-----------------
   父类ParentClass的内部类
   子类ChildClass的内部类

上面的例子中,只有count()方法是被重写了,父类类型与子类类型只保持重写后的方法,而其他成员都是隐藏,父类类型保持一份,子类类型也保持一份。
方法重写的条件

  • 重写的方法是子类从父类继承下来的实例方法,不能是静态方法

  • 子类重写后的方法的 返回类型 必须是 原父类方法的返回类型的可替换类型

  • 子类重写后的方法的访问权限 不能比 原父类方法的访问权限低;

  • 子类重写后的方不能比父类方法抛出更多的异常;

  • 当重写泛型方法时,先进行类型擦除。再按照上面的4个小点,重写类型擦除后的方法;

可替换类型补充:

  • 对于返回类型是基本类型、void,重写方法的返回类型必须是一样;

  • 对于返回类型是引用类型,返回类型可替换成该类型的 子类型;

class ParentClass{//父类
   public int count() {//
       return 0;
   }
   Object method() {
       return "aa";
   }
   <T extends ParentClass> T getValue(T t) {//泛型方法
       System.out.println();
       return t;
   }
}
class ChildClass extends ParentClass{//子类
   public int count() {//重写count()方法,由于返回类型是基本类型,不能变,必须是一致
       return 0;
   }
   public String method() {//重写method():访问权限增大,返回类型是Object的子类String
       return "aa";
   }
   ChildClass getValue(ParentClass ch) {//重写泛型方法getValue()
       return null;
   }
}

解析一下此例子中的泛型方法重写,父类中的泛型方法getValue()进行类型擦除后,是:

ParentClass getValue(ParentClass t){
   return null;
}

所以,子类ChildClass的方法重写是合理的。

04
/
19

征求意见/Advice

首先,非常感谢大家的支持,公众号从零开始,2个月左右也逐渐的有了许多的粉丝,我也很愿意分享个人的学习的经验与优质的学习教程,同时,也更加的愿意和大家成为朋友,说不定以后还一起工作呢,哈哈。这两个月,也一直发了许多的文章,不知道小伙伴们到底都需要什么样的文章,或者想再深入的学习什么样的知识,前面发的大部分是基础的知识,对于java的框架,ssh、ssm、javaee知识没有涉及。我目前的想法是,可能有许多的小伙伴都是基础阶段的,可能最近的一些文章有些难懂(集合源码解析),所以暂时还是先每天分享一篇基础的文章(java集合基础、java io基础、java多线程基础)、面试题库基础算法练习,层层深入。如果小伙伴们有什么意见,希望大家可以在留言区或私信积极的给出意见,在这里谢谢大家的支持了。


回复以下关键字获取更多学习资源

java基础|html5|css|js|jquery|angularJs|ajax|node.js|javaEE基础| |struts2|hibernate|spring|svn|maven|springmvc|mybatis|linux|oracle| |luncene|solr|redis|springboot|架构师资源|dubbo|php|webservice|c++基础|nginx|mysql|sqlserver|asp.net

更多学习资源逐步更新,请置顶公众号不要错过更新


好好学java
每日推送java优质文章、视频教程、热点资讯
微信ID:SIHAI0911
长按左侧二维码关注



 阅读文章全部内容  
点击查看
文章点评
相关文章
白诗秀儿 关注

文章收藏:1308

TA的最新收藏