zoukankan      html  css  js  c++  java
  • 关于java可变(协变)返回类型的解说之一------------基类与派生类

      在java代码中,人们惯性的认为一个方法中只能返回一种返回值或者无返回。博主在做开发过程中碰到了这样一种情况,安卓客户端请求数据,后台可能返回两种结果(1)访问令牌失效,无数据返回。(2)正常获取数据。

      这样的情况下需要根据访问令牌标识来判断是否有数据返回。当无效时返回用户重新登录提示,正常时则返回数据。显然,返回的结果有两种,那么一个方法里面只能返回一种类型的禁锢使得开发起来略显笨拙。使得开发起来相当难受。

      思考良久,又结合C++协变返回类型的启发。摘抄原文中的一句话:在C++中,只要原来的返回类型是指向类的指针或引用,新的返回类型是指向派生类的指针或引用,覆盖的方法就可以改变返回类型。这样的类型称为协变返回类型(Covariant returns type).

      因为java里面有没有指针,所以无法做到以上的功能。但是派生类是包含父类的共有方法和保护方法的。再根据里氏代换原则(任何基类可以出现的地方,子类一定可以出现),那么凡是派生类包含的基类属性,基类一定包含,这样的话情况会好很多。那么只要由派生类设置属性返回到基类中,基类方法一定能操作这些属性。那么一条完整的可变返回类型就可以建立起来。下面结合代码来验证:

      首先先定义两个实体类,代码如下,

      

     1 class Person {
     2     /** 假设每个人都有一个名字 **/
     3     String name;
     4 
     5     public String getName() {
     6         return name;
     7     }
     8 
     9     public void setName(String name) {
    10         this.name = name;
    11     }
    12 
    13 }// person
    14 
    15 class SuperMan extends Person {
    16     /** 假设每个超人都有身高 **/
    17     int height;
    18 
    19     public int getHeight() {
    20         return height;
    21     }
    22 
    23     public void setHeight(int height) {
    24         this.height = height;
    25     }
    26 }// SuperMan

      SuperMan类继承Person类(博主当时想不出来什么好东西了- -!),则SuperMan类包含name和height两个属性,基类Person只包含name属性。

      先说明一下普通的操作方式,以此作为对比。代码如下:

      

    1 public static Person getPerson1() {
    2         Person person = new Person();
    3         person.setName("无语");
    4         return person;
    5     }
    1 public static SuperMan getSuperMan1() {
    2         SuperMan man = new SuperMan();
    3         man.setName("不知道");
    4         man.setHeight(120);
    5         return man;
    6     }

      很简单,返回值就是预期的返回类型,但是如果把返回类型替换一下结果如何。如下所示:

      

    1 public static SuperMan getSuperMan() {
    2         Person person = new SuperMan();
    3         person.setName("小虎");
    4         return (SuperMan) person;
    5     }

      以上只能得到Superman的name属性无法得到height属性,如果在返回之前强转以此加上height属性后返回即可得到一个完整的SuperMan对象。这里不再尝试,读者自行处理。

      

    1 public static Person getPerson() {
    2         SuperMan man = new SuperMan();
    3         man.setHeight(100);
    4         man.setName("大明");
    5         return man;
    6     }

      以上代码就是此文章的核心,也是解决文章开头问题的核心。怎么操作呢?

      我们写两个类,ErroMessage和DataMessage类,其中ErroMessage是基类,DataMessage继承基类。ErroMessage包含erroMessage属性类型为private,DataMessage包含data属性。那么ErroMessage就只包含erroMessage属性,操作时只会引起erroMessage的变化,而不会引起data的变化。而操作DataMessage类时只能操作data属性。而在一个方法中,只要保持方法类型为ErroMessage,返回时就可以根据需要来返回相应的类型。这样使用方法时,用派生类得到所有属性,如果子类属性为空,那么基类属性一定不为空。如果派生类属性不为空,那么基类属性一定为空。这样就可以按需取得相应的数据。操作起来相当简单。代码操作如下:

      

    1 printDivider("person");
    2         Person person = getPerson();
    3         System.out.println("person的名字是" + person.getName());
    4         SuperMan superMan = (SuperMan) person;
    5         System.out.println("通过强转获取到的超人高度是这样的" + superMan.getHeight());

      以上就是博主对可变返回类型的理解。

      其中核心思想是这样的:派生类可以包含基类的共有属性,那么基类一定能从派生类获取到自身暴露给派生类属性的值。这是一种逆向思维方式,可能有悖于传统代码编写方式,但是做软件就是应该尝试打破传统思维,纵使道路崎岖不堪。如果有错误的话,还望各位读者提出指正批评意见,共同成长。

      最后博主写了一个小demo,下载地址是:http://download.csdn.net/detail/tianqianya/8321397

      下一次则将说明接口的可变返回类型。敬请期待~  ^_^

      QQ群号433409373 ->老夫在此等候小伙伴一起学习探讨交流~~~共建学习平台                                                                 

      

    史上最难学的计算机技术,没有之一
  • 相关阅读:
    微信小程序开发之选项卡
    sublime text3安装cssrem 插件步骤
    我的第二个Vue项目
    node下载指定版本
    我的第一个vue项目构建
    js实现二级月日联动菜单
    webStrom设置打开默认浏览器
    html-webpack-plugin Configuration配置信息
    webpack html-webpack-plugin 遍历
    git使用笔记
  • 原文地址:https://www.cnblogs.com/sanra/p/4198939.html
Copyright © 2011-2022 走看看