软件构造期末复习考点总结

【考点 Equals】

  • ==是引用等价性 ;而equals()是对象等价性。

    • == 比较的是索引。更准确的说,它测试的是指向相等(referential equality)。如果两个索引指向同一块存储区域,那它们就是==的。对于我们之前提到过的快照图来说,==就意味着它们的箭头指向同一个对象。
    • equals()操作比较的是对象的内容,换句话说,它测试的是对象值相等(object equality)。e在每一个ADT中,quals操作必须合理定义。
  • 基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean

    • 他们之间的比较,应用双等号(==),比较的是他们的值。
  • 复合数据类型(类) 
    • 当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。
    • JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
    • 对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。
  • HahCode:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。

  当我们当向集合中插入对象时,就可以使用hashcode,先调用这个对象的hashCode方法,得到对应的hashcode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了。

【考点 函数规约】 requires与effects

声明式规约更有价值 ; 内部实现的细节不在规约里呈现,而放在代码实现体内部注释里呈现,例:

static String join(String delimiter, String[] elements)
effects: returns concatenation of elements in order, with delimiter inserted between each pair of adjacent elements // Declarative specs

更强的规约包括更轻松的前置条件和更严格的后置条件;

方法前的注释也是一种规约,但需人工判定其是否满足。

  • 参数由@param 描述
  • 子句和结果用 @return 和 @ throws子句 描述
  • 尽可能的将前置条件放在 @param 中
  • 尽可能的将后置条件放在 @return 和 @throws 中

【考点 ADT的四种类型】

  • Creators(构造器):

    • 创建某个类型的新对象,?个创建者可能会接受?个对象作为参数,但是这个对象的类型不能是它创建对象对应的类型。可能实现为构造函数或静态函数。(通常称为工厂方法)
    • t* ->  T
    • 栗子:Integer.valueOf(Object  obj):object → integer
  • Producers(生产器):
    • 通过接受同类型的对象创建新的对象。
    • T+ , t* -> T
    • 栗子:String.concat( )  :String x String → String
  • Observers(观察器):
    • 获取抽象类型的对象然后返回一个不同类型的对象/值。
    • T+ , t* -> t
    • 栗子:List.size( )   : List → int
  • Mutators(变值器):
    • 改变对象属性的方法 ,
    • 变值器通常返回void,若为void,则必然意味着它改变了对象的某些内部状态;当然,也可能返回非空类型
    • T+ , t* -> t || T || void
    • 栗子:List.add( ) :List x int → List

【考点 ADT的 AF与 RI】

在研究抽象类型的时候,先思考一下两个值域之间的关系:

  • 表示域(rep values)里面包含的是值具体的实现实体。一般情况下ADT的表示比较简单,有些时候需要复杂表示。
  • 抽象域(AF)里面包含的则是类型设计时支持使用的值。这些值是由表示域“抽象/想象”出来的,也是使用者关注的。

R->A的映射特点:

  • 每一个抽象值都是由表示值映射而来 ,即满射:每个抽象值被映射到一些rep值
  • 一些抽象值是被多个表示值映射而来的,即未必单射:一些抽象值被映射到多个rep值
  • 不是所有的表示值都能映射到抽象域中,即未必双射:并非所有的rep值都被映射。

在描述抽象函数和表示不变量的时候,注意要清晰明确:

  • 对于RI(表示不变量),仅仅宽泛的说什么区域是合法的并不够,你还应该说明是什么使得它合法/不合法。
  • 对于AF(抽象函数)来说,仅仅宽泛的说抽象域表示了什么并不够。抽象函数的作用是规定合法的表示值会如何被解释到抽象域。作为一个函数,我们应该清晰的知道从一个输入到一个输入是怎么对应的。

【考点:黑盒、白盒框架】

  • 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。
  • 为了增加代码的复用性,可以使用委派和继承机制。同时,在使用这两种机制增加代码复用的过程中,我们也相应地在不同的类之间增加了关系(委派或继承关系)。而对于一个项目而言,各个不同类之间的依赖关系就可以看做为一个框架。一个大规模的项目可能由许多不同的框架组合而成。

