软件构造复习

Posted Y-Y-R

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了软件构造复习相关的知识,希望对你有一定的参考价值。

面向对象编程

基本概念

静态/实例方法

实例方法必须对某个特定对象使用

在类中使用static修饰的静态方法会随着类的定义而被分配和装载入内存中;而非静态方法属于对象的具体实例,只有在类的对象创建时在对象的内存中才有这个方法的代码段

接口与枚举

接口只给出方法规约

接口中无构造器(因为接口不能实例化)、属性和具体实现

 从Java 8以后,接口中可以实现静态方法。可以在接口中实现静态工厂方法以解决客户端不知道实现类的名称的问题:

 defalt关键字

在接口中可实现用defalt关键字修饰的方法(非静态方法),在实现类中不需要重复实现

 继承与重写

接口的继承

 重写

严格继承:子类只能添加新方法,无法重写超类中的方法

final修饰的方法不能被重写(final修饰的类不能被继承)

重写的函数:完全同样的signature。实际执行时调用哪个方法,运行时决定

用super来调用父类的方法

重写时,不要改变原方法的本意

重写方法调用的一个例子:

抽象类

抽象类中可以有抽象方法(只给出函数签名,无具体实现),用关键字abstract声明

可以只实现共性,其余由子类实现。有些子类型有而有些子类型没有的操作,不要在父类中定义和实现,而应在特定子类中实现

抽象类不能实例化对象

多态、子类型、重载

三种多态

特殊多态:重载

参数化多态:泛型

子类型多态、包含多态:继承

特殊多态与重载

多个方法具有同样的名字,但有不同的参数列表或返回值类型

重载是静态多态,根据参数列表进行最佳匹配,属于静态类型检查(在编译阶段时决定具体要执行哪个方法)

与之相反,重写是在运行时进行动态类型检查

重载的参数类型或参数个数必须不同,返回值、修饰符、异常可以不同:

 重载也可以发生在父类和子类之间

重写与重载的对比

 重写方法的访问权限不能比原方法更严格,但可以变宽松

 参数多态与泛型编程

泛型类:定义中包含了类型变量的类

泛型接口、泛型方法的定义类似

使用"<>"声明

方法的类型参数(下图中的"<E>"):

 泛型擦除

Java在编译期间会清除泛型信息,如List<String>和List<Integer>编译之后都是List

所有类型参数都用他们的限定类型替换,包括类、变量和方法,如果类型变量有限定则原始类型就用第一个边界的类型来替换,如 class Pr<T extends Comparable & Serializable> 的原始类型就是 Comparable
java编译器先检查代码中泛型的类型,然后再进行类型擦除,再进行编译

下面代码运行结果为true,因为泛型信息被清除了

ArrayList<String> arrayList1=new ArrayList<String>();

arrayList1.add("abc");

ArrayList<Integer> arrayList2=new ArrayList<Integer>();

arrayList2.add(123);

System.out.println(arrayList1.getClass()==arrayList2.getClass());

Java中不能声明泛型数组

通配符(Wildcards),只在使用泛型的时候出现,不能在定义中出现

通配符写作"?"

<?>接受任意类型,如List<?>接受任何类型的列表

<? extends T>接受T和T的所有子类

<? super T>接受T和T的所有父类

子类型多态

“B是A的子类”意味着B满足A的Spec,即子类型的规约不能弱化超类的规约

子类型多态:不同类型的对象可以统一的处理而无需区分

LSP原则

如果S是T的子类,那么T的对象可以被S的对象替换

  • 重写时,子类的规约要强于父类的规约(更弱的前置条件,更强的后置条件)(java无法检测)
  • 子类的可见性要强于父类(即父类如果是public,子类不能为private)
  • 子类不能比父类抛出更多的异常

Instanceof

判断一个对象是否是一个类(也可以是子类)的实例

动态类型检查

  • List<Object>不是List<String>的父类
  • List<String>ArrayList<String>的父类
  • List<?> 是 List<String>的父类

尽量避免使用Instanceof,其他获取对象运行时的类型的方法也应避免使用,如getClass

使用多态来避免使用Instanceof

Object类的方法

equals

判断两对象是否相等

重写equals的例子:

hashCode

获取对象的哈希值 

toString

获取对象的字符串表示

ADT与OOP中的等价性

相等关系

相等关系是等价关系

从而equals方法确定的关系应当是等价关系

不可变类型的等价性

利用抽象函数AF来判断两个对象是否等价

记AF为f:R->A,如果f(a)=f(b),则a与b等价

站在外部观察者角度,如果对两个对象调用任何操作,都会得到相同的结果,则认为两个对象是等价的

==与equals

==:引用等价性,两个引用指向同一个地址

equals比较对象的内容,即对象等价性

在自定义ADT时,需要重写Object的equals方法

实现equals()

在Object中实现的缺省equals()是在判断引用等价性,即"==",所以一般需要重写

 注意重写时,equals方法的参数需要为Object类型,否则为重载!

等价的对象必须有相同的hashCode,所以如果重写了equals且不能保证对象不被放入hashSet,hashMap,则必须重写hashCode

