HIT2022春软件构造课程——第三次博客发布

第四章到第八章

基本数据类型、对象数据类型

  1. 基本数据类型:
    • int
    • long
    • boolean
    • double
    • char
  2. 对象数据类型
    • Object
    • 常见的对象类型:String,BigInteger
  3. 基本类型和对象类型的特点比较
基本类型对象类型
一定不可变可以可变
在栈中分配在堆中分配
只有值除了值还有ID
代价低代价高

静态、动态类型检查

  1. 语言类型
    1. 静态类型语言
      • 所有的变量,根据声明和定义,在编译时类型可以确定的语言
    2. 动态类型语言
      • 在运行阶段进行类型检查
  2. 检查类型
    1. 静态检查:运行前自动的发现错误
      • 语法
      • 类名、函数名
      • 参数数目
      • 参数类型
      • 返回值类型
    2. 动态检查:运行时自动的发现错误
      • 非法参数值
      • 非法返回值
      • 数组越界
      • 访问空指针
  3. 总结
    • 静态检查是基于类型的检查,错误与变量实际数据无关
      因此静态检查无法检查出由于数值导致的而非类型导致的错误

    • 动态检查能够弥补静态检查的缺陷

    • 不论是动态类型语言还是静态类型语言都可以执行 两种 类型的检查

Mutable/Immutable

  1. immuntable(对象数据类型而言,不考虑基本类型)
    • 变量不可变:
      不能使用 赋值 语句改变 变量 指向的存储空间
      因此,每一次 使用= 进行 赋值 操作,都是新建了一个对象
      可以使用final关键字实现
    • 类型不可变:
      一旦不可变类型被创建,其数值不可改变
      即该对象类型没有可变方法或不支持可变操作
  2. mutable(只能是对象数据类型)
    • 存在改变引用内存数值的方法
    • 改变时不需要拷贝,可以提高效率,适合共享数据
    • 风险和应对方式:
      1. 可变函数参数:
        • 原因:当传入可变类作为参数时,该方法有可能修改这个可变类,导致出错
        • 方法:尽量不要在函数内修改参数,或者传入不可变对象
      2. 返回可变参数:
        • 原因:返回的可变类可能是类的成员变量,用户的修改行为会破坏RI
        • 方法:防御拷贝,返回不可变对象

Snapshot diagram

  • 是一种展示变量随时间变化的图示
    1. 基本类型的变量:使用 单实线 指向一个数据primitive

    2. 可变对象 的表示和改变:使用 单实线 指向 单实线圈
      在这里插入图片描述
      在这里插入图片描述

    3. 不可变对象 的表示和改变:使用 单实线 指向 双实线圈
      在这里插入图片描述

    4. final变量:使用 双线箭头
      在这里插入图片描述

Specification(前置/后置条件)

  • 规约由前置条件和后置条件组成,
    1. 若前置条件满足,则后置条件必须满足
    2. 前置条件不满足,可以做任何事情,推荐"快速失败"
    3. 在规约中使用不可变对象有利于减低复杂度
  • 前置条件:
    1. 对客户端的约束,在使用方法时必须满足的条件
    2. 关键字:requires
  • 后置条件
    1. 对开发者的约束,在方法结束时必须满足的条件
    2. 关键字:effects

行为等价性

  • 行为等价性 是规约的一种具体表现形式,如果两个实现符合规约,则等价

规约的强度

  1. S 2 ≥ S 1 S_2\geq S_1 S2S1: S 2 S_2 S2的前置条件弱于 S 1 S_1 S1的前置条件,后置条件相同
  2. S 2 ≥ S 1 S_2\geq S_1 S2S1: S 2 S_2 S2的后置条件强于 S 1 S_1 S1的前置条件,前置条件相同
  3. S 2 ≥ S 1 S_2\geq S_1 S2S1: S 2 S_2 S2的前置条件弱于 S 1 S_1 S1的前置条件 and 在满足前置条件的情况下, S 2 S_2 S2后置条件强于 S 1 S_1 S1的前置条件

ADT的四种操作类型

  1. Creators: 即构造方法,从无到有
    • public ClassName(parameter.../null)
  2. Producers: 从旧到新
    • public ClassName producer(parameter.../null)
  3. Observers: 只是取数据
    • public ImmutableType getElement()
  4. Mutators: 只有在mutable的ADT中才有,能够改变该ADT的数值
    • public Boolean/void setElement(parameter.../null)

表示独立性、表示泄露、不变量

  1. 表示独立性(Representation Independence):
    • RI定义为ADT的功能和使用与其内部的字段和算法(表示)无关这样一种性质
    • RI能够使得客户端在符合语法下使用ADT,实现者修改ADT的表示之后,客户端代码工作正常
    • RI是通过规约实现的,规约能够排除表示的因素,创造出client可以依赖的内容
  2. 不变量(Invariant)
    • ADT在运行的任何时候都能保持不变的一种属性,比如immutability
    • ADT的Invariants由ADT负责,与任何的client的行为都无关
  3. 表示泄露(representation exposure)
    • 例子:在类代码的外部能够直接修改类的字段
    • 表示泄露会破坏表示独立性,也会影响不变量,无法在不影响客户的情况下修改内部表示
  4. 总结
    • 不要将mutable参数包括到类中
    • 返回immutable或者mutable类的不可变视图。
    • 使用immutable

