关于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

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

                                                                   2015-01-02

  

时间: 2024-10-17 17:21:42

关于java可变(协变)返回类型的解说之一------------基类与派生类的相关文章

Java之协变返回类型详解(附源码)

前言 Java SE5中添加了协变返回类型,它表示在导出类中的被覆盖方法可以返回基类方法的返回类型的某种导出类型: 示例源码 package com.mufeng.theeighthchapter; class Grain { @Override public String toString() { // TODO Auto-generated method stub return "Grain"; } } class Wheat extends Grain { @Override p

Java协变返回类型

今天看到句话:“支持重写方法时返回协变类型”. 那么什么事协变类型?在网上找了找资料,大体上明白了. Java 5.0添加了对协变返回类型的支持,即子类覆盖(即重写)基类方法时,返回的类型可以是基类方法返回类型的子类.协变返回类型允许返回更为具体的类型.示例程序如下: 代码如下: import java.io.ByteArrayInputStream; import java.io.InputStream; class Base { //子类Derive将重写此方法,将返回类型设置为InputS

协变返回类型

java se5中添加了协变返回类型,他表示在到处类中的被覆盖方法可以返回基类方法的返回类型的某种导出类型 class Grain(){ public String toStinrg(){return "Grain";} } class Wheat extends Grain(){public String toString(){return "Wheat";} } calss Mill(){ Grain process(){return new Grain();}

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

Covariant Returen Types(协变返回类型)

基类virtual func返回类型为某个类(class Super)的ptr或ref,子类重写的virtual func返回类型可改为该类子类(class Sub : public Super)的ptr或ref. class Base { public: virtual Base* clone() const { return new Base(*this); } virtual ~Base() {} }; class Derived : public Base { public: virtu

协变、逆变与不变:数组、泛型、与返回类型

转自:http://blog.csdn.net/yi_Afly/article/details/52071260 1. 前言 之前几篇博文,有些地方涉及到了协变性.逆变性与不变性在Java中的表现,所以这篇博文将重点记录这方面的内容,并辅以JDK源码中的一些实例,加以说明. 2. 定义 这里讨论的协变.逆变与不变都是编程语言中的概念.下面介绍定义: 若类A是类B的子类,则记作A ≦ B.设有变换f(),若: 当A ≦ B时,有f(A)≦ f(B),则称变换f()具有协变性. 当A ≦ B时,有f

继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类。 (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法。 (3)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量不能被继承。 (4)子类中定义的成员方法,并且这个方法的名字返回类型,以及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承。 分析以上程

继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法.(3)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量不能被继承.(4)子类中定义的成员方法,并且这个方法的名字返回类型,以及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承. 分析以上程序示例,主要疑惑点是“子类继承父类的成员变量,父类对象是否会实例化?私有成员变量是否会被继承?被继承的成员变量

java方法重写返回值类型

重写(Overriding)(1) 父类与子类之间的多态性,对父类的函数进行重新定义.如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding).在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法.但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写.方法重写又称方法覆盖.(2)若子类中的方法与父类中的某一方法具有相同的方法名.返回类型和参数表,则新方法将覆盖原有的方法.如需父类中原有的方法,可使用super关键字

Java返回类型泛型的用法小结

Java返回类型泛型的用法小结 版权声明:本文为博主原创文章,未经博主允许不得转载. 关于Java泛型的基本用法就不多说了,主要是一个编译期的检查,也避免了我们代码中的强制转换,比较经典的用法有泛型DAO,泛型Page的DTO. 现在我要说的是一个挺有趣但是貌似还不是太多的人在代码中使用的方法,前段时间用guava和op4j的时候发现这样的用法,看看了源码,也是很简单的. 比如guava中创建集合的方法 List<xx> list = Lists.newArrayList(),这个代替了我们传