i一、自我介绍
***********************************************************************************
二、项目
介绍一个做过的印象最深刻的项目。觉得在项目中自己的贡献是什么?
项目中遇到的最困难的问题?如何解决的?
项目介绍(STAR)+ 技术难点+ 解决方案(建议准备2个)
***********************************************************************************
三、常规问题
(1)为什么投测试开发岗?(对岗位的理解+JD与自我匹配+未来发展)
***********************************************************************************
(2)测试开发与测试的区别?
测试工程师一般是从用户的角度出发,检测开发工程师开发的软件或系统是否符合产品的需求,关注用户的体验;测试开发工程师除了需要完成测试工程师需要做一些常规的业务测试外,还需要具有一定的编程能力,开发自动化测试工具,提高测试的效率,保证产品的质量,降低测试的成本。
(3)还有什么问题要问我?
***********************************************************************************
计算机基础知识及补充
1. 计算机网络
>>线程和进程的区别
(1)进程是资源分配和调度的一个独立单元,而线程是CPU调度的基本单位。(调度)
(2)同一个进程中可以并发多个线程,一个线程不能独立的存在,它必须是进程的一部分。(包含)
(3)线程是轻量级的进程,它的创建和销毁所需要的时间和空间的开销比进程小很多。(开销)
(4)线程有自己的私有属性线程控制块TCB,而进程也有自己的私有属性进程控制块PCB,这些私有属性是不被共享的,用来标示一个进程或一个线程的标志。(标志)
>>TCP/UDP的区别
(1)TCP面向连接,UDP是无连接的;
(2)TCP提供可靠的服务,UDP尽最大努力交付,不保证可靠交付;
(3)TCP有拥塞控制,UDP没有拥塞控制;
(4)每一条TCP连接只能是点到点的,UDP支持一对一,一对多,多对一和多对多的交互通信;
(5)TCP首部开销20字节;,UDP的首部开销小,只有8个字节;
(6)TCP的逻辑通信信道是全双工的可靠信道(建立连接后,客户端和服务器端进程可以同时发送和接收数据。),UDP则是不可靠信道。
TCP报文段和UDP报文段的结构:
>>TCP的可靠性保证
通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
应用数据被分割成TCP认为最适合发送的数据块,当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段 (超时重发) 。当TCP收到发自TCP连接另一端的数据,它将发送一个确认(确认应答)。这个确认不是立即发送,通常将推迟几分之一秒。TCP将保持它首部和数据的检验和,这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段 (校验出包有错,丢弃报文段,不给出响应,TCP发送数据端,超时时会重发数据)。既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层(对失序数据进行重新排序) 。既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据(丢弃重复数据)。
>>网络结构及网络协议
OSI分层(7层) :物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
TCP/IP分层(4层) :网络接口层、网际层、运输层、应用层
五层协议(5层) :物理层、数据链路层、网络层、运输层、应用层
应用层 |
HTTP、FTP、SMTP、DNS、NFS、Telnet等 |
运输层 |
TCP、UDP |
网络层 |
IP、ICMP、ARP、RARP等 |
链路层 |
以太网、高级链路控制、帧中继、PPP等 |
物理层 |
IEEE 802.1A、IEEE 802.2~IEEE 802.11 |
每一层的协议:
物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器,网关)
数据链路:PPP、FR、HDLC、VLAN、MAC (网桥,交换机)
网络层:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器)
传输层:TCP、UDP、SPX
会话层:NFS、SQL、NETBIOS、RPC
表示层:JPEG、MPEG、ASII
应用层:FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS
每一层的作用:
物理层:通过媒介传输比特,确定机械及电气规范(比特Bit)
数据链路层:将比特组装成帧和点到点的传递(帧Frame)
网络层:负责数据包从源到宿的传递和网际互连(包PackeT)
传输层:提供端到端的可靠报文传递和错误恢复(段Segment)
会话层:建立、管理和终止会话(会话协议数据单元SPDU)
表示层:对数据进行翻译、加密和压缩(表示协议数据单元PPDU)
应用层:允许访问OSI环境的手段(应用协议数据单元APDU)
TCP对应的协议:
(1) FTP :定义了文件传输协议,使用21端口。常说某某计算机开了FTP服务便是启动了文件传输服务。下载文件,上传主页,都要用到FTP服务。
(2) Telnet :它是一种用于远程登陆的端口,用户可以以自己的身份远程连接到计算机上,通过这种端口可以提供一种基于DOS模式下的通信服务。如以前的BBS是-纯字符界面的,支持BBS的服务器将23端口打开,对外提供服务。
(3) SMTP :定义了简单邮件传送协议,现在很多邮件服务器都用的是这个协议,用于发送邮件。如常见的免费邮件服务中用的就是这个邮件服务端口,所以在电子邮件设置-中常看到有这么SMTP端口设置这个栏,服务器开放的是25号端口。
(4) POP3 :它是和SMTP对应,POP3用于接收邮件。通常情况下,POP3协议所用的是110端口。即,只要你有相应的使用POP3协议的程序(例如Fo-xmail或Outlook),就可以不以Web方式登陆进邮箱界面,直接用邮件程序就可以收到邮件(如是163邮箱就没有必要先进入网易网站,再进入自己的邮-箱来收信)。
(5)HTTP协议: 是从 Web 服务器传输超文本到本地浏览器的传送协议。
UDP对应的协议:
(1) DNS :用于域名解析服务,将域名地址转换为IP地址。DNS用的是53号端口。
(2) SNMP :简单网络管理协议,使用161号端口,是用来管理网络设备的。由于网络设备很多,无连接的服务就体现出其优势。
(3) TFTP (Trival File Transfer Protocal),简单文件传输协议,该协议在熟知端口69上使用UDP服务。
>>DNS域名系统的工作原理
(1)客户机提出域名解析请求,并将该请求发送给本地的域名服务器。
(2)当本地的域名服务器收到请求后,就先查询本地的缓存,如果有该纪录项,则本地的域名服务器就直接把查询的结果返回。
(3)如果本地的缓存中没有该纪录,则本地域名服务器就直接把请求发给根域名服务器,然后根域名服务器再返回给本地域名服务器一个所查询域(根的子域) 的主域名服务器的地址。
(4)本地服务器再向上一步返回的域名服务器发送请求,然后接受请求的服务器查询自己的缓存,如果没有该纪录,则返回相关的下级的域名服务器的地址。
(5)重复第四步,直到找到正确的纪录。
(6)本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时还将结果返回给客户机。
例:当你在浏览器输入www.baidu.com的时候,先查询浏览器的缓存中是否有域名和IP的映射关系,如果没有则查询本地hosts文件,然后查询客户端DNS缓存(如果存在客户端缓存的话),下一步是本地DNS服务器,检查本地DNS服务器的hosts文件和DNS缓存,如果还没有则下一步是ISP,ISP检查缓存还是没有;则ISP向根服务器发起询问请求,根服务器向ISP返回com.的IP地址,ISP向com.发起询问请求,com.向ISP返回baidu.com.的IP,则ISP再想baidu.com.发起询问,刚好baidu.com.有www.baidu.com.的IP,向ISP返回该IP地址,ISP得到www.baidu.com的IP后,将IP返回本地DNS服务器,本地DNS服务器在返回给客户端。这样完成整个流程。
>>TCP三次握手和四次挥手
三次握手:
主机A向B发送连接请求;主机B对收到的主机A的报文段进行确认;主机A再次对主机B的确认进行确认。
(1)第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。(SYN=1, ACK=0)
(2)第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。(SYN=1, ACK=1)
(3)第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手,客户端与服务器开始传送数据。(ACK=1)
四次挥手:
(1)客户端A向服务器端B发送一个FIN,用来关闭A到B的数据传送。 (FIN=1)
(2)服务器B收到这个FIN,它返回一个ACK,确认序号为收到的序号加1。一个FIN将占用一个序号。 A到B的连接释放。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。(FIN=1, ACK=1)
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。 A到B的连接释放。(ACK=1)
为什么需要“三次握手”?
为了防止已失效的连接请求报文段突然又传送到了服务端,防止server端一直等待,浪费资源。
为什么需要“四次挥手”?
由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭。
TCP为什么会采用三次握手,若采用二次握手可以吗?
采用三次握手是为了防止失效的连接请求报文段突然又传送到主机B,因而产生错误。采用两次握手不行。
>>ARP协议的工作原理
完成IP地址到MAC地址的映射。
(1)首先,每个主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址之间的对应关系。
(2)当源主机要发送数据时,首先检查ARP列表中是否有对应IP地址的目的主机的MAC地址,如果有,则直接发送数据,如果没有,就向本网段的所有主机发送ARP数据包,该数据包包括的内容有:源主机 IP地址,源主机MAC地址,目的主机的IP 地址。
(3)当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC地址写入到ARP列表中,如果已经存在,则覆盖,然后将自己的MAC地址写入ARP响应包中,告诉源主机自己是它想要找的MAC地址。
(4)源主机收到ARP响应包后。将目的主机的IP和MAC地址写入ARP列表,并利用此信息发送数据。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
广播发送ARP请求,单播发送ARP响应。
>>长连接和短连接
短连接 :连接->传输数据->关闭连接
比如HTTP,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。但是HTTP也有长连接。
长连接:连接->传输数据->保持连接 -> 传输数据-> ………..->直到一方关闭连接,多是客户端关闭连接。 长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。
(注意:长连接和短连接都是相对于TCP来说的,UDP是无连接的。)
>>HTTP的请求报文和响应报文
请求报文:请求行(方法+URL+HTTP版本)+报文头部+报文主体
响应报文:状态行(HTTP版本+状态码+状态描述)+报文头部+报文主体
>>HTTP特点
(1)支持C/S模式。
(2)无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
(3)无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
(4)简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
(5)灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
>>HTTP与HTTPS的区别
HTTPS是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL。
>>HTTP工作步骤
客户发起建立TCP连接——>客户发送HTTP请求——>服务器返回HTTP请求——>释放此次TCP连接(——>建立新的TCP连接,因为HTTP是无状态的,每个事务独立处理)
>>HTTP 协议包括哪些请求
GET:请求读取由URL所标志的信息。
POST:给服务器添加信息(如注释)。
PUT:在给定的URL下存储一个文档。
DELETE:删除给定的URL所标志的资源。
(HTTP中的 GET,POST,PUT,DELETE 就对应着对URL资源的 查,改,增,删 4个操作。所以说:GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。)
>>Get和Post的区别
(1)get是从服务器上获取数据,post是向服务器传送数据。
(2)在客户端, get方式在通过URL提交数据,数据在URL中可以看到;post方式,数据放置在HTML HEADER内提交
(3)对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。
(4)get方式提交的数据最多只能有1024字节,而post则没有此限制
(5)安全性问题。正如在2中提到,使用get的时候,参数会显示在地址栏上,而 post 不会。所以,如果这些数据是中文数据而且是非敏感数据,那么使用 get ;如果用户输入的数据不是中文字符而且包含敏感数据,那么还是使用 post为好。
>>HTTP请求和响应的全过程
(1)连接:当输入一个请求时,首先建立一个socket连接(三次握手),因为socket是通过ip和端口建立的,所以,之前则还有一个DNS解析过程。如把www.baidu.com变成一个ip,如果url不包含端口号,则会使用该协议的默认端口号,HTTP协议的默认端口号为80。
(2)请求:连接成功后,开始向web服务器发送请求,这个请求一般是GET或POST请求。
(3)应答:web服务器收到这个请求,进行处理。web服务器会把文件内容传送给响应的web浏览器。 包括:HTTP头信息,体信息。
(4)关闭连接:当应答结束后,web浏览器与web服务器必须断开,以保证其它web浏览器能够与web服务器建立连接。
>>路由设备与相关层
物理层 :中继器(Repeater,也叫放大器),集线器。
数据链路层 :网桥,交换机。
网络层 :路由器。
网关 :网络层以上的设备。
>>常见的路由选择协议
常见的路由选择协议有:RIP协议、OSPF协议。
RIP协议 :底层是贝尔曼福特算法,它选择路由的度量标准(metric)是跳数,最大跳数是15跳,如果大于15跳,它就会丢弃数据包。
OSPF协议 :底层是迪杰斯特拉算法,是链路状态路由选择协议,它选择路由的度量标准是带宽,延迟。
>>IP地址
>>Socket通信(TCP编程)
TCP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt(); * 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、开启监听,用函数listen();
5、接收客户端上来的连接,用函数accept();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
8、关闭监听;
TCP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置要连接的对方的IP地址和端口等属性;
5、连接服务器,用函数connect();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
2.操作系统
>>什么是死锁?死锁产生的原因?死锁的必要条件?怎么处理死锁?
(1)死锁是相互等待资源而产生的一种僵持状态,如果没有外力的干预将一直持续这个状态。
(2)原因:系统资源不足、相互竞争资源、请求资源顺序不当
(3)必要条件:互斥、不可剥夺、循环等待、请求与保持
(4)处理:因为互斥是不可改变的,所以只能破坏其他三个条件中的一个来解除死锁,方法:剥夺资源、杀死其中一个线程
>>Windows内存管理方式
段存储、页存储、段页存储
>>进程的几种状态?
创建状态:进程在创建时需要申请一个空白PCB,向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态
就绪状态:进程已经准备好,已分配到所需资源,只要分配到CPU就能够立即运行
执行状态:进程处于就绪状态被调度后,进程进入执行状态
阻塞状态:正在执行的进程由于某些事件(I/O请求,申请缓存区失败)而暂时无法运行,进程受到阻塞。在满足请求时进入就绪状态等待系统调用
终止状态:进程结束,或出现错误,或被系统终止,进入终止状态。无法再执行
>>IPC进程通信方式?
(1)管道(匿名管道(pipe亲缘关系的进程通信)、命名管道(mkfifo/mknod))
(2)消息队列:是基于消息的、用无亲缘关系的进程间通信
(3)信号量:相当于一把互斥锁,通过p、v操作
(4)共享内存:是进程间通信速度最快的,所以用经常是集合信号量或互斥锁来实现同步
>>线程同步的机制。
(1)临界区。通过对多线程的串行化来访问公共资源或一段代码,速度快,适合 控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个 线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的 线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他 线程才可以抢占。
(2)互斥量。采用互斥对象机制。只有拥有互斥对象的线程才有访问公共资源的 权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。 互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的 公共资源安全共享 。
(3)信号量。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时 刻访问此资源的最大线程数目。
(4)事 件。通过通知操作的方式来保持线程的同步,还可以方便实现对多个线 程的优先级比较的操作。
>>常用的Linux命令
ls |
显示指定工作目录下之内容 |
列出/bin目录下所有名称是s开头的档案的详细资料(l),按最新时间顺序(t): ls -lt s* /bin |
cd |
变换工作目录 |
跳到 /usr/bin/ : cd /usr/bin 返回home:cd ~ |
pwd |
显示当前工作目录(路径) |
pwd |
mkdir |
创建目录 |
在工作目录下的A目录中,建立一个名为 Test 的子目录:mkdir -p A/Test |
rmdir |
删除目录 |
删除空目录:rmdir |
touch或vim |
创建文件 |
touch test.txt 或 vim test.txt |
rm |
删除文件或目录 |
删除test文件:rm test.txt 删除/bin目录下的所有文件(递归强制):rm -rf /bin |
cp |
复制文件或目录 |
将Test目录下的所有文件复制到当前目录:cp Test* ./ |
mv |
移动或更名现有的文件或目录 |
移动当前目录的test文件到上一级目录:mv test.txt ../ 更名文件: mv test.txt newTest.txt |
chmod |
变更访问权限 |
为所有用户增加对文件a.txt的读写权限:chmod a +rw a.txt |
file |
辨识文件类型 |
file |
find |
查找符合条件的文件或目录 |
…… |
cat |
文本输出 |
查看文件:cat test.txt 将几个文件合并为一个文件: cat file1 file2 > file |
tar |
备份文件 |
tar –cvf JavaMe.tar JavaMe |
>或>> |
以重写或追加的方式输出重定向 |
cat /dev/null > Error.log cat Error.log > > test.log |
su |
变更用户身份 |
su – admin |
netstat |
显示网络状态 |
netstat -anp | grep 8080 |
ping |
检测主机 |
ping 10.137.41.21 |
ifconfig |
显示或设置网络设备 |
查看:ifconfig |
ftp |
设置文件系统相关功能 |
连接ftp:ftp ip地址/主机名 下载文件:ftp> get test.txt 上传文件:ftp> put test.txt |
linux用过的命令
ls 显示文件或目录
-l 列出文件详细信息l(list)
-a 列出当前目录下所有文件及目录,包括隐藏的a(all)
mkdir 创建目录
-p 创建目录,若无父目录,则创建p(parent)
cd 切换目录
touch 创建空文件
echo 创建带有内容的文件。
cat 查看文件内容
cp 拷贝
mv 移动或重命名
rm 删除文件
-r 递归删除,可删除子目录及文件
-f 强制删除
find 在文件系统中搜索某文件
wc 统计文本中行数、字数、字符数
grep 在文本文件中查找某个字符串
rmdir 删除空目录
tree 树形结构显示目录,需要安装tree包
pwd 显示当前目录
ln 创建链接文件
more、less 分页显示文本文件内容
head、tail 显示文件头、尾内容
ctrl+alt+F1 命令行全屏模式
系统管理命令
stat 显示指定文件的详细信息,比ls更详细
who 显示在线登陆用户
whoami 显示当前操作用户
hostname 显示主机名
uname 显示系统信息
top 动态显示当前耗费资源最多进程信息
ps 显示瞬间进程状态ps -aux
du 查看目录大小du -h /home带有单位显示目录信息
df 查看磁盘大小df -h 带有单位显示磁盘信息
ifconfig 查看网络情况
ping 测试网络连通
netstat 显示网络状态信息
man 命令不会用了,找男人 如:man ls
clear 清屏
alias 对命令重命名 如:alias showmeit="ps -aux" ,另外解除使用unaliax showmeit kill 杀死进程,可以先用ps 或 top命令查看进程的id,然后再用kill命令杀死进 程。
打包压缩相关命令
gzip:
bzip2:
tar: 打包压缩
-c 归档文件
-x 压缩文件
-z gzip压缩文件
-j bzip2压缩文件
-v 显示压缩或解压缩过程v(view)
-f 使用档名
例:
tar -cvf /home/abc.tar /home/abc 只打包,不压缩
tar -zcvf /home/abc.tar.gz /home/abc 打包,并用gzip压缩
tar -jcvf /home/abc.tar.bz2 /home/abc 打包,并用bzip2压缩
当然,如果想解压缩,就直接替换上面的命令 tar -cvf / tar -zcvf / tar -jcvf 中的“c” 换成“x” 就可以了。
关机/重启机器 shutdown -r 关机重启
-h 关机不重启
now 立刻关机
halt 关机
reboot 重启
Linux管道
将一个命令的标准输出作为另一个命令的标准输入。也就是把几个命令组合起来使用,后一 个命令除以前一个命令的结果。
例:grep -r "close" /home/* | more 在home目录下所有文件中查找,包括close的文 件,并分页输出。
vim使用
vim三种模式:命令模式、插入模式、编辑模式。使用ESC或i或:来切换模式。
命令模式下:
:q 退出
:q! 强制退出
:wq 保存并退出
:set number 显示行号
:set nonumber 隐藏行号
/apache 在文档中查找apache 按n跳到下一个,shift+n上一个
yyp 复制光标所在行,并粘贴
h(左移一个字符←)、j(下一行↓)、k(上一行↑)、l(右移一个字符→)
3. 算法及思想(排序、链表、查找)
>>排序算法
快速排序使用分治策略来把一个序列分为两个子序列。步骤为:
堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构(通常堆是通过一维数组来实现的),并同时满足堆的性质:即子结点的键值总是小于(或者大于)它的父节点。我们可以很容易的定义堆排序的过程:
冒泡排序是重复地走访过要排序的元素,一次比较相邻两个元素,如果他们的顺序错误就把他们调换过来,直到没有元素再需要交换,排序完成。这个算法的名字由来是因为越小(或越大)的元素会经由交换慢慢“浮”到数列的顶端。冒泡排序算法的运作如下:
插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。具体算法描述如下:
>>堆和栈的区别
(1)栈内存存储的是局部变量而堆内存存储的是实体;
(2)栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
(3)栈内存存放的变量生命周期一旦结束就会被释放,堆内存放的实体会被垃圾回收机制不定时的回收。
>>B+树、B-树和红黑树
B-树的特性:
(1)关键字集合分布在整颗树中;
(2)任何一个关键字出现且只出现在一个结点中;
(3)搜索有可能在非叶子结点结束;
(4)其搜索性能等价于在关键字全集内做一次二分查找;
(5)自动层次控制;
(6)由于限制了除根结点以外的非叶子结点,至少含有M/2个儿子,确保了结点的至少利用率,其最底搜索性能为:O(log2n)只与节点数有关,与M无关。
B+的特性:
(1)所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
(2)不可能在非叶子结点命中;
(3)非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
(4)更适合用于数据库和操作系统的文件系统;
红黑树:红黑树就是用红链接表示3-结点的2-3树。
红黑树(Red Black Tree)是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
红黑树性质:
1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
红黑树的本质:
红黑树是对2-3查找树的改进,只是它们对3结点的表示不同,将3-结点表示为由一条左斜的红色链接相连的两个2-结点。若指向它的链接是红色的,那么该节点为红色,红黑树都既是二叉查找树,也是2-3树
小结:
B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3。
4. 软件测试理论
黑盒测试 |
不关心内部结构和代码 |
白盒测试 |
需要了解内部结构和代码 |
静态测试 |
不执行被测试文件 |
动态测试 |
执行被测试文件 |
单元测试 |
测试软件的单元模块如某个功能、类等 |
集成测试 |
将各单元集成到一起测试 |
系统测试 |
测试软件是否符合系统中的各项需求 |
功能测试 |
测试软件是否符合功能性需求 |
性能测试 |
测试软件在各种状态下的性能 |
回归测试 |
软件被修正或运行环境发送改变后重新进行测试 |
安全测试 |
测试软件防止非法入侵的能力 |
兼容性测试 |
测试软件与其他软件、硬件的兼容能力 |
测试用例设计——场景模拟(要求充分全面的考虑执行过程中遇到的全部可能性)
自动化测试框架和原理
Selenium、Loadrunner、JMeter、Junit
性能测试需要关注的性能指标(见补充)
UI测试
接口测试
白盒测试?
白盒测试是指测试人员可以直接访问内部数据结果、算法及其代码实现的测试。包括:编程应用接口测试(调用API接口验证返回结果的正确性)、代码覆盖率测试(条件组合覆盖、语句覆盖、判定/条件覆盖等)、缺陷注入方法(错误和临界条件情况)等。
黑盒测试?
黑盒测试是指只关注业务功能点不关注内部结构和代码的测试。包括:等价类划分法、边界值分析法
软件测试划分为几个阶段?单元测试——集成测试——确认测试——系统测试——验收测试
评价软件质量的衡量指标?
(1)正确性——功能测试
(2)可靠性——系统可靠性测试
(3)易用性——功能测试
(4)可维护性——系统测试
(5)安全性——系统测试
(6)健壮性——功能测试
测试驱动开发(TDD)?先写测试程序,然后再编码实现使其通过测试。
缺陷跟踪和管理?
创建缺陷——开启缺陷——工作中、退回——验证、验证失败——关闭、取消
测试工作内容和测试的过程?
搭建测试环境——准备测试数据——准备测试脚本或代码——开启监控工具——执行测试用例——收集数据和结果——确认测试是否通过——问题分析和缺陷追踪
需求分析——制定测试计划——设计测试用例——执行用例——缺陷管理——测试报告
5.Java基础
>>什么是面向对象思想
面向对象是一种思想,世间万物都可以看做一个对象。
面向对象软件开发的优点:
代码开发模块化,更易维护和修改;
提高了代码的复用性;
增强代码的可靠性和灵活性;
增加代码的可读性。
>>面向对象的四大基本特性
抽象、封装、继承、多态。
·抽象。抽象就是将一些事物的共性和相似点抽离出来,并将这些属性归为一个类,这个类只考虑这些事物的共性和相似之处,并且会忽略与当前业务和目标无关的那些方面,只将注意力集中在与当前目标有关的方面。
·封装。封装是为了隐藏内部实现细节,是保证软件部件具有优良的模块性的基础。封装的目标就是要实现软件部件“高内聚,低耦合”,防止程序之间的相互依赖性带来的变动影响。
·继承。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法(Override,重写方法)使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
·多态。多态是运行时刻接口匹配的对象相互替换的能力。指程序定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译期并不确定,而是在程序运行期间才确定(称之为动态绑定),即一个引用变量指向的是哪个类的实例对象,在编译期间并不确定,在运行阶段才能决定,因此,这样就可以使得引用变量绑定到各种不同的类实现上,从而实现不同的行为。多态性增强了软件的灵活性和扩展性。
>>Java集合框架
Java集合框架是一种工具类,就像是容器,存储任意数量的具有共同属性的对象。
(1)Collection接口
是List、Set和Queue接口的父接口;
定义了可用于操作List、Set和Queue的方法——增删改查;
·List接口及其实现类——ArrayList
List(序列),元素有序,并且可重复;
List可以精确控制元素的插入位置,或删除指定位置的元素;
ArrayList——数组序列,是List的一个重要实现类;
ArrayList底层是由数组实现的
泛型集合中,不能添加泛型规定的类型及其子类型以外的对象,否则会报错。
泛型集合中的限定类型,不能使用基本类型,必须用基本类型的包装类。
·Set接口及其实现类——HashSet
Set(集),元素无序,并且不可以重复;
HashSet——哈希集,是Set的一个重要实现类;
(2)Map接口
Map提供了一种映射关系,元素是以键值对(key-value)的形式存储的,能根据key快速查找value;
Map中的键值对以Entry类型的对象实例形式存在;
key值不能重复,value值可以重复;
key对value是多(一)对一的关系;
Map接口提供了返回key值集合、value值集合、Entry值集合,的方法;
Map支持泛型,形式如:Map
·HashMap类
HashMap是Map的一个重要实现类,也是最常用的,基于哈希表实现;
HashMap中的Entry对象是无序排列的;
Key值和value值都可以为null,但是一个HashMap只能有一个Key值为null的映射(Key值不可重复)。
框架的优点如下:
(1)降低开发成本。 (2)提高代码质量。 (3)降低代码维护成本。 (4)复用性和可操作性。
为何Collection不从Cloneable和Serializable接口继承?
Collection接口指定一组对象,对象即为它的元素。如何维护这些元素由Collection的具体实现决定。例如,一些如List的Collection实现允许重复的元素,而其它的如Set就不允许。很多Collection实现有一个公有的clone方法。然而,把它放到集合的所有实现中也是没有意义的。这是因为Collection是一个抽象表现。重要的是实现。 当与具体实现打交道的时候,克隆或序列化的语义和含义才发挥作用。所以,具体实现应该决定如何对它进行克隆或序列化,或它是否可以被克隆或序列化。在所有的实现中授权克隆和序列化,最终导致更少的灵活性和更多的限制。特定的实现应该决定它是否可以被克隆和序列化。
为何Map接口不继承Collection接口?
尽管Map接口和它的实现也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map继承Collection毫无意义,反之亦然。如果Map继承Collection接口,那么元素去哪儿?Map包含key-value对,它提供抽取key或value列表集合的方法,但是它不适合“一组对象”规范。
>>HashMap的工作原理
HashMap实际上是一个“链表散列”,如下是它数据结构:最左侧是一个数组,数组中的每一个元素都是一个链表,链表的每一个元素都是entry。HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。
>>Array和ArryList的区别
(1)Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
(2)Array大小是固定的,ArrayList的大小是动态变化的。
(3)ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等。
>>ArrayList和LinkList的区别
(1)ArrayList实现了基于动态数组的数据结构,LinkedList实现了循环双向链表数据结构。
(2)对于随机访问get和set,ArrayList更优,因为LinkedList要移动指针。
(3)对于新增和删除操作add和remove,LinedList更优,因为ArrayList要移动数据。而 LinkedList是使用链表实现的,若要从链表中删除或插入某一个对象,只需要改变前后对象的引用即可。
>>ArrayList和Vector的区别
(1)Vector是同步的,而ArrayList不是。如果你寻求在迭代的时候对列表进行改变,应该使用CopyOnWriteArrayList。
>>如何初始化一个指针数组
首先明确一个概念,就是指向数组的指针,和存放指针的数组。指向数组的指针:char (*array)[5];含义是一个指向存放5个字符的数组的指针。存放指针的数组:char *array[5];含义是一个数组中存放了5个指向字符型数据的指针。 按照题意,我理解为初始化一个存放指针的数组:
char *array[2]={“China”,”Beijing”};其含义是初始化了一个有两个指向字符型数据的指针的数组,这两个指针分别指向字符串”China”和”Beijing”。
>>指针和引用的区别
(1)指针有自己的一块空间,而引用只是变量的一个别名;
(2) “sizeof 引用" = 指向引用变量的大小 , "sizeof 指针"= 指针本身的大小;
(3)指针可以被初始化为NULL,而引用只能在初始化时被赋值且不能为NULL;
(4)可以有const指针,但是没有const引用;
(5)指针在使用中可以指向其它对象,可以被改变,但是引用只能是一个对象的引用,不能被改变。
>>APP测试和Web测试的区别
(1)系统架构。Web是B/S结构,APP是C/S结构,web测试只要更新服务器端,客户端就会自动同步更新,APP的客户端需要用户自己更新。
(2)性能。Web页面更多的关心响应时间,APP还需要关心流量、电量、CPU等指标。
(3)兼容性。Web测试更注重浏览器、计算机硬件等方向的兼容性,APP测试更注重操作系统、分辨率等方向的测试。
(4)测试工具。Web端一般使用Selenium、LR等工具,APP端一般使用Appium、JMeter等工具。
除此之外,APP测试还需要弱网测试(如中断、来电、关机等)、安装、卸载、更新等情况。
补充2:
>>JAVA和C++的区别
>>HTTP状态码
2——请求成功 3——请求被重定向 4——客户端错误 5——服务器错误
200 |
OK |
服务器已成功处理了请求 |
304 |
未修改 |
从上次请求后请求的网页未修改过 |
301 |
永久移动 |
资源永久移动到新URL |
302 |
临时移动 |
资源临时移动到新URL |
303 |
查看其它地址 |
使用GET和POST请求查看 |
307 |
临时重定向 |
使用GET请求重定向 |
401 |
未授权 |
请求要求身份验证 |
403 |
禁止 |
服务器拒绝请求 |
404 |
找不到 |
服务器找不到请求的网页 |
>>HTTP和HTTPS的区别
超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息。HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此HTTP协议不适合传输一些敏感信息,比如信用卡号、密码等。为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS。为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
HTTPS和HTTP的区别主要为以下四点:
>>软件开发流程
(产品规划和设计)——问题定义与背景分析——需求分析——概要设计——详细设计——代码开发——测试——(上线运营推广)
>>测试模型
(1)“V”型
特点:【活动串行】这是一种古老的瀑布模型,反映了实际和测试之间的关系。
局限:仅仅把测试过程作为编码之后的一个阶段,忽视了测试对需求分析,系统设计的验证,如果前面设计错误,得一直到后期的验收测试才被发现,耗时耗力。
(2)“W”型
特点:【活动串行】测试与开发同时进行,在V模型的基础上,增加了在开发阶段的同步测试。测试伴随着整个软件开发周期,而且测试的对象不仅仅是程序,需求、设计等开发输出的文档同样要测试。
局限:仍然不支持迭代,减少了一定错误发生率,但是需按照流水线进行设计、编码和测试。
(3)”H”型
特点:【活动并行】过程活动完全独立,贯穿于整个产品的周期,与其他流程并发地进行,某个测试点准备就绪时,就可以从测试准备阶段进行到测试执行阶段;软件测试可以进行尽早的进行;软件测试可以根据被测物的不同而分层次进行。
结论:软件测试应该尽早准备、尽早执行。
(4)TDD测试驱动开发
TDD(Test-Driven Development)是敏捷开发中的一项核心实践和技术,也是一种设计方法论,其基本思想是:在明确要开发某个功能后,在开发功能代码之前,先编写测试代码,然后编写功能代码并用测试代码进行验证,如此循环直到完成全部功能的开发。
流程:面向接口开发代码(没有具体实现) ——> 针对写的抽象代码编写单元测试 ——> 编写具体的功能代码 ——> 运行单元测试 ——> 通过
优点:
>>对测试的了解
(1)测试流程
需求分析——制定测试计划——设计测试用例——执行测试(搭建测试环境——准备测试数据——准备测试脚本——执行测试用例——收集数据和结果)——缺陷管理——输出测试报告
(2)测试方法
黑盒测试:等价类划分法、边界值分析法、错误推测法、因果图法等;
白盒测试:逻辑覆盖法(语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖)、代码检查法、基本路径测试法等;
(3)测试工具
JUnit——单元测试,JMeter——性能和接口测试,LoadRunner——压力测试,Selenium——web端测试,APPium——移动端测试。
>>性能测试指标
性能测试是通过自动化测试工具模拟多种正常、峰值和异常负载条件对系统的各项性能指标进行测试。负载测试是测试当负载逐渐增加时,系统各项性能指标的变化情况;压力测试是通过确定一个系统的瓶颈或不能接受的性能点来获得系统能提供的最大服务级别的测试。
性能指标:
>>实例:对某个模块的测试或设计测试用例(重要)
>>实例:TDD测试驱动开发
补充3:
>>Linux查询命令
查看CPU利用率 top
查看进程 ps -A
查找文件 find(根据文件的属性查找) grep(根据文件的内容查找)
查看80端口 nestat –nulp|grep 80 (grep用于指定端口号)
find指令
一、概述:
因为Linux下面一切皆文件,经常需要搜索某些文件来编写,所以对于linux来说find是一条很重要的命令。linux下面的find指令用于在目录结构中搜索文件,并执行指定的操作。它提供了相当多的查找条件,功能很强大。在不指定查找目录的情况下,find会在对整个系统进行遍历。即使系统中含有网络文件系统,find命令在该文件系统中同样有效。 在运行一个非常消耗资源的find命令时,很多人都倾向于把它放在后台执行,因为遍历一个大的文件系统可能会花费很长的时间。
1、命令格式
find [查找目录] [查找规则] [查找完后的操作]
即:find pathname -option [-print -exec -ok …]
2、命令功能
用于在文件树中查找文件,并做相应的处理,(有可能访问磁盘)。
3、命令参数
(1)pathname:表示所要查找的目录路径,例如”.”表示当前目录,”/”表示根目录。
(2)-print:将find找到的文件输出到标准输出。
(3)-exec:对找到的文件执行exec这个参数所指定的shell命令,相应的形式为:-exec command {} \; 将查到的文件进行command操作,”{}”就代替查到的文件。
注意:
1)”{}”和”\”之间有一个空格。
2)-ok:和-exec的作用相同,只不过-ok更加安全一点,在执行每一个命令之前,系统会让用户确定是否执行。
二、查找规则:
1、根据文件名查找
(1)-name :根据文件名进行查找,区分大小写精确查找。
【例】
(3)文件名通配符:
“*”:通配任意的字符,可以是任何东西。
【例】
(4)”?”:可表示任意单个字符
【例】
注:与上例比较得知,空不为单字符,所以不能查找“file”文件。
(5)”[]”表示通配括号里面的任意一个字符,注意[]里面的内容会被解析成单个字符。
【例】
2、根据文件的时间戳信息查找文件
在根据时间戳信息查找的时候,所有的time都是以天为单位,min都是以分钟为单位。+n表示n以前,-n表示n以内。
(1)以最近一次存取的时间为参数
1)-atime:
A、find pathname -atime +n //表示n天前存取过的文件
B、find pathname -atime -n //表示以当前时间为起点前n天内存取过的文件
2)-amin :
A、find pathname -amin +n //表示n分钟前存取过的文件。
B、find pathname -amin -n //表示以当前时间为起点前n分钟内存取过的文件。
【例】
(2)以最近一次修改的时间为参数
1)-mtime:
A、find pathname -mtime +n //表示n天前修改过的文件
B、find pathname -mtime -n //表示以当前时间为起点前n天内修改 过的文件
2)-mmin:
A、find pathname -mmin +n //表示n分钟前存取过的文件
B、find pathname -mmin -n //表示以当前时间为起点前n修改 内存取过的文
【例】
(3)以最近一次更改的属性为参数
1)-ctime:
A、find pathname -ctime +n //表示n天前更改 过的文件
B、find pathname -ctime -n //表示以当前时间为起点前n天内更改 过的文件
2)-cmin:
A、find pathname -cmin +n //表示n分钟前更改过的文件
B、find pathname -cmin -n //表示以当前时间为起点前n分钟内更改 过的文件
【例】
3、根据文件所属用户和所属组来查找文件
(1)根据文件所有者查找文件:-user
【例】
4、根据nouser或nogroup查找
(1)查找无有效属主的文件:-nouser
find pathname -nouser
(2)查找无有效属组的文件:-nogroup
find pathname -nogroup
5、-perm :根据权限来查找文件
【例】
6、根据uid和gid查找文件
(1)根据文件的uid查找:-uid
(2)根据文件所在组的gid查找:-gid
7、-type:根据文件类型查找文件
(1)普通文件:f
find pathname -type f
【例】
(2)目录文件:d
find pathname -type d
【例】
(3)链接文件:l
find pathname -type l
(4)块设备文件:b
find pathname -type b
(5)字符设备文件:c
find pathname -type c
(6)管道设备文件:p
find pathname -type p
(7)套接字文件:s
find pathname -type s
8、根据文件大小查找文件:-size
(1)find pathname -size +n //表示大于n字节的文件
(2)find pathname -size -n //表示小于n字节的文件
(3)find pathname -size n //表示等于n字节的文件
【例】
9、按照参考文件的更改时间查找
-newer :file1//查找更改时间比file1的更改时间距离当前时间近的文件
【例】
10、maxdepth和mindepth
(1)-maxdepth
1)-maxdepth n : 搜索深度距离当前目录最多n个子目录深度
【例】
(2)-mindepth
2)-mindepth n :搜索深度距离当前目录至少n个子目录深度
【例】
12、按照硬连接的数目进行查找
(1)-link n :硬连接连接数等于n的文件或目录
【例】
(2)-link +n :硬连接连接数大于n的文件或目录
【例】
(3)-link -n :硬连接连接数小于n的文件或目录
【例】
13、-a、-o,-not(也就是与、或、非)
(1)-a:连接两个不同的条件(即两个条件必须同时为真)
【例】
(2)-o:连接两个不同的条件(两个条件只要满足一个即可)
【例】
14、查找完成之后的操作
(1) -exec command {} \;: 其中,”{}”就代表查找之后返回的文件。
【例】
(2)-ok command {} \;-ok相对于-exec而言更安全一点,会让用户确定所要执行的操作。
【例】
补充4:
1.冒泡排序
package Sort;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int [] a = {1,100,234,44,3,2,4,5};
bubbleSort(a,a.length+1);
System.out.println(Arrays.toString(a));
}
public static int[] bubbleSort(int[] A, int n) {
for (int i=0;i for (int j=i+1;j if (A[i] > A[j]){ int tmp = A[i]; A[i] = A[j]; A[j] = tmp; } } } return A; } } 2.快速排序 package Sort; import java.util.Arrays; public class QuickSort { public static void main(String[] args) { int A[] = {1,6,9, 2, 3, 1, 5, 4 }; quickSort(A, 0, 7); System.out.println(Arrays.toString(A)); } public static void quickSort(int[] A, int left, int right) { if (left < right) { // 一次划分 int mid = partion(A, left, right); quickSort(A, 0, mid - 1); quickSort(A, mid + 1, right); } } public static void swap(int[] A, int l, int r) { int tmp = A[l]; A[l] = A[r]; A[r] = tmp; } public static int partion(int[] a, int left, int right) { // 轴值,默认选取数组的第一个数字 while (left < right) { while (left < right && a[left] <= a[right]) { right--; } if (left swap(a, left, right); } while (left < right && a[left] <= a[right]) { left++; } if (left swap(a, left, right); } } return left; } } 3.插入排序 package Sort; public class InsertionSort { public int[] insertionSort(int[] A, int n) { int i, j, temp; for(i = 1; i < n; i++){ temp = A[i]; for(j = i; j > 0 && A[j - 1] > temp; j-- ){ A[j] = A[j - 1]; } A[j] = temp; } return A; } } 3.1希尔排序(插入排序的一种) package Sort; import java.util.Arrays; public class ShellSort { public static void main(String[] args) { int[] a = { 54, 35, 48, 36, 27, 12, 44, 44, 8, 14, 26, 17, 28 }; sort(a); System.out.println(Arrays.toString(a)); } public static void sort(int[] a) { // 设置步长,默认为数组长度的一半 int step = a.length / 2; while (step >= 1) { for (int i = step; i < a.length; i += step) { int tmp = a[i]; int j; for (j = i; j > 0 && a[j - step] > tmp; j -= step) { a[j] = a[j - step];//元素后移 } a[j] = tmp;//插入的位置,注意此时j在for循环中已经进行了一次-- } step /= 2; } } } 4堆排序 package Sort; import java.util.Arrays; public class HeapSort { public static void main(String[] args) { int[] a = { 2, 5, 9, 6, 1, 4, 8, 7, 12, 50 }; sort(a); System.out.println(Arrays.toString(a)); } public static void sort(int[] a) { int len = a.length; for (int i = 0; i < len - 1; i++) { // 建堆 buildHeap(a, len - 1 - i); // 交换堆顶元素和最后一个元素 swap(a, 0, len - 1 - i); } } private static void swap(int[] a, int i, int j) { // TODO Auto-generated method stub int tmp = a[i]; a[i] = a[j]; a[j] = tmp; } public static void buildHeap(int[] a, int lastIndex) { // 从最后一个节点的父节点开始 for (int i = (lastIndex - 1) / 2; i >= 0; i--) { // 当前节点存在子节点 while (i * 2 + 1 <= lastIndex) { // 左节点下标值 int l = i * 2 + 1; // 右结点下标值 int r = i * 2 + 2; // 默认左节点为最大值 int biggerIndex = l; // 存在右结点 if (l < lastIndex) { // 右结点的值比左节点大 if (a[r] > a[l]) { biggerIndex = r; } } // 当前节点的值比孩子节点的最小值小,交换 if (a[i] < a[biggerIndex]) { swap(a, i, biggerIndex); // 把最大值下标赋给当前节点,进入下一次while循环判断 i = biggerIndex; } else { break; } } } } } 单词反转 public class Test { public static void main(String[] args) { String src = "Hello Java Hello China";//需要处理的字符串 String[] arr = src.split(" ");//按空格分割 int length = arr.length;//计算数组长度 StringBuilder sb = new StringBuilder(src.length());//新建一个StringBuilder对象 for (int i=length-1;i>=1;i--){ sb.append(arr[i]+" ");//将字符串依次加入StringBuilder中 } sb.append(arr[0]);//最后一个单词不加空格 System.out.println(sb.toString());//输出 } } java统计字符串中每个字符出现的次数 public static void count(String str){ //将字符串转化为字符数组 char[] chars = str.toCharArray(); //创建一个HashMap名为hm HashMap //定义一个字符串c,循环遍历遍历chars数组 for(char c : chars){ //containsKey(c),当c不存在于hm中 if(!hm.containsKey(c)){ hm.put(c,1); }else{ //否则获得c的值并且加1 hm.put(c, hm.get(c)+1); } //或者上面的if和else替换成/* hm.put(c,hm.containsKey(c) ? hm.get(c)+1:1);*/ } for(Character key: hm.keySet()){ //hm.keySet()代表所有键的集合,进行格式化输出