hit-20lzh

   :: 首页  :: 新随笔  :: 联系 ::  :: 管理

基本数据类型:

  char、int、float、double等,空间在栈中进行分配

对象数据类型(引用数据类型):

  对象类型Object type,包括String以及专门设计给基本数据类型的包装类:Boolean、Integer、Short、Long、Character、Float、Double

  只能通过在栈中存储的地址进行操控。

 

Static checking:对类型的检查

  •  语法错误
  • 类名/函数名错误(没检查到field或method)
  • 参数数目错误
  • 参数类型错误
  • 返回值类型错误

Dynamic checking:对值的检查

  • 非法参数值(除0错误)
    •  需要注意,浮点数除0只会返回错误值,不会产生异常
  • 非法返回值
  • 越界访问
  • 空指针

 

对变量和变量值:

       改变变量等价于将该变量指向另一个存储空间

       改变变量的值等价于将该变量当前指向的存储空间中写入一个新值

Immutable types:

  •   Value不可改变的类型:String、Integer……

      一旦赋初值,其值不发生改变

  •   Java中将这一概念泛化到了对象:对一个对象而言,Value不可变 ó引用不变

      一旦确定其指向的对象,不能再改变其指向对象

Final:(体现一种决策体现,其规则检查将由编译器进行)

       Final可修饰基本数据类型or对象数据类型。使用final将开启编译器对变量的检查,若检测到第一次赋值/引用之后的再次变化,将提示错误。

       Final可修饰方法。被final修饰的方法无法被重写。

       Final可修饰类。被final修饰的类无法被继承

防御式拷贝:一种针对mutable对象的保护设计,需要人工实现

       对于mutable对象,由于其本身特点,一旦在程序中出现多个指向它的引用,对其更改很容易造成意想不到且难以发现的错误,因此使用防御式拷贝的手段,即返回一个内容相同但地址不同的对象,即使最终发生更改,也不会在其它方法中暴露出来

       这种方式有个缺点,容易产生大量的内存浪费。

另一种方法:包装器(在运行阶段进行,无法进行静态检查)

 

基本类型的值/对象类型的值:

 

可变对象/不可变对象:

 

可变/不可变引用:

 

 

Specification:

  • l  类型:
    • n      静态类型声明(方法签名):根据语法给出输入、返回值、和可能抛出异常的信息
    • n    方法前的注释
  • l  -precondition

              -postcondition

              -Exceptional behavior

  • l  需要隐藏本地变量

测试用例的编写必须仅依据规约进行,eg.int find(int num)函数返回num所在的索引,即使在实现时我们采用的方法是返回最后一个索引,也不能在测试代码编写时。

      

规约的分类:

  • l  确定性:
  • l  陈述性:
  • l  强度:

 

行为等价性:以client对两个函数,如何判断两种实现方式是否是等价的?(思考什么是行为等价性)

       以client的视角来说,它所知道的只有函数的签名和注释,因此其行为等价性的判别需要关注:

  • l  函数签名(输入、返回、异常类型是否一致)
  • l  根据spec来判断是否对相同input,能得到相同的output
    • n    Eg. 在数组中寻找一个数的索引,即使所找到的索引不同,但若对return的说明,仅声称它代表着一个匹配该数的索引,则仍认为两者行为等价

 

规约的强度:(更强的规约,限制更少、满足更多)

  • Precondition(对输入的要求)更弱 || Postcondition(对输出的要求)更强,说明spec更强
  • 存在这样一种情况,在对比两个规约的时候,当比较出两者precondition强弱的时候,postcondition的判断应在最弱precondition的限制下进行比较

 

规约的画法:

  • l  满足规约的所有实现(无法具体表示),用一个矩形表示
  • l  满足规约的某一个实现
    • n    Precondition越弱→可能的输入越多→实现的自由度越小→圈越小
    • n    Postcondition越强→保证的东西越多→实现的自由度越小→圈越小

ADT操作类型:

Creators:构造器——从无到有

Producers:生产器——从有到新

Observers:观察器

Mutators:变值器——改变对象属性

 

表示独立性:ADT的保持的一种特性,client无需知道具体实现即可使用,implementor进行改变无需通知client,只需保证spec即可。

表示泄露:调用class的代码可通过实例化直接修改原先class的内部表示,从而使得部分client(可能)对class的这些内部实现产生依赖。

 

RI:Rep Invariant,表示不变量,定义了所有field可能的取值中,哪些合法,哪些不合法

AF:给出解释field所有合法取值的办法

 

等价性:

如何理解等价性?

  等价性的判断是基于两个对象来进行的,脱离两个对象来谈等价没有意义

  等价性的判断可以有不同的标准,如接下来的AF和Observation

ADT的理解:

ADT是对数据的抽象,体现为对一组数据的操作

ADT的抽象通过对AF的设计进行实现,AF将ADT中具体的表示抽象成对外的表示

外界对ADT进行的各种操作均由ADT提供,因此其展示出来的结果由ADT确定

等价性类型:

等价性类型:

  AF等价性:根据AF的映射,来比较两个对象的内部表示是否一样

  观察等价性:通过对对象所有的Observer进行调用,并根据观察结果,判断两对象是否等价

  引用等价性:”==”操作符进行的判断,判断两个引用对象的地址是否相等或两个基本类型的值是否相等

  对象等价性:”equal(Object o)”,Object类本身具有的equal()进行引用等价判断,因此需要在子类中重写该函数,以满足implementor对等价性的要求。对象等价性的定义由implementor来去确定。

  行为等价性:对两个对象,调用两个对象的任何方法都能展示出一样的结果

Immutable对象:

  对象等价性:由于其对象不可变,因此倾向于重写equal()来实现其等价性

Mutable对象

  观察等价性:在对于一个mutable对象,往往倾向于实现严格的观察等价性

  行为等价性:对mutable对象而言,引用地址相同即可保证这一等价性,因此其equal往往无需重写

Equal()函数:

  最开始事项的位置在Object类中,原型为equal(Object o)

  在子类中要对equal()进行重写时需要注意,使用的是重载还是重写,重写要求形参是Object对象,否则实际进行的是重载

  若目的是重写该函数,最好使用@Override进行修饰,交给编译器进行检查

  必须满足等价关系:

    自反性

    传递性

    对称性

  对两个对象,在不改变其value的情况下,多次调用equal返回值应一样

Hashcode和equal函数的关系

  Hashcode和equal本身并无关系,hashcode是在Set、List、Map这些本质数据结构是散列表的Collection子类中进行使用的

一些神奇的机制

  Integer的-128~127,Java提供了包装类来对将一个整型数转换成一个对象,若该Integer对象代表的数落在[-128,127]之间,除非对象是new出来的,否则该对象的地址保存在一个常量池中(cache数组),此时无论多少个Integer对象,它们都有着相同的引用地址

等价性的小结:

  • 等价性需要考虑是否满足等价关系
  • 一个对象的等价性必须与其hashcode相吻合
  • AF是不可变类型等价性的基础
  • 引用等价性是可变类型等价性的基础
  • Final Rule:
    • 对于不可变类型必须重写equals()和hashCode()函数
    • 对于可变类型完全不必重写其equals()和hashCode()函数
posted on 2022-06-12 16:59  Auhevil  阅读(52)  评论(0编辑  收藏  举报