在复习过程中,LSP原则是个很重要的内容。这里先给出LSP原则的定义。

LSP定义
Functions that use pointers or referrnces to base classes must be able to use objects of derived classes without knowing
it.(所有引用基类的地方必须能透明地使用其子类的对象。)

这个的主要作用就是规范继承时子类的一些书写规则。其主要目的就是保持父类方法不被覆盖。

也就是所有引用父类的地方,替换子类进去,不会有任何影响。

子类必须完全实现父类的方法
子类可以有自己的个性
覆盖或实现父类的方法时输入参数可以被放大
覆盖或实现父类的方法时输出结果可以被缩小

LSP是子类型关系的一个特殊定义,称为(强)行为子类型化。在编程语言中,LSP依赖于以下限制:
前置条件不能强化
后置条件不能弱化
不变量要保持或增强
子类型方法参数:逆变
子类型方法的返回值:协变
异常类型:协变

这里出现了两个生词:协变和逆变。本篇文章主要说一下这俩是啥。

逆变与协变综述:如果A、B表示类型,f(⋅)表示类型转换,≤表示继承关系(比如,A≤B表示A是由B派生出来的子类):

f(⋅)是逆变(contravariant)的,当A≤B时有f(B)≤f(A)成立;
f(⋅)是协变(covariant)的,当A≤B时有f(A)≤f(B)成立;
f(⋅)是不变(invariant)的,当A≤B时上述两个式子均不成立,即f(A)与f(B)相互之间没有继承关系。

协变(Co-variance)
  父类型->子类型:越来越具体(specific)。
  在LSP中,返回值和异常的类型:不变或变得更具体 。

逆变(Contra-variance)

  父类型->子类型:越来越抽象。

  参数类型:要相反的变化,不变或越来越抽象。

来看一下应用:

数组是协变的:一个数组A[ ] ,可能包含了A类型的实例或者A的任何子类型的实例

1 Number[] numbers = new Number[2];
2 numbers[0] = new Integer(10);
3 numbers[1] = new Double(3.14);
4
5 Integer[] myInts = {1,2,3,4};
6 Number[] myNumber = myInts;
7
8 myNumber[0] = 3.14; //run-time error!

第8行会报错的原因是myNumber指向的是一个Integer[] 而不是Number[],对Interger赋值一个double类型的,不是协变

其实在继承中只需要注意LSP原则即可,这是不矛盾的。

对于参数,也就是前置条件,应当逆变,把前置条件范围放宽。

对于返回值,也就是后置条件,应当协变,把后置条件范围缩小。

这两者加起来,也就是规约变强,符合LSP。

LSP原则中的逆变和协变的更多相关文章

  1. Java中的逆变与协变

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  2. Java中的逆变与协变(转)

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  3. Java中的逆变与协变 专题

    结论先行: PECS总结: 要从泛型类取数据时,用extends: 协变 要往泛型类写数据时,用super: 逆变 既要取又要写,就不用通配符(即extends与super都不用) 不变 List&l ...

  4. OOP中的逆变和协变

    逆变和协变在存在于强类型语言中,尽管非常少提及.可是里面蕴含了面向对象的世界观.感谢和我一起讨论这个问题的人. 这里用了C#.Scala的语法作为演示样例.事实上逆变和协变的概念跟语言本身关系不大.事 ...

  5. C#中的逆变和协变

    msdn 解释如下: “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型. “逆变”则是指能够使用派生程度更小的类型. 解释的很正确,大致就是这样,不过不够直白. 直白的理解: “协变” ...

  6. Java中的逆变与协变 很直接不饶弯的讲出来了

    ```java 协变 extends只能new 辈分比自己低的家伙 List<? extends Number> list001 = new ArrayList<Integer> ...

  7. Java 逆变与协变的名词说明

    最近在研究Thinking in Java的时候,感觉逆变与协变有点绕,特意整理一下,方便后人.我参考于Java中的逆变与协变,但是该作者整理的稍微有点过于概念化,我在这里简单的说一下 我对于协变于逆 ...

  8. Java 逆变与协变

    最近一直忙于学习模电.数电,搞得头晕脑胀,难得今天晚上挤出一些时间来分析一下Java中的逆变.协变.Java早于C#引入逆变.协变,两者在与C#稍有不同,Java中的逆变.协变引入早于C#,故在形式没 ...

  9. .NET Core CSharp初级篇 1-8泛型、逆变与协变

    .NET Core CSharp初级篇 1-8 本节内容为泛型 为什么需要泛型 泛型是一个非常有趣的东西,他的出现对于减少代码复用率有了很大的帮助.比如说遇到两个模块的功能非常相似,只是一个是处理in ...

  10. .NET 4.0中的泛型逆变和协变

    转载自:http://www.cnblogs.com/Ninputer/archive/2008/11/22/generic_covariant.html:自己加了一些理解 随Visual Studi ...

随机推荐

  1. 实验1task1

      <实验结论> #include <stdio.h> #include <stdlib.h> int main() { printf(" O \n&qu ...

  2. thirty-one

    动态组件 动态切换组件的显示和隐藏 如何实现动态组件的渲染 vue提供了有一个内置的<component>组件,专门用来实现动态组件的渲染.示例代码如下: 使用keep-alive保持状态 ...

  3. comment out one line in the file with sed

    sed -i "/test2/s/^/#/" test.log https://jaminzhang.github.io/linux/sed-command-usage-summa ...

  4. history 添加 时间戳和ip,用户

    vim  /etc/profile 在文件最后加入 HISTFILESIZE=4000 # 默认保存命令是1000条,这里修改为4000条 HISTSIZE=4000 USER_IP=`who -u ...

  5. C#中检测代码执行时间

    使用System.Diagnostics.Stopwatch, using System; using System.Diagnostics; using System.Threading; clas ...

  6. 查看Windows操作系统编码方式

    chcp 编码表: 代码页 国家(地区)或语言 437 美国 708 阿拉伯文(ASMO 708)720 阿拉伯文(DOS)850 多语言(拉丁文 I) 852 中欧(DOS) - 斯拉夫语(拉丁文 ...

  7. WPF窗体图标设置

    WPF程序在编写结束后,界面没有图标,影响美观性.今天在添加图标的时候,一直报错,然后通过查找资料,将这个问题解决,现在将主要步骤记录如下; 准备好图标文件,注意文件格式应该为ico格式文件.有一个在 ...

  8. 解决QtCreator运行程序报plugin xcb的错误

    解决方法:将对应项目的运行环境的LD_LIBRARY_PATH中的qt的库路径移到最前面,如下图: LD_LIBRARY_PATH可以指定查找共享库的路径,将qt的共享库移到前面,可以优先使用qt的库

  9. ssh远程连接服务器

    远程连接服务器及压缩文件与解压 1 终端连接 ssh -p 端口号 用户名@地址 例如:ssh -p 80 name@host 每次远程连接,使用账号和密码登录,有可能使得端口被监听到,从而导致挖矿情 ...

  10. python pip的使用

    1.导出安装包 pip freeze > requirements.txt 2.安装requirements.txt文件中指定的扩展库:pip install -r requirement.tx ...