`

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     publicvoid setName(String name) {
10         this.name = name;
11     }
12 
13 }// person
14 
15 class SuperMan extends Person {
16     /** 假设每个超人都有身高 **/
17     int height;
18 
19     publicint getHeight() {
20         return height;
21     }
22 
23     publicvoid setHeight(int height) {
24         this.height = height;
25     }
26 }// SuperMan

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

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

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

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

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

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

1 publicstatic 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());

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

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

FROM:http://www.tuicool.com/articles/qUJFbi

分享到:
评论

相关推荐

    dotnet 5 从 IL 层面分析协变返回类型新特性.rar

    在开发过程中,协变返回类型可以提高代码的可重用性和灵活性。例如,在设计一个返回可枚举集合的方法时,可以声明为返回`IEnumerable<object>`,而实际返回的是`IEnumerable<string>`或`IEnumerable<int>`等更具体...

    java基础入门教程

    4 软 件 最 终 产 品 :用 Java 语 言 开 发 的 软 件 可 以 具 有 可视化 、 可 听 化 、 可 操作 化 的 效 果 ,这 要 比 电 视 、 电 影 的 效果 更 为 理 想 ,因 为 它 可 以做 到 "即 时 、 交 互、 动 画 与 ...

    java150 toC#

    2. 方法签名:Java的方法签名包括返回类型、方法名和参数列表,C#也是这样,但C#允许方法重载,可以根据不同的参数列表定义多个同名方法。 3. 注释:Java使用`//`和`/*...*/`进行单行和多行注释,C#则有`//`、`///`...

    java泛型的内部原理及更深应用

    7. **泛型方法**:除了泛型类,我们还可以定义泛型方法,方法的返回类型和参数列表可以包含类型参数。这增加了方法的灵活性,使得方法可以处理不同类型的参数。 8. **泛型与反射**:虽然泛型信息在运行时不存在,但...

    深入Java核心Java中多态的实现机制.pdf

    6. **返回类型**:多态方法的返回类型必须相同,或者返回类型之间存在协变关系(例如,父类类型可以作为子类类型的返回类型)。 7. **访问控制**:派生类的方法访问修饰符不能比基类更严格,这意味着如果基类方法是...

    Java重载.docx

    从Java 7开始,子类方法的返回类型可以是父类返回类型的派生类,这称为协变返回类型。 3. **访问修饰符**:重写方法的访问权限不能低于被重写方法。比如,如果父类方法是`public`,子类重写方法不能声明为`...

    JAVA 范例大全 光盘 资源

    实例96 方法改变(协变式返回类型) 251 实例97 静态导入 252 实例98 动物搭配(泛型) 253 实例99 人员信息(枚举类型) 256 实例100 printf()用法 260 实例101 使用ProcessBuilder调用外部命令 263 实例102 ...

    java采购管理系统源码-retrotranslator:Retrotranslator是使Java应用程序兼容Java1.4、Java1.3

    协变返回类型 格式化输出 静态导入 并发实用程序 集合框架增强 下载 () 并解压二进制分发文件Retrotranslator-_n.n.n_-bin.zip ,其中nnn是最新的 Retrotranslator 版本号。 使用 Java 5.0 或 Java 6 编译您的类并将...

    JAVA资格认证:SCJP310-055中文

    第一部分:声明、初始化、和作用域。... 定义并使用可变参数。正确重写和重载方法并识别方法合法的返回值,包括协变返回。  为类及层次类编写构造函数,知道默认构造函数的行为,实例化类及内部类

    java试题 (2).docx

    而`List<Integer>`不能赋值给`List<Number>`,因为泛型不支持协变。所以AD是正确答案。 5. 命名原则:好的命名应该具有表达力、具体、包含重要信息,但不应过长。所以ABC是正确答案。 **判断题解析:** 1. 接口中...

    effective-java:阅读《有效的Java》一书

    - **覆盖方法的注意事项**:避免在子类中改变方法的访问权限,抛出更宽泛的异常,或改变返回类型。 5. **泛型** - **类型安全的异构容器**:泛型提供了编译时类型检查,避免了强制类型转换。 - **协变与逆变**:...

    JavaGenerics

    然而,泛型方法的返回类型并不支持协变,只有参数类型支持逆变。 以上就是Java泛型的一些核心概念和使用技巧,掌握这些知识点有助于编写更加安全、可维护的代码。在实际开发中,灵活运用泛型可以提高代码质量,减少...

    20练习1

    从Java 5.0开始,重写方法的返回值可以是子类类型,这是协变返回类型。构造方法可以被重载,但不能被重写。 关于数据类型传递,Java总是按值传递,但对引用类型而言,实际上是传递了对象的引用地址,基本类型则是...

    理学继承接口与泛型PPT课件.pptx

    - Java 5.0以后,返回类型可以是父类类型的任何子类,这被称为协变返回类型。 5. **super关键字**: - `super`关键字用于引用父类的成员,包括变量和方法。 - 在构造方法中,`super(参数列表)`用于调用父类的...

    java8集合源码-OCP-Notes:OCP-Notes

    返回类型必须是协变的,即。 相同或更多限制(父返回的子类) 如果抛出任何受检异常,则只能抛出相同或更严格的异常。 未经检查的异常是免费游戏。 此外,可以跳过抛出相同的异常。 没有新的或更广泛的。 超载 不同...

    快学scala第一章习题答案.doc

    val 变量是不可变的,而 var 变量是可变的。 八、Scala 中的方法 Scala 语言支持多种方法,如实例方法、静态方法、扩展方法等。Scala 语言还提供了许多高级方法编程概念,如隐式转换、隐式参数等。 九、Scala 中...

    Kotlin学习参考笔记(先找到summary.md目录)

    - **变量声明**:Kotlin支持var(可变变量)和val(不可变变量)。例如,`var myVar = 10` 和 `val myVal = "Hello"`。 - **数据类型**:Kotlin有基本数据类型(如Int、Double、Boolean等)以及引用类型(类、接口...

    100家大公司笔试题汇总

    - `Sub`类重写了`Super`类的`getLenght()`方法,返回类型不同,但Java允许返回类型的协变。 - 输出结果为B. 4,5,因为`sooper`调用的是`Super`类的方法,而`sub`调用的是`Sub`类的方法。 5. Servlet处理请求方式...

Global site tag (gtag.js) - Google Analytics