【测开面试题】八股文总结
🎄Java基础
1. Java数据类型
基本数据类型:byte,char,short,int,float,double,long,boolean
引用数据类型:class,Arrays,interface
Python基本数据类型:int,float,str,bool
2. 理解面向对象
面向对象是利于语言对现实事物进行抽象。面向对象具有以下四大特征:
(1)继承:继承是从已有类得到继承信息创建新类的过程
(2)封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。
(3)多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。
(4)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。
3. ==和Equals的区别
==:
如果比较的是基本数据类型,那么比较的是变量的值
如果比较的是引用数据类型,那么比较的是地址值(两个对象是否指向同一块内存)
Equals:
如果没重写equals方法比较的是两个对象的地址值
如果重写了equals方法后我们往往比较的是对象中的属性的内容
equals方法是从Object类中继承的,默认的实现就是使用==
4. String,String buffer和String builder区别
(1)String是不可变的,String buffer,String builder是可变的;所谓不可变,任何修改操作都要重新创建对象,不能直接修改;
(2)String线程安全(因为不可变,天然线程安全),String buffer线程安全(加锁synchronized),String builder线程不安全;
(3)String一般作为字符串常量使用,在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都需要判断锁,效率相对更低
5. final关键字
final作为Java中的关键字可以用于三个地方。用于修饰类、类属性和类方法。
特征:凡是引用final关键字的地方皆不可修改!
(1)修饰类:表示该类不能被继承;
(2)修饰方法:表示方法不能被重写;
(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
6. 抽象类和接口有什么区别?
(1)关键字:抽象类通过abstract定义,接口通过interface定义
(2)方法实现:抽象类可以有具体的方法和抽象方法,接口在java 8前只能有抽象方法,之后可以有默认的方法和静态方法
(3)成员变量:抽象类可以有普通的成员变量,接口只能是public static final修饰(常量)
(4)构造方法:抽象类有构造方法,接口没有构造方法
(5)多继承:抽象类一个类只能继承一个抽象类,接口一个类可以实现多个接口
(6)访问修饰符:抽象类的方法可以是任意访问修饰符,接口的方法默认是public
7. 重载和重写的区别
(1)重载发生在本类,重写发生在父类与子类之间
(2)重载的方法名必须相同,重写的方法名相同且返回值类型必须相同
(3)重载的参数列表不同,重写的参数列表必须相同
(4)重写的访问权限不能比父类中被重写的方法的访问权限更低
(5)构造方法不能被重写
8. 什么是自动装拆箱 int和Integer区别
基本数据类型,如int,float,double,boolean,char,byte,不具备对象的特征,不能调用方法。
(1)装箱:将基本类型转换成包装类对象
(2)拆箱:将包装类对象转换成基本类型的值
java为什么要引入自动装箱和拆箱的功能?
主要是用于java集合中,List<Inteter> list=new ArrayList<Integer>();
list集合如果要放整数的话,只能放对象,不能放基本类型,因此需要将整数自动装箱成对象。
区别:
(1)Integer是int的包装类,int则是java的一种基本数据类型
(2)Integer变量必须实例化后才能使用,而int变量不需要
(3)Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
(4)Integer的默认值是null,int的默认值是0
🌲数据结构
1. ArrayList和LinkedList的区别
(1)ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
(2)对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
(3)对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。 这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。
2. HashMap和HashTable区别
(1)线程安全性不同
HashMap是线程不安全的,HashTable是线程安全的,其中的方法是Synchronized,在多线程并发的情况下,可以直接使用HashTable,但是使用HashMap时必须自己增加同步处理。
(2)是否提供contains方法
HashMap只有containsValue和containsKey方法;HashTable有contains、containsKey和containsValue三个方法,其中contains和containsValue方法功能相同。
(3) key和value是否允许null值
Hashtable中,key和value都不允许出现null值。HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。
(2)数组初始化和扩容机制
HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。
3. HashSet 的实现原理
(1)基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。
(2)当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。
(3)HashSet的其他操作都是基于HashMap的。
4. HashMap底层原理
HashMap的底层结构在jdk1.7中由数组+链表实现,在jdk1.8中由数组+链表+红黑树实现,以数组+链表的结构为例。
HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对。HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。
JDK1.8 之前 HashMap 由 数组+链表 组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突(两个对象调用的hashCode方法计算的哈希码值一致导致计算的数组索引值相同)而存在的(“拉链法”解决冲突).JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(或者红黑树的边界值,默认为 8)并且当前数组的长度大于64时,此时此索引位置上的所有数据改为使用红黑树存储。
补充:将链表转换成红黑树前会判断,即使阈值大于8,但是数组长度小于64,此时并不会将链表变为红黑树。而是选择进行数组扩容。
这样做的目的是因为数组比较小,尽量避开红黑树结构,这种情况下变为红黑树结构,反而会降低效率,因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡 。同时数组长度小于64时,搜索时间相对要快些。所以综上所述为了提高性能和减少搜索时间,底层在阈值大于8并且数组长度大于64时,链表才转换为红黑树。具体可以参考 treeifyBin方法。
当然虽然增了红黑树作为底层数据结构,结构变得复杂了,但是阈值大于8并且数组长度大于64时,链表转换为红黑树时,效率也变的更高效。
详解HashMap:史上最详细的 JDK 1.8 HashMap 源码解析_jdk1.8 .map-CSDN博客
5. 冒泡排序
6. 快速排序
🌳操作系统
1. 创建线程有哪几种方式?
(1)继承Thread类实现多线程
(2)覆写Runnable()接口实现多线程,而后同样覆写run().推荐此方式
(3)覆写Callable接口实现多线程(JDK1.5)
(4)通过线程池启动多线程
(5)通过Lambda表达式
2. 线程和进程的区别
(1)进程是操作系统进行资源分配的基本单位
(2)线程是CPU调度执行的基本单位
(3)进程创建开销大,进程创建开销小,轻量
(4)一个进程崩溃不影响其他进程,一个线程崩溃可能导致整个进程终止
(5)一个进程可以包含多个线程,线程必须存在于某个进程内
3. 线程不安全的原因
(1)现成在系统中是随机调度,抢占式执行
(2)多个线程针对同一变量进行修改操作
(3)线程针对变量的修改不是原子的
(4)内存可见性,指令重排序
4. 如何保证线程安全
(1)加锁,synchronized
5. 线程的状态
(1)NEW状态
Thread 对象有了,还没有调用 start,系统内部的线程还没有创建。
(2)TERMINATED状态
线程已经终止了,内核中的线程已经销毁了,Thread对象还在
(3)RUNNABLE状态
后面三种状态都为阻塞状态,只是把不同的原因的阻塞区分了
(4)WAITING状态
原因:死等产生的阻塞
代码里面打印不了此时的状态,因为一直在打印。通过jconsole工具查看main线程的状态
(5)TIME_WAITING状态
原因:带有超时时间的等产生的阻塞
sleep也是带有时间的,也是TIME_WAITING
(6)BLOCKED状态
原因:进行锁竞争的时候产生的阻塞(讲到线程安全的时候会说!)
只要线程出现上述三个的任意一个状态,都为阻塞状态,只是三个产生状态的原因不一样!!!
6. 进程调度
核心原则:分时复用
(1)一个核心同一时刻,只能运行一个进行;16个核心同一时刻,能运行16个进程,从微观的角度来说这是同时执行的,又称为并行执行。
(2)一个核心不同时刻,可以执行不同的进程,这一刻执行进程1,下一刻执行进程2......,CPU就把总的执行时间,划分成若干个片段,每个片段执行一个进程,由于CPU切换进程的速度极快,人是感知不到,站在人的角度来看这若干个进程是在同时执行,又称为并发执行。
(3)所以操作系统就会按照并行+并发两种相互搭配,来进行进程的调度
7. sleep() 和 wait() 有什么区别
sleep方法:
属于Thread类中的方法;会导致程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持着,当指定时间到了之后,又会自动恢复运行状态;在调用sleep方法的过程中,线程不会释放对象锁。(只会让出CPU,不会导致锁行为的改变)
wait方法:
属于Object类中的方法;在调用wait方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify方法后本线程才进入对象锁定池准备。获取对象锁进入运行状态。(不仅让出CPU,还释放已经占有的同步资源锁)
8. notify()和 notifyAll()有什么区别
notify():
唤醒一个处于等待状态的线程,
注意的是在调用此方法的时候,
并不能确切的唤醒某一个等待状态的线程,
而是由JVM确定唤醒哪个线程,而且不是按优先级。
notifyAll():
唤醒所有处入等待状态的线程;
并可以理解为把他们排进一个队列;
只不过只有头部的线程获得了锁,才能运行;
注意!!并不是给所有唤醒线程一个对象的锁,而是让它们竞争,
当其中一个线程运行完就开始运行下一个已经被唤醒的线程,因为锁已经转移了。
9. 什么是死锁
所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。
10. 死锁的必要条件
11. synchronized和volatile的区别
1)volatile比synchronized更轻量级。
2)volatile没有synchronized使用的广泛。
3)volatile不需要加锁,比synchronized更轻量级,不会阻塞线程。
4)从内存可见性角度看,volatile读相当于加锁,volatile写相当于解锁。
5)synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性。
6)volatile本身不保证获取和设置操作的原子性,仅仅保持修改的可见性。但是java的内存模型保证声明为volatile的long和double变量的get和set操作是原子的。
12. 懒汉恶汉模式
🌴网络
1. UDP和TCP的区别
(1)TCP基于连接,UDP基于无连接。
(2)TCP对系统资源要求高,UDP少。
(3)TCP是基于字节流的,UDP是数据报文模式。
(4)TCP复杂,UDP简单。
2. Session和Cookie的区别
(1)Cookie 是客⼾端保存⽤⼾信息的⼀种机制.Session 是服务器端保存⽤⼾信息的⼀种机制.
(2)Cookie 和 Session之间主要是通过 SessionId 关联起来的, SessionId是 Cookie 和 Session 之间的桥梁
(3)Cookie 和 Session 经常会在⼀起配合使⽤. 但是不是必须配合
- 完全可以⽤ Cookie 来保存⼀些数据在客⼾端.这些数据不⼀定是⽤⼾⾝份信息,也不⼀定 是SessionId
- Session 中的sessionId 也不需要⾮得通过 Cookie/Set-Cookie 传递,⽐如通过URL传递
3. get和post的区别
使用习惯上有区别 :
(1)语义不同: 从语义上来说GET 通常用于获取数据, POST 通常用于提交数据.
(2)传递数据的时候,GET通常使用query string,POST通常使用body
(3)服务器对于GET 请求,经常设计成是幂等的,POST 请求设计则不要求幂等(如果多次请求得到的结果一样, 就视为请求是幂等的)。这个要求只是HTTP协议标准文档给出的建议。
(4)GET 请求的结果可以被缓存, 可以被浏览器收藏夹收藏,POST 一般不行。 (这一点也是承接幂等性)。一个网站通过GET获取到一些图片,比如搜狗的主页,搜索栏上面的logo,像这个图片,就是通过浏览器,浏览器通过GET请求从服务器获取到,我们通过抓包,就看不到是哪个请求是获取图片,之所以没有看到就是被缓存了。要想看到,按住crtl在点击刷新。浏览器就可以缓存这些图片,下次访问这个网站就不必从网络获取了,直接从之前缓存的数据读取(缓存在硬盘上的)。
4. HPPT常见的状态码
(1)200 OK //客户端请求成功
(2)301 Permanently Moved (永久移除),请求的 URL 已移走。Response 中应该包含一个 Location URL, 说明资源现在所处的位置
(3)302 Temporarily Moved 临时重定向
(4)400 Bad Request //客户端请求有语法错误,不能被服务器所理解
(5)401 Unauthorized //请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用
(6)403 Forbidden //服务器收到请求,拒绝提但是供服务(权限不足,例如登录之后才能访问)
(7)404 Not Found //请求资源不存在,eg:输入了错误的 URL
(8)500 Internal Server Error //服务器内部错误,例如空指针,下标越界
(9)503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
5. HTTPS加密过程
【JavaEE初阶】HTTPS协议加密过程_运营商劫持 事件-CSDN博客
6. 三次握手
7.四次挥手
8. 浏览器输入url,发生什么?
(1)URL解析:浏览器接收到用户在地址栏输入的url,并进行解析。url包括:协议,主机名,端口号,路径,查询参数等信息。
(2)DNS解析:浏览器需要将主机名解析为对应的IP地址,以便无服务器进行建立连接。
(3)建立连接:通过三次握手来与服务器建立连接,确保通信双方能够正常通信。
(4)发起请求:建立连接后,浏览器会向服务器发送HTTP请求,这个请求包括请求方法,路径,请求头,请求体,还会进行SSL/TLS握手过程进行安全加密通信。
(5)服务器返回响应
(6)页面渲染
9. TCP/IP
应用层:应用层是用户与网络应用程序之间的接口。它为用户提供各种网络服务,例如网页浏览、电子邮件、文件传输等。
传输层:传输层负责在两个主机之间建立端到端的通信。它提供了数据传输的可靠性和流量控制。TCP,UDP
网络层:网络层负责将数据包从源主机传输到目标主机。它处理路由选择和数据包转发,确保数据包能够跨网络传输。IP地址
链路层:链路层负责在相邻节点之间传输数据帧。它处理物理链路的错误检测和纠正,确保数据帧的可靠传输。MAC地址
物理层:理层负责在物理介质上进行数据的传输。它处理信号的传输、电气特性、物理连接等。
🍃测试
1. 什么是软件测试
定义:验证软件产品的特性是否满足用户需求
简单的理解为就是找Bug,发现缺陷;查看当前这个软件是否做了其应该做的,还查看当前这个软件是否做了其不应该做的。
2. 什么是需求
用户需求:用户需求:可以简单理解为甲方提出的需求,如果没有甲方,那么就是终端用户使用产品时必须要完成的任务。该需求一般比较简略,通常是一句话。
软件需求:或者叫功能需求,该需求会详细描述开发人员必须实现的软件功能。软件需求是测试人员进行测试工作的基本依据。
3. 软件的生命周期
需求分析——计划——设计——编码——测试——运行维护
4. 常见的开发模型
瀑布模型:
优点/特点:
- 强调开发的阶段性
- 线性结构,每个阶段只执行一次
- 是其他模型的基础框架
缺点:
- 测试后置
- 前⾯各阶段遗留的风险推迟到测试阶段才被发现,导致项目大面积返工,失去了及早修复的机会
- 必须留有足够的时间给测试活动,否则导致测试不充分,将缺陷直接暴露给用户(产品质量差)
- 周期太长,产品很迟才能被看到和使用,可能会导致需求/功能过时
瀑布模型的适用场景:需求固定的小项目
螺旋模型:
螺旋模型中,各个阶段都引入了风险分析和原型,如进行需求分析之前,会有一个原型,我们就会针对这个原型进行风险分析,是否合理,合理就进行下一步,不合理重新再来。原型也就是各个阶段之前的模型。
优点/特点:
- 强调严格的全过程风险管理
- 强调各开发阶段的质量
- 增加⻛险分析和原型
缺点:
- 项目中可能存在的风险性与风险管理人员的技能水平有直接关系
- 需求人员、资金、时间的增加和投入,可能会导致项目的成本太高
适用场景:规模庞大、复杂度高、风险大的项目
5. 软件测试的生命周期
软件测试贯穿于软件的整个生命周期,针对这句话我们一起来看一下软件测试是如何贯穿软件的整个生命周期。
各阶段具体内容:
6. 如何描述一个Bug
描述bug的基本要素:问题出现的版本、问题出现的环境、问题出现的步骤、预期结果、实际结果
7. Bug的生命周期
测试人员在执行测试的过程中如有发现bug,需要在对应的bug管理平台来创建bug(bug生命起 源),创建好的bug需要被开发人员修复,以及测试人员的持续跟踪和测试。
测试人员应该跟踪一个Bug的整个生命周期,从Open到Closed的所有状态。
● New:新发现的Bug,未经评审决定是否指派给开发人员进行修改。
● Open:确认是Bug,并且认为需要进行修改,指派给相应的开发人员。
● Fixed:开发人员进行修改后标识成修改状态,有待测试人员的回归测试验证。
● Rejected:如果认为不是Bug,则拒绝修改。
● Delay:如果认为暂时不需要修改或暂时不能修改,则延后修改(级别低&时间不够)。
● Closed:修改状态的Bug经测试人员的回归测斌验证通过,则关闭Bug。
● Reopen:如果经验证Bug仍然存在,则需要重新打开Bug,开发人员重新修改。
无效的bug:open->closed 或 open-rejected-closed
8. 黑盒测试
链接:【软件测试】设计测试用例-CSDN博客
9. 白盒测试
链接:【软件测试】测试的分类-CSDN博客
10. 测试的分类
链接:【软件测试】测试的分类-CSDN博客
11. 性能测试
首先可以添加一个测试计划,在测试计划中添加一个线程组,可以设置线程数,持续时间以及循环次数;在线程组中通过取样器添加一个HTTP请求,可以设置它的协议,IP地址,端口号,请求方式以及路径,还可以添加参数。此时就可以对这个接口进行压测或者并发测试;也可以通过监听器中的查看结果数,来观察发送的请求是否成功以及返回结果。
🎍数据库
1. MySQL的事务
事务的基本要素:
原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位
一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
事务的并发问题:
脏读:数据库中,如果有事务A和事务B,事务A针对某个表做出了一些修改,在事务A提交(事务执行完毕;commit)之前,事务B就对这里的数据进行了读取。最终就可能会出现A后续读取的数据和B读取的数据是不同的。
解决办法:针对"写操作"进行加锁,也就是A在写的时候,B不能读,等到A写完了,B才能读。
不可重复读:存在三个事务ABC,现在事务A针对数据进行修改提交,事务B进行读取数据(事务B可能要读取多个sql),事务C又针对数据进行修改(因为上述只针对"写操作"加锁,没有针对"读操作加锁"),就会使事务B里面的不同读操作,读出来的结果不一样。
解决办法:进一步约定,给"读操作"加锁,上述造成"不可重复读问题"是因为B在读的时候,C进行了写,现在给"读操作"加锁之后。就达到了在读的时候不能写,在写的时候不能读。
幻读:事务A先修改并提交数据,事务B进行读数据,此时事务C没有修改事务B的数据,但是给对应的表进行了新增数据/删除数据等操作,导致事务B中,读到的数据集不同(内容一致,数据的条数增加/减少)。
可以认为是不可重复读的一种特殊情况,不可重复读强调的是数据内容变了,幻读强调的是数据集合变了。
解决办法:"串行化",使所有的事务都严格按照"一个接一个"的方式执行,这时候完全没有并发了,此时执行效率是最低的,隔离性是最高的,数据也是最准确的。