【白盒框架】

  • 白盒框架是基于面向对象的继承机制。之所以说是白盒框架,是因为在这种框架中,父类的方法对子类而言是可见的。子类可以通过继承或重写父类的方法来实现更具体的方法。
  • 虽然层次结构比较清晰,但是这种方式也有其局限性,父类中的方法子类一定拥有,要么继承,要么重写,不可能存在子类中不存在的方法而在父类中存在。
  • 软件构造课程中有关白盒框架的例子:

【黑盒框架】

  • 黑盒框架时基于委派的组合方式,是不同对象之间的组合。之所以是黑盒,是因为不用去管对象中的方法是如何实现的,只需关心对象上拥有的方法。
  • 这种方式较白盒框架更为灵活,因为可以在运行时动态地传入不同对象,实现不同对象间的动态组合;而继承机制在静态编译时就已经确定好。
  • 黑盒框架与白盒框架之间可以相互转换,具体例子可以看一下,软件构造课程中有关黑盒框架的例子,更改上面的白盒框架为黑盒框架:

【两者对比】

  • 白盒框架利用subclassing:

    • 允许扩展每一个非私有方法
    • 需要理解父类的实现
    • 一次只进行一次扩展
    • 通常被认为是开发者框架
  • 黑盒框架使用委派中的组合composition:
    • 允许在接口中对public方法扩展
    • 只需要理解接口
    • 通常提供更多的模块
    • 通常被认为是终端用户框架,平台

【LSP】

  • 里氏替换原则的主要作用就是规范继承时子类的一些书写规则。其主要目的就是保持父类方法不被覆盖。子类的规约变强!
  • LSP依赖于以下限制:
    • 前置条件变弱或者不变
    • 后置条件变强或者不变
    • 不变量要保持或增强
    • 子类型方法参数:逆变(规约变强,前置变弱 反着变)
    • 子类型方法的返回值:协变(规约变强,前置变强 协同变化)
    • 异常类型:协变
  • 数组是协变的,向上转型是成立的
Fruit[] apples=new Apple[size];  
  • 泛型是类型不变的(泛型不是协变的)。举例来说

    • ArrayList<String> 是List<String>的子类型
    • List<String>不是List<Object>的子类型
  • 类型擦除的结果: <T>被擦除 T变成了Object

【Throwable】

  • 健壮性:输入错误,给出确定的正常的输出,倾向于容错;正确性:出现错误报出错误,倾向于error。
  • 对外的接口,倾向于健壮性;对内的实现,倾向于正确性。

  • 运行时异常:由程序员处理不当造成,如空指针、数组越界、类型转换
  • 其他异常:程序员无法完全控制的外在问题所导致的,通常为IOE异常,即找不到文件路径等
  • checked异常:
    • checked exception是需要强制catch的异常,你在调用这个方法的时候,你如果不catch这个异常,那么编译器就会报错,比如说我们读写文件的时候会catch IOException,执行数据库操作会有SQLException等。

  • unchecked异常:

    • 这种异常不是必须需要catch的,你是无法预料的,比如说你在调用一个 list.szie()的时候,如果这个list为null,那么就会报NUllPointerException,而这个异常就是 RuntimeException,也就是UnChecked Exception
    • 常见的unchecked exception:JVM抛出,如空指针、数组越界、数据格式、不合法的参数、不合法的状态、找不到类等

    

【GC的四种策略】                                          

  • 引用计数

    • 基本思想:为每个object存储一个计数RC,当有其他 reference指向它时,RC++;当其他reference与其断开时,RC--;如 果RC==0,则回收它。
    • 优点:简单、计算代价分散,“幽灵时间”短 为0
    • 缺点:不全面(容易漏掉循环引用的对象)、并发支 持较弱、占用额外内存空间、等
  • Mark-Sweep(标记-清除)算法
    • 基本思想:为每个object设定状态位(live/dead)并记录,即mark阶段;将标记为dead的对象进行清理,即sweep可阶段。
    • 优点:可以处理循环调用,指针操作无开销,对象不变
    • 缺点:复杂度为O(heap),高 堆的占用比高时影响性能,容易造成碎片,需要找到root

  • Copying(复制)算法

    • 基本思想:为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。
    • 优势:运行高效、不易产生内存碎片
    • 缺点:复制花费大量的时间,牺牲内存空间

  • Mark-Compact(标记-整理)算法

    • 基本思想:为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。

  • 年青一代使用copying算法,年好易贷使用Mark sweep和mark-compact算法