表示空间、抽象空间、AF、表示不变量

  1. 表示空间®:

    • 表示值构成的空间,即所有字段的所有可能值构成的空间。
      所有字段的笛卡尔乘积,例如一个类如下,则表示空间如下:
    public class Demo{
        private int a;
        private boolean b;
    }
    

    N ( i n t ) × N ( b o o l e a n ) N(int)\times N(boolean) N(int)×N(boolean)

    • 实现者可以直接修改表示空间
  2. 抽象空间(A):

    • 抽象值构成的空间,设计该ADT的所支持的抽象值
  3. 抽象函数(Abstract Function):

    • AF指如何将 表示空间 中的每一个值,解释为 抽象空间 的每一个值
    • AF一定是是满射,不一定是单射,所以必然存在 某些表示值 不能映射 成为 抽象目标值
  4. 表示不变量(Rep Invariant)

    • ADT的一个重要的不变量(Invariant),ADT在运行时,RI必须时刻为真
    • RI是一个 R − > B o o l e a n R->Boolean R>Boolean的一个映射函数, 当且仅当 r可以被AF映射为a 的时候为true
    • RI规定了哪些表示空间的数值可以映射为抽象空间
  5. 关系

    • R是定义域,A是值域,AF是一个映射函数
    • 相同的R,可以有不同的RI
    • 相同的R,RI,可以有不同的AF,映射成为不同的A
    • checkRep()方法使用assert进行RI的检查

注释撰写AF、RI、Safety from Rep Exposure

  1. AF
    • 明确的R到A的映射关系,使用自然语言即可
  2. RI:
    • 每一个field需要满足的限定条件
    • 多个field之间的关系的限定条件
  3. Safety from Rep Exposure
    • 检查各个字段是否私有
    • 检查处理字段的方法的参数,返回值
    • 证明代码未对外泄露自己的Rep
  4. Spec
    • 规约中 不能写 R空间和AF和RI的内容,只能写 A空间的数据
  5. 不变量的保证的标准
    • 使用creator和producers生成的时候保持true
    • 使用mutators和observer的时候保持true
    • 表示未泄露

接口、抽象类、具体类

  1. 接口
    • 传统的接口中只有方法的定义没有实现
    • java的接口中可以有 默认(default关键字)的实现,亦可以有成员变量
    • 接口可以被接口单继承,被类多实现
  2. 抽象类
    • 在普通类的基础上增加了抽象方法的类,一旦出现抽象方法,则该类必定是抽象类
    • 抽象类必须要使用关键字abstract修饰,抽象方法必须用abstract修饰
    • 抽象方法没有实现,只有定义
    • 不能实例化抽象类
  3. 具体类
    • 可以具体实例化的类
  4. 作用域
作用域当前类同一包内子孙类(不同包内)其他包
publicyesyesyesyes
protectyesyesyesno
defaultyesyesnono
privateyesnonono

继承(override)

  1. 继承
    • 用于实现抽象/具体类与抽象/具体类,接口与接口之间的复用修改关系,但是不能是普通类继承抽象类
    • 使用extend关键字进行继承,java只有单继承
  2. 重写
    • 在继承的时候,使用@Override记号,修改父类函数的情况
    • 重写的函数,完全相同的函数签名,包括函数名、参数类型列表、返回值
    • 返回值、可见性、异常,必须满足 LSP原则
    • 运行时 决定采用哪个函数

多态(overload)

  1. 多态
    • 函数重载
    • 泛型
    • 子类替换父类
  2. 重载
    • 多个方法(同一个类或者不同类)函数名字相同,但是 参数类型列表不相同 的情况
    • 返回值、可见性、异常,都是可以不同,但是如果只有这个不同则编译错误
    • 可以在 编译时,根据变量的 类型,决定函数的调用

泛型

  • 一个类或者接口声明了泛型变量,则是泛型,具体代码如下
class ClassName <T,E,..>{
    private T a;
    public  E b;
}

equals和==

  1. ==的引用等价性

    • 对于基本数据类型,两个变量 数值 相等
    • 对于对象数据类型,两个变量 地址 相等
  2. equals对象等价性

    • 基本数据类型没有equals
    • 对象数据类型的equals方法在没有被重写时是==
    • equals函数基本写法
    @Override
    public boolean equals(Object o){
        if (!(o instanceof ClassName)){
            return false;
        }
        ClassName that = (ClassName) o;
        return your equals logical
    } 
    
    • instanceof关键字
      1. 可判断null
      2. 可判断类名
      3. 是动态检查,不是静态,除了equals建议少用

hashCode()和equals()

  1. equals自定义逻辑要满足以下要求
    1. 自反
    2. 传递
    3. 对称
  2. hashCode自定义逻辑要满足以下要求
    1. equalstrue的对象,hashCode必须相等
    2. equalsfalse的对象,hashCode可以相等,但是性能不好
    3. hashCode对于未发生变化的对象必须不可变

可变/不可变对象的等价性

  1. 可变对象的等价性
    • 观察等价性:
      1. 如果不改变对象,任何观察都相同,则观察等价
      2. 对于只调用observerproducercreator都是一样的结果
    • 行为等价性:
      1. 在改变对象的情况下,各种操作都相同
      2. 调用各种方法,包括·mutator,结果都相同
    • 可变对象偏向使用观察等价性,例如JDK中的List
      不同List的实现,只要 元素相同,则equals
      但是JDK中不同的mutable类使用的等价性不同,StringBuilder则是使用行为等价性
    • 总结
      1. 可变类型使用行为等价性,不用重写equalshashCode
      2. 如果要判断观察等价性建议写similar方法重新判断
  2. 不可变对象的等价性
    • 必须重写equalshashCode
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值