目录
- 怎么看待测开
- 对测试开发的理解
- 你认为测试人员需要具备哪些素质。
- 项目中遇到的困难 怎么解决
- 单例模式的多种实现
- JVM的GC机制
- JVM的内存结构
- 内存泄露
- 如何避免内存泄漏?
- 栈中存储的是什么
- Arrays.sort的原理
- 归并排序和快速排序的原理
- 快排的时间复杂度,最坏情况,以及基本思路
- 为什么数据量大使用快速排序更好?
- 数据库索引
- 不适合做数据库索引的字段
- 适合做数据库索引的字段
- 数据库 查询姓名包含张三的记录,查询前十条记录
- delete\drop\truncate的区别
- 两个数字 不用额外空间进行交换
- 数据库事务四大特性
- 输入url页面的反应过程
- HTTP请求方法、请求头
- get\post区别
- mysql数据库和redis区别
- redis如何保证一致性,使用redis缓存有啥优点
- http一次请求的过程
- TCP和UDP的区别
- 死锁的发生
- Linux系统进程的通信
- 进程通信的方式
- Linux 常用命令
- Linux如何查询和杀死一个进程
- 如何判断链表是否有环
- Git命令的介绍
- Git提交代码完整流程
- git pull和git fetch的区别
- 怎么做接口测试
- 如何进行页面自动化测试?
- 如何进行接口自动化测试
- HashMap底层原理
- Mysql查询底层原理
- HashMap扩容机制
- HashMap和HashTable的区别
怎么看待测开
首先,在近几年,国内对软件测试越来越重视,测试的前景是非常好的。其次,测试在一个项目开发的过程中是非常重要的一环。开发人员很难在开发的时候又要全面兼顾产品的质量,测试人员就是项目内部的最后把关者,最大程度的保证项目上线不会出现问题。责任非常大,责任越大成就感就越大。我很喜欢这样的工作。
对测试开发的理解
测试开发首先离不开测试,而软件测试是指,在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。而且,现在不仅仅是通过手工测试来发现定位Bug,也会通过编写脚本、测试工具来完成自动化测试,因此,对于测试开发人员来说,他除了保证产品质量之外,还要编写脚本以及开发测试工具。这就是我对测试开发的一点理解。
你认为测试人员需要具备哪些素质。
良好的测试基础理论;首先要有一定的沟通协调能力,因为测试人员经常会与开发人员接触处理一些问题,需要心平气和地沟通。还需要有一定的耐心,不能放过每一个错误;要有责任感,要尽自己最大的能力,保证产品的质量。要有好奇心,保持一种怀疑的态度,测试人员的任务是找出缺陷,不是证明没有缺陷,所以需要保持怀疑。要细心;乐观;
项目中遇到的困难 怎么解决
遇到的困难就是在做实验时的时候,模型调试一直不对,卡了很久。然后开始从头检查数据,模型参数,发现都是对着,所以没有头绪的时候,就开始百度或者查查之前的文章,重新找一下灵感,再继续做。
单例模式的多种实现
饿汉式(线程安全,可用)
缺点:类一加载的时候,就实例化,提前占用了系统资源
常量式(线程安全,可用)
缺点:类一加载的时候,就实例化,提前占用了系统资源
懒汉式(线程不安全,并发场景不可用)
缺点:第一次加载时反应稍慢,线程不安全。
同步的懒汉式?(线程安全,可用,不建议使用)
缺点:第一次加载时反应稍慢,每次调用getInstance都进行同步,造成不必要的同步开销,这种模式一般不建议使用。
双重检查锁 DCL (线程安全,大多数场景满足需求,推荐使用)
优点:资源利用率高,第一次执行getInstance时单例对象才会被实例化,效率高。
缺点:第一次加载时反应稍慢,也由于Java内存模型的原因偶尔会失败。在高并发环境下也有一定的缺陷,虽然发生的概率很小。DCL模式是使用最多的单例实现方式,它能够在需要时才实例化单例对象,并且能够在绝大多数场景下保证单例对象的唯一性,除非你的代码在并发场景比较复杂或者低于jdk1.6版本下使用,否则这种方式一般能够满足需求。
静态内部类(线程安全,推荐使用)
枚举单例(线程安全,不建议使用)
优点:枚举实现单例很简单,也很安全。
缺点:经验丰富的 Android 开发人员都会尽量避免使用枚举。官方文档有说明:相比于静态常量Enum会花费两倍以上的内存。
另类实现——利用容器实现单例
利用了 HashMap 容器 key 不可重复的特性。
优点:这种实现方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一接口进行获取操作,降低用户使用成本,也对用户隐藏了具体实现,降低耦合度。
缺点:没有私有化构造方法,用户可以 new 出新的实例对象。
JVM的GC机制
JAVA GC(Garbage Collection,垃圾回收)
随着程序的运行,内存中的实例对象、变量等占据的内存越来越多,如果不及时进行回收,会降低程序运行效率,甚至引发系统异常。
在上面介绍的五个内存区域中,有3个是不需要进行垃圾回收的:本地方法栈、程序计数器、虚拟机栈。因为他们的生命周期是和线程同步的,随着线程的销毁,他们占用的内存会自动释放。所以,只有方法区和堆区需要进行垃圾回收,回收的对象就是那些不存在任何引用的对象。
常见的GC算法:复制、标记-清除和标记-压缩
JVM的内存结构
根据JVM规范,JVM把内存划分成了如下几个区域:
1.方法区(Method Area)
2.堆区(Heap)
3.虚拟机栈(VM Stack)
4.本地方法栈(Native Method Stack)
5.程序计数器(Program Counter Register)
其中,方法区和堆所有线程共享。
方法区存放了要加载的类的信息(如类名、修饰符等)、静态变量、构造函数、final定义的常量、类中的字段和方法等信息。
堆区(Heap)堆区由所有线程共享,在虚拟机启动时创建。堆区主要用于存放对象实例及数组,所有new出来的对象都存储在该区域。
虚拟机栈(VM Stack)虚拟机栈占用的是操作系统内存,每个线程对应一个虚拟机栈,它是线程私有的,生命周期和线程一样,每个方法被执行时产生一个栈帧(Statck Frame),栈帧用于存储局部变量表、动态链接、操作数和方法出口等信息,当方法被调用时,栈帧入栈,当方法调用结束时,栈帧出栈。
本地方法栈(Native Method Stack)本地方法栈用于支持native方法的执行,存储了每个native方法的执行状态。
程序计数器(Program Counter Register)它的作用是:JVM在解释字节码(.class)文件时,存储当前线程执行的字节码行号,只是一种概念模型,各种JVM所采用的方式不一样。字节码解释器工作时,就是通过改变程序计数器的值来取下一条要执行的指令,分支、循环、跳转等基础功能都是依赖此技术区完成的
内存泄露
内存泄露是指:内存泄漏也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
常见的内存泄露造成的原因
单例造成的内存泄漏
由于单例的静态特性使得其生命周期和应用的生命周期一样长,如果一个对象已经不再需要使用了,而单例对象还持有该对象的引用,就会使得该对象不能被正常回收,从而导致了内存泄漏。
非静态内部类创建静态实例造成的内存泄漏
Handler造成的内存泄漏
线程造成的内存泄漏
资源未关闭造成的内存泄漏
对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,从而造成内存泄漏。
使用ListView时造成的内存泄漏
集合容器中的内存泄露
WebView造成的泄露
如何避免内存泄漏?
平常养成良好的代码书写习惯,该销毁的对象要销毁比如destory啊 广播啊 ,涉及到要用到content上下文的优先考虑全局上线文对象。
栈中存储的是什么
一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
Arrays.sort的原理
双轴快排的算法,总的来说, Arrays.sort使用了两种排序方法,快速排序和优化的合并排序。
快速排序使用的是分治思想,将原问题分成若干个子问题进行递归解决。选择一个元素作为轴(pivot),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比轴元素小,另外一部分的所有数据都比轴元素大,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。双轴快排(DualPivotQuicksort),顾名思义有两个轴元素pivot1,pivot2,且pivot ≤pivot2,将序列分成三段:x < pivot1、pivot1 ≤ x ≤ pivot2、x >pivot2,然后分别对三段进行递归。这个算法通常会比传统的快排效率更高,也因此被作为Arrays.java中给基本类型的数据排序的具体实现。
归并排序和快速排序的原理
归并排序基本原理
归并排序使用了一个被称为分治法的通用模式,在分治法中,我们将问题分解为类似于原子问题的问题,递归的求解这些子问题,然后再合并这些自问题的解来得出原问题的解。
分治法的一般步骤
1、分解:把一个问题分解为多个子问题,这些子问题是更小实例上的原问题。
2、解决:递归求解自问题。当子问题足够小时,按照基础情况求解。
3、合并:把自问题的解合并为原问题的解。
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
快速排序基本原理
和归并排序一样,快速排序也使用分治模式
假设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一躺快速排序。一躺快速排序的算法是:
1、设置两个变量I、J,排序开始的时候I:=1,J:=N-1;
2、以第一个数组元素作为关键数据,赋值给X,即X=A[1];
3、从J开始向前搜索,即由后开始向前搜索(J=J-1),找到第一个小于X的值,两者交换;
4、从I开始向后搜索,即由前开始向后搜索(I=I+1),找到第一个大于X的值,两者交换;
5、重复第3、4步,直到I=J;
快排的时间复杂度,最坏情况,以及基本思路
快速排序的时间性能取决于快速排序递归的深度,最优的情况下,快速排序算法的时间复杂度为O(nlogn)。在最坏的情况下,待排序的序列为正序或者逆序,其时间复杂度为O(n2)。分治法的基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。
为什么数据量大使用快速排序更好?
快速排序果然是快,数据越大优势越明显,并且实现上也较为简单。理论上它的平均时间和归并排序,堆排序都是一样的(在最坏情况还还不如它们),都是O(nlog2n),但实际运行来看比它们两者的速度都快一倍以上。
数据库索引
一、数据索引是干什么用的呢?
数据库索引其实就是为了使查询数据效率快。
二、数据库索引有哪些呢?
聚集索引(主键索引):在数据库里面,所有行数都会按照主键索引进行排序。
非聚集索引:就是给普通字段加上索引。
联合索引:就是好几个字段组成的索引,称为联合索引
不适合做数据库索引的字段
性别
理论文章会告诉你值重复率高的字段不适合建索引。不要说性别字段只有两个值,网友亲测,一个字段使用拼音首字母做值,共有26种可能,加上索引后,百万加的数据量,使用索引的速度比不使用索引要慢!
适合做数据库索引的字段
1、表的某个字段值得离散度越高,该字段越适合选作索引的关键字。主键字段以及唯一性约束字段适合选作索引的关键字,原因就是这些字段的值非常离散。MySQL 在处理主键约束以及唯一性约束时,考虑周全。数据库用户创建主键约束的同时, MySQL 自动创建主索引( primary index ),且索引名称为 Primary;数据库用户创建唯一性索引时, MySQL 自动创建唯一性索引( unique index ),默认情况下,索引名为唯一性索引的字段名。
2、占用存储空间少的字段更适合选作索引的关键字。例如,与字符串相比,整数字段占用的存储空间较少,因此,较为适合选作索引关键字。
3、存储空间固定的字段更适合选作索引的关键字。与 text 类型的字段相比, char 类型的字段较为适合选作索引关键字。
4、Where 子句中经常使用的字段应该创建索引,分组字段或者排序字段应该创建索引,两个表的连接字段应该创建索引。
5、更新频繁的字段不适合创建索引,不会出现在 where 子句中的字段不应该创建索引。
数据库 查询姓名包含张三的记录,查询前十条记录
select top 10 * form 表 where name like 张三
delete\drop\truncate的区别
1、delete和truncate仅仅删除表中的数据,drop连同数据和表的结构一起全部删除,打个比方,delect是是删除电脑上的一个文件,truncate是删除一个文件夹,drop是格式化磁盘。
2、delect是DML语句,操作完以后如果没有提交事务还可以回滚,truncate和drop是DDL语句,操作即生效,无法回滚,打个比方,delete是删除文件了,还可以去回收站找回,truncate和drop是直接被永久从磁盘上清除了,无法找回来。
3、执行的速度是,drop>truncate>delete,打个比方,drop是光速,truncate是飞机,delete是自行车。
两个数字 不用额外空间进行交换
利用了异或运算的性质:
相同的两个数异或结果为0,任何数与0异或结果还是其自身,异或运算满足交换律和结合律
于是将xy的结果赋予x,接着再将x与y异或,此时y的值就是xy^y = x(yy) = x,也就是说y拿到了x原本的值。
此时x依然是两数异或的结果,而y是x原本的值,接着进行xy就等同于xy^x = y, 于是x就拿到了y原本的值。这种方法很巧妙,也不太好理解,但是不存在溢出的情况。
数据库事务四大特性
1、原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
2、一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
3、隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
4、持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
输入url页面的反应过程
总体来说分为以下几个过程:
DNS解析
TCP连接
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面
连接结束
HTTP请求方法、请求头
HTTP是超文本传输协议,其定义了客户端与服务器端之间文本传输的规范。
请求方法GET, POST 和 HEAD方法。OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法
请求头
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:
User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。
get\post区别
最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数。
GET 用于获取信息,是无副作用的,是幂等的,且可缓存
POST 用于修改服务器上的数据,有副作用,非幂等,不可缓存
GET产生一个TCP数据包;POST产生两个TCP数据包。
mysql数据库和redis区别
1.mysql和redis的数据库类型
mysql是关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。
redis是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限。
2.mysql的运行机制
mysql作为持久化存储的关系型数据库,相对薄弱的地方在于每次请求访问数据库时,都存在着I/O操作,如果反复频繁的访问数据库。第一:会在反复链接数据库上花费大量时间,从而导致运行效率过慢;第二:反复的访问数据库也会导致数据库的负载过高,那么此时缓存的概念就衍生了出来。
3.缓存
缓存就是数据交换的缓冲区(cache),当浏览器执行请求时,首先会对在缓存中进行查找,如果存在,就获取;否则就访问数据库。
缓存的好处就是读取速度快
4.redis数据库
redis数据库就是一款缓存数据库,用于存储使用频繁的数据,这样减少访问数据库的次数,提高运行效率。
5.redis和mysql的区别总结
(1)类型上
从类型上来说,mysql是关系型数据库,redis是缓存数据库
(2)作用上
mysql用于持久化的存储数据到硬盘,功能强大,速度较慢,基于磁盘,读写速度没有Redis快,但是不受空间容量限制,性价比高
redis用于存储使用较为频繁的数据到缓存中,读取速度快,基于内存,读写速度快,也可做持久化,但是内存空间有限,当数据量超过内存空间时,需扩充内存,但内存价格贵
(3)需求上
mysql和redis因为需求的不同,一般都是配合使用。
需要高性能的地方使用Redis,不需要高性能的地方使用MySQL。存储数据在MySQL和Redis之间做同步。
redis如何保证一致性,使用redis缓存有啥优点
Redis优点
内存操作数据速度快
IO复用,速度快
单线程模型,避免线程切换带来的开销,速度快
1.MySQL持久化数据,Redis只读数据
redis在启动之后,从数据库加载数据。读请求:不要求强一致性的读请求,走redis,要求强一致性的直接从mysql读取写请求:数据首先都写到数据库,之后更新redis(先写redis再写mysql,如果写入失败事务回滚会造成redis中存在脏数据)
2.MySQL和Redis处理不同的数据类型
MySQL处理实时性数据,例如金融数据、交易数据Redis处理实时性要求不高的数据,例如网站最热贴排行榜,好友列表等
在并发不高的情况下,读操作优先读取redis,不存在的话就去访问MySQL,并把读到的数据写回Redis中;写操作的话,直接写MySQL,成功后再写入Redis(可以在MySQL端定义CRUD触发器,在触发CRUD操作后写数据到Redis,也可以在Redis端解析binlog,再做相应的操作)
在并发高的情况下,读操作和上面一样,写操作是异步写,写入Redis后直接返回,然后定期写入MySQL
http一次请求的过程
建立TCP连接
Web浏览器向Web服务器发送请求命令
Web浏览器发送请求头信息
Web服务器应答
Web服务器发送应答头信息
Web服务器向浏览器发送数据
Web服务器关闭TCP连接
TCP和UDP的区别
TCP/IP 是互联网相关的各类协议族的总称
UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。
死锁的发生
发生死锁时,进程永远不能完成,系统资源被阻碍使用,以致于阻止了其他作业开始执行。
必要条件
如果在一个系统中以下四个条件同时成立,那么就能引起死锁:
互斥:至少有一个资源必须处于非共享模式,即一次只有一个进程可使用。如果另一进程申请该资源,那么申请进程应等到该资源释放为止。
占有并等待:—个进程应占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有。
非抢占:资源不能被抢占,即资源只能被进程在完成任务后自愿释放。
循环等待:有一组等待进程 {P0,P1,…,Pn},P0 等待的资源为 P1 占有,P1 等待的资源为 P2 占有,……,Pn-1 等待的资源为 Pn 占有,Pn 等待的资源为 P0 占有。
我们强调所有四个条件必须同时成立才会出现死锁。循环等待条件意味着占有并等待条件,这样四个条件并不完全独立。
Linux系统进程的通信
进程的概念
进程是操作系统的概念,每当我们执行一个程序时,对于操作系统来讲就创建了一个进程,在这个过程中,伴随着资源的分配和释放。可以认为进程是一个程序的一次执行过程。
进程通信的概念
进程用户空间是相互独立的,一般而言是不能相互访问的。但很多情况下进程间需要互相通信,来完成系统的某项功能。进程通过与内核及其它进程之间的互相通信来协调它们的行为。
进程通信的应用场景
数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。
共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
进程通信的方式
管道( pipe ):
管道包括三种:
普通管道PIPE: 通常有两种限制,一是单工,只能单向传输;二是只能在父子或者兄弟进程间使用.
流管道s_pipe: 去除了第一种限制,为半双工,只能在父子或兄弟进程间使用,可以双向传输.
命名管道:name_pipe:去除了第二种限制,可以在许多并不相关的进程之间进行通讯.
信号量( semophore ) :
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
消息队列( message queue ) :
消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号 ( sinal ) :
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存( shared memory ) :
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
套接字( socket ) :
套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
Linux 常用命令
——系统管理命令::su 切换账户
Ifconfig 查看IP地址
Ping 检查网络是否连接
Kill杀死进程
Kill -9 强制杀死
——系统资源查询命令:ps 查看进程
Ps -ef 查看所有的进程
Netstat查看网络状况
Netstat-apn查看所有的端口
——管道命令:Ps -ef | grep xiaobao
查看所有进程,通过管道找到相应的进程包名
Kill -9 杀死进程
Chmod赋权命令 chmod -R 777 XIAOBAI
——目录操作命令:cd xiaobai 进入目录里面
cd / 根目录
pwd当前目录
mkdir 创建目录
rmdir 删除目录
ls ll 查看说有的目录
——文件编辑就命令:vi a.txt 编辑文件
Cat a.txt 查看文件
rm -rf 强制删除
find / -name .txt 在根目录下面查找txt文件
——文件解压压缩命令:
压缩 tar -czvf test.tar.gz.test 将文件压缩成.test.tar.gz
解压 tar -xzvf test.tar.gz.test将文件解压成.test.tar.gz
Linux如何查询和杀死一个进程
ps -ef|grep 进程名
kill -9 进程号
如何判断链表是否有环
对于这个问题我们可以采用“快慢指针”的方法。就是有两个指针fast和slow,开始的时候两个指针都指向链表头head,然后在每一步操作中slow向前走一步即:slow = slow->next,而fast每一步向前两步即:fast = fast->next->next。
由于fast要比slow移动的快,如果有环,fast一定会先进入环,而slow后进入环。当两个指针都进入环之后,经过一定步的操作之后
二者一定能够在环上相遇,并且此时slow还没有绕环一圈,也就是说一定是在slow走完第一圈之前相遇。
Git命令的介绍
git add # 将工作区的修改提交到暂存区
git commit # 将暂存区的修改提交到当前分支
git reset # 回退到某一个版本
git stash # 保存某次修改
git pull # 从远程更新代码
git push # 将本地代码更新到远程分支上
git reflog # 查看历史命令
git status # 查看当前仓库的状态
git diff # 查看修改
git log # 查看提交历史
git revert # 回退某个修改
Git提交代码完整流程
预备:先拉代码 Git pull
第一步:把更改的代码暂存起来
Git add
第二步:把暂存的改动提交到本地的版本库
git commit
第三步:将本地的分支版本上传到远程并合并
git push <远程主机名> <本地分支名>:<远程分支名>
一般情况下,我们都不用写后面的,直接 git push 即可。
git pull和git fetch的区别
git pull # 从远程更新代码
相同点
首先在作用上他们的功能是大致相同的,都是起到了更新代码的作用。
Git fetch和git pull区别为:远端跟踪分支不同、拉取不同、commitID不同。
一、远端跟踪分支不同
1、Git fetch:Git fetch能够直接更改远端跟踪分支。
2、git pull:git pull无法直接对远程跟踪分支操作,我们必须先切回本地分支然后创建一个新的commit提交。
二、拉取不同
1、Git fetch:Git fetch会将数据拉取到本地仓库 - 它并不会自动合并或修改当前的工作。
2、git pull:git pull是从远程获取最新版本并merge到本地,会自动合并或修改当前的工作。
三、commitID不同
1、Git fetch:使用Git fetch更新代码,本地的库中master的commitID不变,还是等于1。
2、git pull:使用git pull更新代码,本地的库中master的commitID发生改变,变成了2。
Selenium 八种元素定位方法
Id name xpath class tag link partial_link CSS
怎么做接口测试
–由于我们项目前后端调用主要是基于http协议的接口,所以测试接口时主要是通过工具或代码模拟http请求的发送与接收。工具有很多如:postman、jmeter、soupUI、java+httpclient、robot framework+httplibrary等。也可以用 接口自动化来实现,就是用代码实现,框架和UI自动化差不多,发送请求用断言来判断。
如何进行页面自动化测试?
使用selenium,建立一个测试工程,在工程里创建一个测试文件, 运行这个测试,你将看到firebox浏览器被自动启动,然后会自动的输入selenum并搜索。
如何进行接口自动化测试
其测试的基本原理是模拟前端(客户端)向服务器发送数据,得到相应的响应数据,从而判断接口是否可以正常的进行数据交换。
打开测试用例的Excel表格,填写用例编号、接口描述信息,被测接口的域名和请求地址。
选择接口请求的方式,目前有两种,一种是POST,一种是GET,根据实际情况选择。
选择接口接收数据的方式,目前有三种,Form类型,请求的数据会进行urlencode编码,一般都是这种类型,官网的接口主要是这种;Data类型,以文本的形式直接请求接口,不经过urlencode编码,引擎的接口大部分是这种,选择Data类型时,请求的数据有两种,一种是直接在Excel中配置json字符串,一种是填写文本文件路径,文件中也是json字符串,主要在于post的数据很大时,比如保存案例,在Excel中不好管理。File类型表示上传文件,在测试上传时选择File类型。
配置需要向接口发送的数据,
配置数据是否需要编码加密,目前有三种,不加密,MD5加密和DES加密。这是根据我们自身项目的特点加的选项,引擎有几个接口需要进行MD5加密,场景秀的接口都经过了DES加密。
配置检查点,检查点的目的是校验接口返回的数据是否是我们期望的。
配置关联,在接口的测试过程中,两个接口常常会有相关性,比如引擎新建案例需要先登录官网,那么,就需要做前后接口数据的关联
HashMap底层原理
哈希表(hash table)也叫散列表,是一种非常重要的数据结构,
在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同-hash值的链表都存储在一个链表里。
但是当位于一个桶中的元素较多 ,即hash值相等的元素较多时,通过key值依次查找的效率较低。而DK1.8中,哈
希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找
时间。
Mysql查询底层原理
1、连接器管理
首先是数据库连接器,主要负责和客户端建立连接、权限获取、管理连接等,由于整个建连的过程比较复杂,所以尽量使用长连接。
如果数据库发生异常后为了快速恢复,可重启系统重新建立连接。
2、Mysql缓存
mysq|请求首先看缓存数据,key为sqi语句value为查询的结果, 如果存在则直接返回。如果没有则直接往下走。
注意: mysq|缓存对于一些静态数据比较适合 ,对于实时性高的数据最好不要使用。
3、分析器.
对你执行的sq语句进行解析,首先是词法分析包括一些关键字识别, 然后语法分析,查看这条语句是否符合mysq语句
4、优化器
通过你的语句分析,发现那些查询命中索引,还有表之间的连接顺序等
5、执行器
通过上面一系列的验证,使用弓|擎提供的接口。经过不断的执行将查询的结果存放在结果集中,通过explain可以看到执行器具 体扫描
了多少行。
HashMap扩容机制
HashMap使用的是懒加载,构造完HashMap对象后,只要不进行put 方法插入元素之前,HashMap并不会去初始化或者扩容table。当首次调用put方法时,HashMap会发现table为空然后调用resize方法进行初始化,当添加完元素后,如果HashMap发现size(元素总数)大于threshold(阈值),则会调用resize方法进行扩容
扩容过程:
若threshold(阈值)不为空,table的首次初始化大小为阈值,否则初始化为缺省值大小16,
默认的负载因子大小为0.75,当一个map填满了75%的bucket时候,就会扩容,扩容后的table大小变为原来的两倍
假设扩容前的table大小为2的N次方,有上述put方法解析可知,元素的table索引为其hash值的后N位确定
扩容后的table大小即为2的N+1次方,则其中元素的table索引为其hash值的后N+1位确定,比原来多了一位
重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing
因此,table中的元素只有两种情况:
元素hash值第N+1位为0:不需要进行位置调整
元素hash值第N+1位为1:调整至原索引的两倍位置
扩容或初始化完成后,resize方法返回新的table
HashMap和HashTable的区别
HashMap 不是线程安全的
HashMap 是 map 接口的实现类,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值。HashMap 允许 null key 和 null value,而 HashTable 不允许。
HashTable 是线程安全 Collection。
HashMap 是 HashTable 的轻量级实现,他们都完成了Map 接口,主要区别在于 HashMap 允许 null key 和 null value,由于非线程安全,效率上可能高于 Hashtable。
区别如下:
HashMap允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许。
HashMap 把 Hashtable 的 contains 方法去掉了,改成 containsValue 和 containsKey。因为 contains 方法容易让人引起误解。
HashTable 继承自 Dictionary 类,而 HashMap 是 Java1.2 引进的 Map interface 的一个实现。
HashTable 的方法是 Synchronize 的,而 HashMap 不是,在多个线程访问 Hashtable 时,不需要自己为它的方法实现同步,而 HashMap 就必须为之提供外同步。
Hashtable 和 HashMap 采用的 hash/rehash 算法都大概一样,所以性能不会有很大的差异。