【死锁】

  • 产生死锁的四个必要条件:

    • 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
    • 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
    • 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
    • 循环等待条件: 若干进程间形成首尾相接循环等待资源的关系
  • 这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
  • 防止死锁的方法:

    • 加锁顺序:当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。这种方式是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁,但总有些时候是无法预知的

    • 使用粗粒度的锁,用单个锁来监控多个对象

      • 对整个社交网 络设置 一个锁 ,并且对其任何组成部分的所有操作都在该锁上进行同步。
      • 例如:所有的Wizards都属于一个Castle,  可使用 castle 实例的锁
      • 缺点:性能损失大;
        • 如果用一个锁保护大量的可变数据,那么久放弃了同时访问这些数据的能力;
        • 在最糟糕的情况下,程序可能基本上是顺序执行的,丧失了并发性

【用注释形式撰写测试策略】

【测试覆盖度】

代码覆盖度:已有的测试用例有多大程度覆盖了被测程序

代码覆盖度越低,测试越不充分但要做到很高的代码覆盖度,需要更多的测试用例,测试代价高

分类:函数覆盖 + 语句覆盖 +分支覆盖 + 条件覆盖 + 路径覆盖

测试效果:路径覆盖>分支覆盖>语句覆盖

测试难度:路径覆盖>分支覆盖>语句覆盖

路径数量巨大,难以全覆盖

【snapshot】在Runtime,code level,moment

【SOLID】

设计模式前五个原则,恰恰是告诉我们用抽象构建框架,用实现扩展细节的注意事项而已:

  单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合。而开闭原则是总纲(实现效果),它告诉我们要对扩展开放,对修改关闭。

原文地址:https://www.cnblogs.com/HIT-ryp/p/11080751.html

时间: 2024-11-05 21:54:53

软件构造期末复习考点总结的相关文章

哈工大 软件构造课程 复习考点总结(第六、七章)

可维护性的常见度量指标 Cyclomatic complexity 圈复杂度 Lines of Code LoC 代码行数 Maintainability Index (MI) 可维护性指数 Depth of Inheritance 继承的层次数 Class Coupling 类之间的耦合度 Unit test coverage 测试代码覆盖率 Coupling 耦合度 and Cohesion 聚合度 Coupling 耦合度: 模块之间的依赖性. Conhesion 聚合度 功能专一性.高聚

软件构造(复习)——一些关于多线程的知识

写在前面:了解多线程是十分必要的,这篇博文是我对该知识点的一些了解(同时也看了一些相关的Blog),用来复习并巩固相关知识. 一.什么是多线程? 多线程,是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能.在一个程序中,这些独立运行的程序片段叫作"线程"(Thread),利用它编程的概念就叫作"多线程处理(Multithreading)". 多线程是为了同步完成多项任务,不是为了提

软件项目管理|期末复习(二)

1.项目的定义和特征 定义: 为创建某一独特的产品或服务,在一定环境和约束条件下进行的临时性努力. 特征: 一个明确的范围和目标 一个预期完成时间 有可以利用的资源 一种已定义的性能评估方法 不是例行的任务 2.项目管理的定义 一种为高效恰当地完成某个既定的目标而对资源进行管理.分配和调度的过程. 一种为实现既定目标而对技术.人力.金融资源所进行的系统集成. 3.项目管理的内容(项目管理知识体) 范围管理:按照某个特定目标,确定和控制整个项目的过程.项目的目标和对象,确定了范围管理的基础.范围的

