前言:
根据四张考试卷涉及到的部分知识点的总结
对于大题的话,个人写了部分代码可以参考该链接
个人对考试大题的几个代码
今天是6月13号
15号软件构造
没有把握
19号马原
等18号再背
外部质量属性:针对于client的使用这个软件,没必要过剩了解代码内部
【正确性】【健壮性robustness】【可扩展性】【可复用性】【兼容性】【效率】【可移植性】【应用性】【功能性】【及时性】
内部质量属性:针对于代码
源码方面:行数(LoC)、逻辑复杂度
结构方面:耦合、内聚
除此之外还有代码可读性、易于理解、清晰、大小等。
final类无法派生子类
final变量无法改变值/引用
final方法无法被子类重写
mutable:
StringBulider,Date
一个完整的方法包括规约spec和实现体implementation;
尽量不设计mutating的spec,否则就容易引发bugs
除非在后置条件里声明过,否则方法内部不应该改变输入参数
尽量避免使用可变(mutable)的对象
如果规约的强度 S2>=S1,就可以用S2代替S1,
体现有二:
1.一个更强的规约包括更轻松的前置条件和更严格的后置条件;
2.越强的规约,意味着实现者(implementor)的自由度和责任越重,而客户(client)的责任越轻。
S2>=S1
S2的前置条件更弱
S2的后置条件更强
强度越强
画圈越小
如果S2是S1子类(LSP原则)
S2不变量更强
S2前置更弱
S2后置更强
invariant是要求类里面的属性要满足什么
前置条件是要求方法输入要满足什么
后置条件是要求方法输出要满足
!!!!!不同
根据LSP原则
子类应该spec只能不变或更强(不变量invariant更强,前弱后强)
【用注释写AF和RI】
本门课程还要求你将表示暴露的安全性注释出来。
表示不变量和抽象函数都应该记录在代码中,就在代表本身的声明旁边,以下图为例
表示泄露
如果是mutable就需要防御性拷贝
immutable不需要防御性拷贝
方法的重写(override)两同两小一大原则:
1.方法名相同,参数类型相同(传入的参数类型比如相同也不能变小变大!!!)
2.子类返回类型小于等于父类方法返回类型
3.子类抛出异常小于等于父类方法抛出异常
4.子类访问权限大于等于父类方法访问权限(访问权限由高到低:public、protected、包访问权限friendly(默认)、private)
5里氏代换原则(Liskov Substitution Principle, LSP):所有引用基类(父类)的地方必须能透明地使用其子类的对象
6 final方法不能被重写,不能覆盖不可被继承的方法
7 如果方法名称相同而参数列表不同(返回类型可以相同也可以不同),那么只是方法的重载,而非重写
如何处理当前发生的异常
1.在当前try-catch捕获就可以不用方法里面声明
2.在方法里面声明会向上抛出异常给别人处理,就可以不用在当前try-catch
1.如果对异常进行处理,后面代码还会继续执行
2.如果把异常直接抛出,后面代码将不会在继续执行
3.try里面遇到异常就不执行try内部段的下面的了,就直接跳出try执行其他代码块
//代码1
public static void test() throws Exception {
throw new Exception("参数越界");
System.out.println("异常后"); //编译错误,「无法访问的语句」
}
//代码2
try{
throw new Exception("参数越界");
}catch(Exception e) {
e.printStackTrace();
}
System.out.println("异常后");//可以执行
//代码3
if(true) {
throw new Exception("参数越界");
}
System.out.println("异常后"); //抛出异常,不会执行
1.如果对异常进行处理,后面代码还会继续执行
2.如果把异常直接抛出,后面代码将不会在继续执行
3.try里面遇到异常就不执行try内部段的下面的了,就直接跳出try执行其他代码块
public class TestException {
public static void main(String[] args) throws Exception {
int[] i = {1, 2, 3};
try {
System.out.println(i[3]);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("异常后1");//可以执行
try {
System.out.println(i[3]);
} catch (Exception e) {
throw new Exception("错误" + e);
}
System.out.println("异常后2");//不能执行
}
}
1.如果对异常进行处理,后面代码还会继续执行
2.如果把异常直接抛出,后面代码将不会在继续执行
3.try里面遇到异常就不执行try内部段的下面的了,就直接跳出try执行其他代码块
\.
\(
\)
\*
.................
1.阶段:构建 build|| 运行
2.动态:时刻 moment|| 周期
3.级别:代码code || 组件component
①Moment维度关注于程序在某一个时刻的表现,而Period维度更关注于程序在一段时间内的表现;
②Build-time维度关注程序还未被投入运行,编码阶段的表现,而Run-time维度更关注于程序运行时的表现;
③Code-level维度关注程序的语句层面,Component-level维度更关注于一段代码,当作一个块观察比如一个包、一个库。
(1) Build-time, moment, and code-level view 关注的是源码的组织情况,可在词汇(源码)、语法(抽象语法树)、语义(类图)三个层面分别分析。
(2) Build-time, period, and code-level view 关注的是代码的变化(Code churn代码变化)
(3) Build-time, moment, and component-level view 关注的是包/库,而且是静态链接库
(4) Build-time, period, and component-level view 关注代码的更迭,与(2)中不同的是,这个维度下更关注文件版本的变化,而不是具体语句的变化(2中关注的是哪一行代码被修改了)----VCS的引出
(5) Run-time, moment, and code-level view 关注的是程序在某个时间点内存中的情况,如代码快照图(Code Snapshot)、内存信息转储(Memory dump)。
(6) Run-time, period and code-level view 关注的是代码的执行情况,执行跟踪
(7) Run-time, moment, and component-level view 关注的也是包/库,但却是在代码执行过程中的情况,如动态链接库
(8) Run-time, period, and component-level view 关注的是系统的使用情况,使用日志查看
软件构造多维度视图
红色标注为重点(考试会考选择题)
Moment 特定时刻的软件形态 Period 软件形态随时间的变化
AST (Abstract Syntax Tree) 抽象语法树
SCI (Software Configuration Item) 配置项
concurrent multithreads 并发多线程
参考:参考链接
12jmap,Eclipse Memory Analyzer Java堆分析器
Heap Dump 是一个 Java 进程在某个时间点上的内存快照
VisualVM 是一款免费的,集成了多个 JDK 命令行工具的可视化工具,它能为您提供强大的分析能力,对 Java 应用程序做性能分析和调优。这些功能包括生成和分析海量数据、跟踪内存泄漏、监控垃圾回收器、执行内存和 CPU 分析,同时它还支持在 MBeans 上进行浏览和操作。本文主要介绍如何使用 VisualVM 进行性能分析及调优。
Eclipse Memory Analyzer 以及 VisualVM 涉及内存 需要执行代码
hascode相等 equals不一定相等
equals相等hashcode一定相等
assert x>0; 在运行代码中,这个抛出 AssertionError
assertTrue(x>);在junit,这个直接用作测试样例
二者不同
不能assert右侧加可执行代码
比如assert List.pop()==x;错误
pop=List.pop();
assert pop==x;
assert非常影响运行性能
assert只在开发阶段被编译到目标代码中,而在生成代码时不编译进去
checked exception会强制要求加入trycatch
unchecked exception不会强制要求
代码中的 assert 语句太多,会影响代码运行性能,这是为了 correctness 所需付出的必要代价
16.父类属性
在一个子类被创建的时候,首先会在内存中创建一个父类对象,然后在父类对象外部放上子类独有的属性,两者合起来形成一个子类的对象。
所以所谓的继承使子类拥有父类所有的属性和方法其实可以这样理解,子类对象确实拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用。
所谓的子类对象只能继承父类非私有的属性及方法的说法是错误的。可以继承,只是无法访问到而已。子类不能直接访问父类的私有属性,子类只能在父类中写一个public的getXXX的方法来获取父类中的private属性,子类就调用父类的getXXX来获取private属性。
子类继承了父类私有属性,但是只能通过Getter访问到不能直接访问
子类可以直接使用父类的公共属性,不需要super
抽象类特点:
1,抽象类不能被new
2,抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类
3,抽象类的子类必须重写全部的抽象方法,除非子类也是抽象类
4,抽象类不能有方法体
\w包括了_下划线
\w =[a-z]|[A-Z]|[0-9]|_
\w=[a-zA-z0-9_]
x ::= [a-ckx-z] // equivalent to x ::= ‘a’ | ‘b’ | ‘c’ | ‘k’ | ‘x’ | ‘y’ | ‘z’
import java.util.Iterator;
public class Stu implements Iterable<String>
{
private String[] things;
class StuIterator implements Iterator<String> {
private String curString;
private int index=0;
private int size = things.length;
@Override
public boolean hasNext() {
if(index<size-1)
return true;
else
return false;
}
@Override
public String next() {
String res = things[index++];
return res;
}
}
@Override
public Iterator<String> iterator() {
return new StuIterator();
}
public void setThings(String[] things) {
this.things = things;
}
}
class Test{
public static void main(String[] args) {
Stu stu = new Stu();
String[] strings = new String[]{"ABC","BCD"};
stu.setThings(strings);
Iterator<String> iterator = stu.iterator();
String next = iterator.next();
System.out.println("next = " + next);
String next2 = iterator.next();
System.out.println("next = " + next2);
}
}
数组存储的数据类型[ ] 数组名字 = new 数组存储的数据类型[数组长度];
int[] arr = new int[3];
int[] arr = new int[3]
数组存储的数据类型 数组名字[ ] = new 数组存储的数据类型[数组长度];
int arr[] = new int[3];
方法声明抛出throws
抛出throw new RuntimeException();.
它的所有成员变量的赋值仅在构造方法中完成,不会提供任何 setter 方法供外部类去修改。
A并不是越多能力也强,比如不断加同一个等价类中
Cbug已被修复,原测试用例也别删掉,用来检测后续更新是否又把bug改错了
D啥都要撰写
子类必须,强度》=,且不变量》=
协变:
父类型子类型:越来越具体specific
返回值类型:不变或变得更具体
异常的类型:也是如此。
class T {
Object a() { … }
}
class S extends T {
@Override
String a() { … }
}
反协变(逆变):(目前Java中遇到这种情况,当作overload看待)
父类型子类型:越来越具体specific
参数类型:要相反的变化,要不变或越来
越抽象
class T {
void c( String s ) { … }
}
class S extends T {
@Override
void c( Object s ) { … }
针对这个题需要知道list的equal
由于lst1和lst1都是实现了List接口的
并且内部元素String能够equal返回true
则lst2.equals(lst1)返回true
下面具体分析
List源码中以及重写了equal和hasCode
对于list.equal(object)
1.判断地址是否object和list引用同一个地址处的,如果是则true
2.再判断object的类型,要求是List否则false
3.如果object是List类,则检查判断内部元素利用equal对应的是否相等,只有都相等才能true
/**
*
*/
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof List)) {
return false;
}
final int expectedModCount = modCount;
// ArrayList can be subclassed and given arbitrary behavior, but we can
// still deal with the common case where o is ArrayList precisely
boolean equal = (o.getClass() == ArrayList.class)
? equalsArrayList((ArrayList<?>) o)
: equalsRange((List<?>) o, 0, size);
checkForComodification(expectedModCount);
return equal;
}
String的源码分析
String内部也重写了equal
当两个字符串的值相同就可以返回true
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
o.hashCode()直接返回这个o的哈希值
观察等价性:可变类型要用,equal要重写比较内部的值
行为等价性(完全引用同一个):不可变类型要用,equal直接用==
可变类型,应该要行为等价性,无需重写这两个函数equal和hasCode
不可变类型,应该观察等价性,要重写这两个函数equal和hasCode
对其大多数可变数据类型(如集合Collections,日期Date)使用观察性相等,但其他可变数据类(如StringBuilder)使用行为相等
List是mutable,但是用的比较内部的值相等即可,观察等价性
StringBuilder是mutable,但是用的equal比较==即可,行为等价性
Collections集合 use observational equality
对于hashSet的contains
1,list.add()的变化会影响list自身的hashCode值
2,set.contains()是利用判断hashCode值,由于add改变了list的hashCode,所以即使之前记录的list的hashcode和之后的hashcode不同
所以返回false
这是由于HashSet底层是由HashMap实现
就是利用了hasCode寻找哈希表要存到的地方,拉链法存储散列表
总之就是list重写了hasCode然后balabala
a.put(“A”,10)
放进去10
出来的a.get(“A”)//->Integer(10)
出来的是Integer类型
SCM与SCI
SCI(Software Configuration Item)软件配置项是最基本单元
仓库:本地仓库或远程仓库都是SCM中的CMDB
File文件就是一种SCI软件配置项
一个git仓库分为:
.git就是本地的CMDB
工作目录
暂存区,.git中的一个文件
不要用list.remove()而是用iterator.remove()
用subjects.remove()集合的remove方法会得到错误结果
因为iter底层也是index,这个集合remove不自动调整iter的index
这样用iter.remove()才是对的
set.add()是一个返回boolean
如果已经在集合里面了则返回false
1.枚举enum和class和interface地位一样
2.enum NameEnum是枚举类也是一个类,里面可以有方法有属性
3,enum继承的是java.lang.Enum
4.枚举类的所有实例都必须放在第一行展示,不需使用new 关键字,不需显式调用构造器。枚举类的实例自动添加public static final修饰。
assertThrows(message,Exception.class,()->方法)
就是利用class Mycomparator implements Comparator
{
public int compare()
}
public class Person implements Cloneable{
}
实现了接口Cloneable才可以clone()
浅拷贝:直接将源对象中的name的引用值拷贝给新对象的name字段;
深拷贝:根据Person源对象中的name指向的字符串对象创建一个新的相同的字符串对象,将这个新字符串对象的引用赋给新拷贝的Person对象的name字段。