以下代码运行结果为false,注意其中的equals为重载

 改为重写equals方法后,运行结果为true

 对象的契约

  1. euqals确定的关系应当是等价关系
  2. 除非对象被修改了,否则多次调用equals应得到相同的结果
  3. “相等”的对象的hashCode必须一致(不相等的对象也可以映射为相同的hashCode,但性能会变差)

可变类型的等价性

观察等价性:在不改变状态的情况下,两个可变对象是否看起来一致

行为等价性:调用对象的任何方法都展示出一致的结果

对不可变对象,观察等价性和行为等价性是相同的,因为它们没有变值器方法

对可变类型,往往倾向于实现严格的观察等价性,如集合类采用观察等价性,但StringBuilder使用行为等价性

一个例子:

 对list进行修改:

 set的contains方法将找不到list:

 原因:set是按哈希值存储的,当list被加入时,它被放在它的哈希值所对应的位置;list被更改后,其哈希值也随之更改,但它在set中的位置没有改变,所以contains方法无法找到list

如果某个mutable的对象包含在HashSet集合类中,当其发生改变后,集合类的行为不确定,务必小心!

一些例子:

 可变类型等价性总结

  • 对可变类型,应实现行为等价性
  • 一般来说,即实现对象等价性
  • 所以可变类型不需要重写equals方法和hashCode方法
  • 如果一定要判断两个对象是否一致,最好定义一个新的方法

总结

对不可变类型

应按AF来确定equals,即实现行为等价性;而hashCode方法应将一个抽象值映射为一个整数

所以必须重写equals和hashCode

对可变类型

应实现行为等价性,对可变类型来说,即实现对象等价性

所以不应该重写equals方法和HashCode方法

Object中的Clone

一般来说,有:

x.clone() != x

x.clone().getClass() ==x .getClass()

x.clone().equals(x)

封装类的等价性

考虑基本数据类型int及其封装类型Integer

如果两个Integer型对象x和y的数值相等,则它们满足equals()

 x和y不在同一地址,故x==y为false

但(int) x==(int) y为true

以下代码的最后一行结果为false

 但如果将130改为在-128到127之间的整数,则结果为true

这是因为Integer x=整数C;Integer y=整数C;x==y为true当且仅当C在-128到127之间

但Integer x=new Integer(整数C);Integer y=new Integer(整数C);x==y始终为false,因为是新建的对象

软件构造复习——关于Java中的正则表达式

写在前面:

               写这篇博客是因为自己在复习“软件构造”这门课时,发现对正则表达式的相关知识掌握不足。所以写下该博,以便复习并巩固相关知识。如发现错误,请您指正,我将不胜感激。

               PS:本文关于正则表达式的知识深度是基于“软件构造”的要求。

 

正则表达式:

          前言:

                    正则表达式定义了字符串的模式。

                    正则表达式可以用来搜索、编辑或处理文本。

                    正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。

          特点:

                    1. 灵活性、逻辑性和功能性非常的强;

                    2. 可以迅速地用极简单的方式达到字符串的复杂控制。

                    3. 对于刚接触的人来说,比较晦涩难懂。

 

一、常见的

     

1.         将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,"n"匹配字符"n"。" "匹配换行符。序列"\\"匹配"\","\("匹配"("。

2.    ^    匹配输入字符串开始的位置。

3.    $   匹配输入字符串结尾的位置。

4.    *   零次或多次匹配前面的字符或子表达式。

5.    +   一次或多次匹配前面的字符或子表达式。

6.    ?   零次或一次匹配前面的字符或子表达式。

7.   {n}   n 是非负整数。正好匹配 n 次。

8.   {n,}   n 是非负整数。至少匹配 n 次。

9.  {n,m}   Mn 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。注意:不能将空格插入逗号和数字之间。

10.   x|y   匹配 xy

11.  [xyz]   字符集。匹配包含的任一字符。

12. [^xyz]  反向字符集。匹配未包含的任何字符。

13.  [a-z]   字符范围。匹配指定范围内的任何字符。

14. [^a-z]   反向范围字符。匹配不在指定的范围内的任何字符。

15.    d   数字字符匹配。

………………

………………(还有很多,但这些已足够)

 

二、应用点(针对课程)

1. 给定的字符串是否符合正则表达式的过滤逻辑(即"匹配");

2. 通过正则表达式,从字符串中获取想要的特定部分。

 

三、一些简单地例子(表达式)

1.匹配网址:    [a-zA-z]+://[^s]*

2.QQ号(至少5位,不以0开头):    [1-9][0-9]{4,}

3.((http|ftp|https)://)(([a-zA-Z0-9._-]+.[a-zA-Z]{2,6})

4.邮箱:^[a-zA-Z0-9_-][email protected][a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$

 

写在后面:

          这些是我复习时所涉及到的一些知识(针对于考试,并未深入),感谢大家的指正!

 

以上是关于软件构造复习的主要内容,如果未能解决你的问题,请参考以下文章

软件构造复习

软件构造复习内容--ADT

软件构造复习——关于Java中的正则表达式

软件构造复习

软件构造复习内容---并发

软件构造复习内容(10)---并发