软件项目管理|期末复习(九)

1.项目管理计划的内容和主要使用者 项目管理计划PMP 是项目经理承担的所有规划任务的核心,各规划任务的结果都出现在PMP中.它是指导所有项目执行的基准文档. 内容:项目概述.项目计划.项目跟踪.团队 主要使用者:业务主管.项目经理.项目开发人员 2.项目概述包含哪些内容 项目的起止日期.项目经理.项目目标.与客户的联系.对客户的主要承诺.所做的假设前提 3.项目计划包含哪些内容 项目过程(标准过程的描述.裁剪指南.需求变更管理).工作量估计.开发环境.工具.培训计划.质量计划.里程碑.风险管理

[期末复习]《语义网与知识图谱》期末复习(一)

上海大学<语义网与知识图谱>期末复习(一) 前言 这个课..不太喜欢.但是不能挂呀!平常的话感觉很难听得进去,因为没有任何先导课,直接上这个确实有点难受,那个老师感觉得到他想表达很多东西,但是有些东西确实表达不够明确,每节课听得都迷迷糊糊,毕竟是一个前沿的东西,如果不是一线战斗的老师,估计很多概念都很难讲清楚吧. 以上均胡扯,万一我有哪天真的用上了呢?(见鬼了). 下面复习主要集中在可能的考点复习上,均个人感觉哪里可能出题等等. 之前总结过rdf/rdfs.turtle和owl语法,所以这里前

[期末复习]《语义网与知识图谱》期末复习(二)

<语义网与知识图谱>期末复习(二) 这次老师发了个最终版的pdf帮助我们复习,那我就重来. 基本 语义web的组成:语义web信息的开放标准.从web描述信息中进一步获取语义的方法. 本体:本体是一种形式化的,对共享概念体系的明确而又详细的说明.提供一种共享词表.核心是分类体系. RDF使用有向图作为数据类型. RDF-Literals 即文本或者说是字符串,在rdf图种用方框表示. RDF表示 一个三元组包含 主语:URIs和空节点 谓语:URIs(通常被成为属性) 宾语:URIs.空节点或

数据结构期末复习第五章数组和广义表

数据结构期末复习第五章 数组和广义表 二维数组A[m][n]按行优先 寻址计算方法,每个数组元素占据d 个地址单元.     设数组的基址为LOC(a11) :LOC(aij)=LOC(a11)+((i-1)*n+j-1)*d     设数组的基址为LOC(a00) :LOC(aij)=LOC(a00)+( i*n+j )*d    二维数组A[m][n]按列优先 寻址计算方法,每个数组元素占据d 个地址单元.     设数组的基址为LOC(a11) :LOC(aij)=LOC(a11)+((j

【软件构造】第一章 软件构造基础(2)

二.软件构造的质量目标 1. 外部属性(主要):影响用户感受,如外观.速度等 (1)正确性:符合规格范围和计划目标 ·只保证各个层面的正确性(假设调用正确) ·检验与调试 ·防御性编程 ·形式化编程 (2)健壮性:响应规格范围外的异常情况 ·提示错误信息 ·正常退出或降级 (3)可扩展性:提供增加新功能的空间 ·固化需求以规避风险 ·设计简洁.离散化 (4)可复用性:使软件模块能够被其他程序使用 ·模式固化 (5)兼容性:跨平台.跨软件交互 ·使用标准文件格式.数据结构.接口,保持一致性 ·定义

麻省理工18年春软件构造课程阅读04“代码评审”

本文内容来自MIT_6.031_sp18: Software Construction课程的Readings部分,采用CC BY-SA 4.0协议. 由于我们学校(哈工大)大二软件构造课程的大部分素材取自此,也是推荐的阅读材料之一,于是打算做一些翻译工作,自己学习的同时也能帮到一些懒得看英文的朋友.另外,该课程的阅读资料中有许多练习题,但是没有标准答案,所给出的答案均为译者所写,有错误的地方还请指出. 译者:李秋豪 审校: V1.0 Thu Mar 8 22:58:41 CST 2018 本次课