测试、测试开发面试准备和复习

 

目录

测开面试复习文档

一:网络知识方面

基础的网络通信知识

各层的协议

IP 是无连接的

TCP/IP

 短连接和长链接

● 请你说一说PC网络故障,以及如何排除障碍

HTTP和HTTPS的区别

GET 和 POST 的区别

TCP和UDP的区别、特点

三次握手

四次挥手:

请你说一下在浏览器中输入一个网址它的运行过程是怎样的?

 请你说一说DNS解析过程

请你说一下为什么tcp可靠,哪些方法保证可靠

ARP协议

网页很卡的原因

二、数据库方面

数据的索引

索引的优点

索引的缺点

数据库的三大范式

关系型和非关系型数据库的区别

数据的操作(增删改查)

关系型数据库与NOSQL

MySQL中char、varchar和text三者的区别

查询借了“数据库”书籍的所有读者的的姓名

查询借书期限超过两个月的所有读者的姓名、所借书籍和借书日期

按读者姓名查询指定读者的借还书历史记录,假设读者姓名为刘勇。

三、Java语言

JAVA多线程开启的三种方式

Integer和int的区别

判断一个类是否“无用”,则需同时满足三个条件:

java类的加载:加载、链接、初始化

主方法

输入和输出

创建字符串

创建数组

数据类型转换

java的三大特性是:封装、继承、多态。

多态:

多态存在的三个必要条件

多态的实现方式

继承的注意事项:

l 继承中的成员方法关系:

抽象

序列化和反序列化

泄漏诊断

Java主动调用gc的方法

JAVA的反射机制

死锁

死锁发生原因

解决死锁的基本方法

死锁检测方法1、Jstack命令

四、数据结构和算法

堆栈空间分配区别:

堆栈缓存方式区别:

堆栈数据结构区别:

存储过程和触发器的区别有:

Hash表即散列表

单向链表反转的多种实现方法

数组和链表的区别

先、中、后序遍历

红黑树

 现在有100W个账户密码,要存起来,要求查找时速度尽可能快,你选择什么数据结构?为什么?

查找方法和复杂度

冒泡排序

选择排序法

归并排序法 

二分法查找

设计模式

设计模式的六大原则

五、测试常识

软件测试流程:

压力测试和负载测试

下面是依据的文档:

单元测试的策略:

设计用例的方法、依据有那些

单元测试、集成测试、系统测试

有效等价类和无效等价类

六、操作系统

对文件和目录进行操作的命令

pwd:显示工作目录路径

cd:更改工作目录路径

ls:列出目录和文件信息

touch:创建空文件、更改文件时间

mkdir:创建目录

cp:复制文件的和目录

mv:文件和目录改名、移动文件和目录路径

rm:删除文件或目录

wc:统计文件行数、单词数、字节数和字符数

du:计算机文件或目录的容量

linux系统显示的命令

uname:显示计算机及操作系统相关信息

hostname:显示或修改计算机主机名

free:查看内存信息

linux命令,找出关键字出现的次数

常用命令

进程和线程

Linux命令

显示终端上的所有进程

Linux杀死某个进程的方法

七、智力题


 

测开面试复习文档

 

一:网络知识方面

基础的网络通信知识

Cookie:记住身份信息,将我们在网站的行为记录号,自动登录账号,不用重新登录账号,可以将我们查的东西来推广告

Session:是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;

Token在计算机身份认证中是令牌(临时)的意思,在词法分析中是标记的意思。一般作为邀请、登录系统使用。

token其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作。

Cache 缓存之前浏览过的东西,数据被缓存到附近的主机,再次打开的时候,速度就很快。cdn

Host接受请求的服务器地址,可以是IP或者是域名

状态码100~199表示请求已收到继续处理,200~299表示成功,300~399表示资源重定向,400~499表示客户端请求出错,500~599表示服务器端出错

200响应成功

302跳转,重定向

400客户端有语法错误

403服务器拒绝提供服务

404请求资源不存在

500服务器内部错误

OSI七层模型:

  • ①物理层、②数据链路层、③网络层、④传输层、⑤会话层、⑥表示层、⑦应用层

各层的协议

TCP/IP: 
数据链路层:ARP,RARP 
网络层: IP,ICMP,IGMP 
传输层:TCP ,UDP,UGP 
应用层:Telnet,FTP,SMTP,SNMP. 

OSI: 
物理层:EIA/TIA-232, EIA/TIA-499, V.35, V.24, RJ45, Ethernet, 802.3, 802.5, FDDI, NRZI, NRZ, B8ZS
数据链路层:Frame Relay, HDLC, PPP, IEEE 802.3/802.2, FDDI, ATM, IEEE 802.5/802.2 
网络层:IP,IPX,AppleTalk DDP 
传输层:TCP,UDP,SPX 
会话层:RPC,SQL,NFS,NetBIOS,names,AppleTalk,ASP,DECnet,SCP 
表示层:TIFF,GIF,JPEG,PICT,ASCII,EBCDIC,encryption,MPEG,MIDI,HTML 
应用层:FTP,WWW,Telnet,NFS,SMTP,Gateway,SNMP

测试、测试开发面试准备和复习_第1张图片

 

HTTP 80端口 

超文本传输协议(HTTPHyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。Http协议是以明文方式发送信息的,如果黑客截取了Web浏览器和服务器之间的传输报文,就可以直接获得其中的信息。虽然HTTP本身是一个协议,但其最终还是基于TCP的。

HTTPS 443  端口

是以安全为目标的Http通道,是Http的安全版。Https的安全基础是SSL

SSL协议可分为两层:SSL记录协议(SSL Record Protocol),它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。SSL握手协议(SSL Handshake Protocol),它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

FTP是File Transfer Protocol,文件传输协议;简单说HTTP是面向网页的,而FTP是面向文件的。

 

TCP/IP 是用于因特网 (Internet) 的通信协议。计算机通信协议是对那些计算机必须遵守以便彼此通信的规则的描述。

TCP 使用固定的连接

TCP 用于应用程序之间的通信。

当应用程序希望通过 TCP 与另一个应用程序通信时,它会发送一个通信请求。这个请求必须被送到一个确切的地址。在双方握手之后,TCP 将在两个应用程序之间建立一个全双工 (full-duplex) 的通信。

这个全双工的通信将占用两个计算机之间的通信线路,直到它被一方或双方关闭为止。

IP 是无连接的

IP 用于计算机之间的通信。

IP 是无连接的通信协议。它不会占用两个正在通信的计算机之间的通信线路。这样,IP 就降低了对网络线路的需求。每条线可以同时满足许多不同的计算机之间的通信需要。

通过 IP,消息(或者其他数据)被分割为小的独立的包,并通过因特网在计算机之间传送。

IP 负责将每个包路由至它的目的地。

TCP/IP

TCP/IP 意味着 TCP IP 在一起协同工作。

TCP 负责应用软件(比如你的浏览器)和网络软件之间的通信。

IP 负责计算机之间的通信。

TCP 负责将数据分割并装入 IP 包,然后在它们到达的时候重新组合它们。

IP 负责将包发送至接受者。

 短连接和长链接

HTTP/1.0中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。

但从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:Connection:keep-alive

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接。

域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用TCPUDP端口53[1]

请你说一说PC网络故障,以及如何排除障碍

首先是排除接触故障、使用ipconfig查看计算机的上网参数、使用ping命令测试网络的连通性、ping本机IPping网关

(1)首先是排除接触故障

即确保你的网线是可以正常使用的

(2)使用ipconfig查看计算机的上网参数

输入ipconfig,按Enter确认,可以看到机器的配置信息,输入ipconfig/all,可以看到IP地址和网卡物理地址等相关网络详细信息。

(3)使用ping命令测试网络的连通性,定位故障范围

ping 127.0.0.1,如显示请求超时,则表明本机网卡的安装或TCP/IP协议有问题,接下来就应该检查网卡和TCP/IP协议,卸载后重装即可。

(4)ping本机IP

可以检查本机的IP地址是否设置有误

(5)ping网关

如果不成功,可能是网关设备自身存在问题,也可能是本机上网参数设置有误,检查网络参数。

(6)Ping本地DNS地址

这样做是为了检查本地DNS服务器是否工作正常。

(7)Ping远程IP地址

可以检查本网或本机与外部的连接是否正常 。

 

HTTP和HTTPS的区别

  • https协议需要到CA(Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。
  • http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  • http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • http的连接很简单,是无状态的。Https协议是由SSL+Http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)

GET 和 POST 的区别

  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST么有。
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET参数通过URL传递,POST放在Request body中。

TCP和UDP的区别、特点

  • TCP的主要特点是:
    • 面向连接。
    • 每一条TCP连接只能是点对点的(一对一)。
    • 提供可靠交付的服务(无差错,不丢失,不重复,且按序到达)(校验和、重传控制、序号标识、滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。)。
    • 提供全双工通信。
    • 面向字节流。
    • 开销比UDP大详情见“TCP协议:报文字段解析”
  • UDP的主要特点是:
    • 无连接。
    • 尽最大努力交付(不保证可靠交付)。
    • 面向报文。
    • 无拥塞控制。
    • 支持一对一、一对多、多对一和多对多的交互通信。
    • 首部开销小(只有四个字段:源端口、目的端口、长度、检验和)。

采用TCP,一旦发生丢包,TCP会将后续的包缓存起来,等前面的包重传并接收到后再继续发送,延时会越来越大。

UDP对实时性要求较为严格的情况下,采用自定义重传机制,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成影响。

TCP协议:报文字段解析

测试、测试开发面试准备和复习_第2张图片

1、端口号:用来标识同一台计算机的不同的应用进程。

     1)源端口:源端口和IP地址的作用是标识报文的返回地址。

     2)目的端口:端口指明接收方计算机上的应用程序接口。

2、序号和确认号:是TCP可靠传输的关键部分。序号是本报文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节一个序号。e.g.一个报文段的序号为300,此报文段数据部分共有100字节,则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。确认号即ACK,指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如建立连接时,SYN报文的ACK标志位为0。
3、数据偏移/首部长度:4bits。

4、保留:为将来定义新的用途保留,现在一般置0。

5、控制位:URG ACK PSH RST SYN FIN,共6个,每一个标志位表示一个控制功能。

      1)URG:紧急指针标志,为1时表示紧急指针有效,为0则忽略紧急指针。

      2)ACK:确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。

      3)PSH:push标志,为1表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
      4)RST:重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求。

     5)SYN:同步序号,用于建立连接过程,在连接请求中,SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1。

     6)FIN:finish标志,用于释放连接,为1时表示发送方已经没有数据发送了,即关闭本方数据流。

6、窗口:滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小时一个16bit字段,因而窗口大小最大为65535。

7、校验和:奇偶校验,此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。

8、紧急指针:只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。

9、选项和填充:最常见的可选字段是最长报文大小,又称为MSS


10、数据部分: TCP 报文段中的数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何数据的报文段。

 

三次握手

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYNack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHEDTCP连接成功)状态,完成三次握手。

四次挥手:

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。四次挥手过程:

1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。

2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。

3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A

4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1

四次挥手原因:这是因为服务端的LISTEN状态下的

请你说一下在浏览器中输入一个网址它的运行过程是怎样的?

参考回答:

1、查询DNS,获取域名对应的IP

1)检查浏览器缓存、检查本地hosts文件是否有这个网址的映射,如果有,就调用这个IP地址映射,解析完成。

2)如果没有,则查找本地DNS解析器缓存是否有这个网址的映射,如果有,返回映射,解析完成。

3)如果没有,则查找填写或分配的首选DNS服务器,称为本地DNS服务器。服务器接收到查询时:

如果要查询的域名包含在本地配置区域资源中,返回解析结果,查询结束,此解析具有权威性。

如果要查询的域名不由本地DNS服务器区域解析,但服务器缓存了此网址的映射关系,返回解析结果,查询结束,此解析不具有权威性。

4)如果本地DNS服务器也失效:

如果未采用转发模式(迭代),本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后,会判断这个域名(如.com)是谁来授权管理,并返回一个负责该顶级域名服务器的IP,本地DNS服务器收到顶级域名服务器IP信息后,继续向该顶级域名服务器IP发送请求,该服务器如果无法解析,则会找到负责这个域名的下一级DNS服务器(如http://baidu.com)的IP给本地DNS服务器,循环往复直至查询到映射,将解析结果返回本地DNS服务器,再由本地DNS服务器返回解析结果,查询完成。如果采用转发模式(递归),则此DNS服务器就会把请求转发至上一级DNS服务器,如果上一级DNS服务器不能解析,则继续向上请求。最终将解析结果依次返回本地DNS服务器,本地DNS服务器再返回给客户机,查询完成。

2、得到目标服务器的IP地址及端口号(http 80端口,https 443端口),会调用系统库函数socket,请求一个TCP流套接字。客户端向服务器发送HTTP请求报文:

1)应用层:客户端发送HTTP请求报文。

2)传输层:(加入源端口、目的端口)建立连接。实际发送数据之前,三次握手客户端和服务器建立起一个TCP连接。

3)网络层:(加入IP头)路由寻址。

4)数据链路层:(加入frame头)传输数据。

5)物理层:物理传输bit

3、服务器端经过物理层数据链路层网络层传输层应用层,解析请求报文,发送HTTP响应报文。

4、关闭连接,TCP四次挥手。

5、客户端解析HTTP响应报文,浏览器开始显示HTML

 

 请你说一说DNS解析过程

参考回答:

1、浏览器先检查自身缓存中有没有被解析过的这个域名对应的ip地址,如果有,解析结束。同时域名被缓存的时间也可通过TTL属性来设置。

2、如果浏览器缓存中没有(专业点叫还没命中),浏览器会检查操作系统缓存中有没有对应的已解析过的结果。而操作系统也有一个域名解析的过程。在windows中可通过c盘里一个叫hosts的文件来设置,如果你在这里指定了一个域名对应的ip地址,那浏览器会首先使用这个ip地址。

但是这种操作系统级别的域名解析规程也被很多黑客利用,通过修改你的hosts文件里的内容把特定的域名解析到他指定的ip地址上,造成所谓的域名劫持。所以在windows7中将hosts文件设置成了readonly,防止被恶意篡改。

3.如果至此还没有命中域名,才会真正的请求本地域名服务器(LDNS)来解析这个域名,这台服务器一般在你的城市的某个角落,距离你不会很远,并且这台服务器的性能都很好,一般都会缓存域名解析结果,大约80%的域名解析到这里就完成了。

4. 如果LDNS仍然没有命中,就直接跳到Root Server 域名服务器请求解析

5. 根域名服务器返回给LDNS一个所查询域的主域名服务器(gTLD Server,国际顶尖域名服务器,如.com .cn .org等)地址

6. 此时LDNS再发送请求给上一步返回的gTLD

7. 接受请求的gTLD查找并返回这个域名对应的Name Server的地址,这个Name Server就是网站注册的域名服务器

8. Name Server根据映射关系表找到目标ip,返回给LDNS

9. LDNS缓存这个域名和对应的ip

10. LDNS把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束

请你说一下为什么tcp可靠,哪些方法保证可靠

参考回答:

[1] 确认和重传机制

建立连接时三次握手同步双方的“序列号 + 确认号 + 窗口大小信息,是确认重传、流控的基础

传输过程中,如果Checksum校验失败、丢包或延时,发送端重传。

[2] 数据排序

TCP有专门的序列号SN字段,可提供数据re-order

[3] 流量控制

滑动窗口和计时器的使用。TCP窗口中会指明双方能够发送接收的最大数据量,发送方通过维持一个发送滑动窗口来确保不会发生由于发送方报文发送太快接收方无法及时处理的问题。

[4] 拥塞控制

TCP的拥塞控制由4个核心算法组成:

“慢启动”(Slow Start

“拥塞避免”(Congestion avoidance

“快速重传Fast Retransmit

“快速恢复”(Fast Recovery

 

ARP协议

  • 第一步:首先,每个主机都会有自己的ARP缓存区中建立一个ARP列表,以表示IP地址和MAC地址之间的对应关系
  • 第二步:当源主机要发送数据时,首先检测ARP列表中是否对应IP地址的目的主机的MAC地址如果有,则直接发送数据。如果没有,就向本网段的所有主机发送ARP数据包,内容:我是IP地址,mac地址,谁是IP地址,mac?
  • 第三步:当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包。如果是,则首先从数据包中取出源主机的IP和mac地址写入到ARP列表中,如果以存在,则覆盖。然后将自己的mac地址写入arp响应包中,告诉源主机自己是它想要找的mac地址
  • 第四步:源主机收到ARP响应包后,将目的主机的IP和mac地址写入arp列表,并利用此信息发送数据如果源主机一直没有收到arp响应数据包,表示arp查询失败。
  •  
  • 为什么要使用ARP协议
    • OSI模型把网络工作分为七层,彼此不直接打交道,只通过接口(layer interface)。IP地址工作在第三层,MAC地址工作在第二层。当协议在发送数据包时,需要先封装第三层IP地址,第二层MAC地址的报头,但协议只知道目的节点的IP地址,不知道目的节点的MAC地址,又不能跨第二、三层,所以得用ARP协议服务,来帮助获取到目的节点的MAC地址。
  • ARP协议是第几层协议
    • 工作在二层,是三层协议。
  • ARP在生成环境产生的问题及解决办法:
    • ARP病毒,ARP欺骗。
    • 高可用服务器对之间切换时要考虑ARP缓存的问题。
    • 路由器等设备无缝迁移时要考虑ARP缓存的问题,例如:更换办公室的路由器。

网页很卡的原因

  • 带宽不足、硬件配置低、CPU或者是内存被占满。
  • http请求次数太多。
  • 接收数据时间过长,如下载资源过大。
  • JS脚本过大,阻塞了页面的加载。
  • 网页资源过多、接受数据时间长、加载某个资源慢。
  • DNS解析速度。
  •  

二、数据库方面

数据的索引

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。

索引的作用:

索引的一个主要目的就是加快检索表中数据,亦即能协助信息搜索者尽快的找到符合限制条件的记录ID的辅助数据结构。

索引的优点

通过建立索引可以极大地提高在数据库中获取所需信息的速度,同时还能提高服务器处理相关搜索请求的效率,从这个方面来看它具有以下优点 [1]  :

  • 在设计数据库时,通过创建一个惟一的索引,能够在索引和信息之间形成一对一的映射式的对应关系,增加数据的惟一性特点。

  • 能提高数据的搜索及检索速度,符合数据库建立的初衷。

  • 能够加快表与表之间的连接速度,这对于提高数据的参考完整性方面具有重要作用。

  • 在信息检索过程中,若使用分组及排序子句进行时,通过建立索引能有效的减少检索过程中所需的分组及排序时间,提高检索效率。

  • 建立索引之后,在信息查询过程中可以使用优化隐藏器,这对于提高整个信息检索系统的性能具有重要意义。

索引的缺点

虽然索引的建立在提高检索效率方面具有诸多积极的作用,但还是存在下列缺点 [1]  :

  • 在数据库建立过程中,需花费较多的时间去建立并维护索引,特别是随着数据总量的增加,所花费的时间将不断递增。

  • 在数据库中创建的索引需要占用一定的物理存储空间,这其中就包括数据表所占的数据空间以及所创建的每一个索引所占用的物理空间,如果有必要建立起聚簇索引,所占用的空间还将进一步的增加

  • 在对表中的数据进行修改时,例如对其进行增加、删除或者是修改操作时,索引还需要进行动态的维护,这给数据库的维护速度带来了一定的麻烦。

数据库的三大范式

第一范式:保证列的原子性,保证列不可再分。

 

第二范式:第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言),也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。

 

第三范式:每列都与主键有直接关系而不是间接关系,不存在传递依赖;(限制一对多的关系,在从表中建立一个外键,通过外键来引用主表的信息)

 

PS:第二范式要遵循第一范式,第三范式要遵循第二范式。

1、不符合第一范式的例子(关系数据库中create不出这样的表):

表:姓名,性别,电话

问题:若某个人有两个电话,家庭电话和手机,这样则不符合第一范式。

解决:把电话列分成两个列即可。

2、不符合第二范式的例子:

表:学号, 姓名, 年龄, 课程名称, 成绩, 学分;

这个表明显说明了两个事务:学生信息, 课程信息,不符合第二范式。

存在问题:数据冗余,每条记录都含有相同信息。

解决:分成学生表和课程表分别存储即可。

3、不符合第三范式的例子:

学号, 姓名, 年龄, 所在学院, 学院联系电话,关键字为单一关键字"学号";

存在依赖传递: (学号) → (所在学院) → (学院地点, 学院电话)

存在问题:

数据冗余:有重复值;

解决:分成学生表,学院表即可。

关系型和非关系型数据库的区别

1、数据存储方式不同。

关系型和非关系型数据库的主要差异是数据存储的方式。关系型数据天然就是表格式的,因此存储在数据表的行和列中。数据表可以彼此关联协作存储,也很容易提取数据。

与其相反,非关系型数据不适合存储在数据表的行和列中,而是大块组合在一起。非关系型数据通常存储在数据集中,就像文档、键值对或者图结构。你的数据及其特性是选择数据存储和提取方式的首要影响因素。

2、扩展方式不同。

SQL和NoSQL数据库最大的差别可能是在扩展方式上,要支持日益增长的需求当然要扩展。

要支持更多并发量,SQL数据库是纵向扩展,也就是说提高处理能力,使用速度更快速的计算机,这样处理相同的数据集就更快了。

因为数据存储在关系表中,操作的性能瓶颈可能涉及很多个表,这都需要通过提高计算机性能来客服。虽然SQL数据库有很大扩展空间,但最终肯定会达到纵向扩展的上限。而NoSQL数据库是横向扩展的。

而非关系型数据存储天然就是分布式的,NoSQL数据库的扩展可以通过给资源池添加更多普通的数据库服务器(节点)来分担负载。

3、对事务性的支持不同。

如果数据操作需要高事务性或者复杂数据查询需要控制执行计划,那么传统的SQL数据库从性能和稳定性方面考虑是你的最佳选择。SQL数据库支持对事务原子性细粒度控制,并且易于回滚事务。

 

 

数据的操作(增删改查)


1.插入数据:
(1)单行INSERT语句
INSERT INTO [表名] (字段1,字段2) VALUES (100,'51WINDOWS.NET')
(2)多行INSERT语句
INSERT INTO [表名] (字段1,字段2) SELECT (字段1,字段2) FROM [表名2] WHERE [条件]


2.删除数据:
DELETE FROM [表名] WHERE [字段名]>100
更新数据:
UPDATE [表名] SET [字段1] = 200,[字段2] = '51WINDOWS.NET' WHERE [字段三] =
\'HAIWA\'


3.查询数据:
select (字段1,字段2) from [表名] where [条件] order by [字段] desc;


4.删除表:
Drop table [表名]


5.新增字段:
ALTER TABLE [表名] ADD [字段名] NVARCHAR (50) NULL


6.删除字段:
ALTER TABLE [表名] DROP COLUMN [字段名]


7.修改字段:
ALTER TABLE [表名] ALTER COLUMN [字段名] NVARCHAR (50) NULL

 

8.删除表中的所有字段:

truncate table tb;

 

关系型数据库与NOSQL

  • 关系型数据库
    • Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL
  • 非关系型数据库 NOSQL(Not Only SQL)
    • NOSQL特点:
      • 易扩展,数据之间没有关系的。
      • 大数据量,高性能。高性能读写非常灵活的。
      • 灵活的数据模型。不需要事先对存储数据建立字段。
      • 高可用。
    • NOSQL主要主流产品
      • Redis、CouchDB、mongoDB、Cassandra。NOSQL中比较火的三个数据库Redis、Memchache、MongoDb。

MySQL中char、varchar和text三者的区别

在MySQL中,char、varchar和text类型的字段都可以用来存储字符类型的数据,char、varchar都可以指定最大的字符长度,但text不可以。

它们的存储方式和数据的检索方式也都不一样。
数据的检索效率是:char > varchar > text

  • 具体说明:
    • char:存储定长数据很方便,CHAR字段上的索引效率级高,必须在括号里定义长度,可以有默认值,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间(自动用空格填充),且在检索的时候后面的空格会隐藏掉,所以检索出来的数据需要记得用trim之类的函数去过滤空格。
    • varchar:存储变长数据,但存储效率没有char高,必须在括号里定义长度,可以有默认值。保存数据的时候,不进行空格自动填充,而且如果数据存在空格时,当值保存和检索时尾部的空格仍会保留。另外,varchar类型的实际长度是它的值的实际长度+1,这一个字节用于保存实际使用了多大的长度。
    • text:存储可变长度的非Unicode数据,最大长度为2^31-1个字符。text列不能有默认值,存储或检索过程中,不存在大小写转换,后面如果指定长度,不会报错误,但是这个长度是不起作用的,意思就是你插入数据的时候,超过你指定的长度还是可以正常插入。
  • 关于存储空间:
    在使用UTF8字符集的时候,MySQL手册上是这样描述的:
    • 基本拉丁字母、数字和标点符号使用一个字节;
    • 大多数的欧洲和中东手写字母适合两个字节序列:扩展的拉丁字母(包括发音符号、长音符号、重音符号、低音符号和其它音符)、西里尔字母、希腊语、亚美尼亚语、希伯来语、阿拉伯语、叙利亚语和其它语言;
    • 韩语、中文和日本象形文字使用三个字节序列。
  • 结论:
    • 经常变化的字段用varchar;
    • 知道固定长度的用char;
    • 超过255字节的只能用varchar或者text;
    • 能用varchar的地方不用text;
    • 能够用数字类型的字段尽量选择数字类型而不用字符串类型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了;
    • 同一张表出现多个大字段,能合并时尽量合并,不能合并时考虑分表

查询借了“数据库”书籍的所有读者的的姓名

SELECT name

FROM reader

WHERE cardid IN

  (SELECT cardid

     FROM borrow

     WHERE bookid IN

      (SELECT bookid

       FROM book

       WHERE bookname = “数据库”))

 

查询借书期限超过两个月的所有读者的姓名、所借书籍和借书日期

SELECE name, bookname, bdate

FROM reader, book, borrow

WHERE book.bookid = borrow.bookid

AND book.cardid = borrow.cardid

AND MONTHS_BETWEEN(SYSDATE,bdate)>2

AND sdate IS NULL

 

按读者姓名查询指定读者的借还书历史记录,假设读者姓名为刘勇。

SELECT bookname, bdate, sdate

FROM book, borrow, reader

WHERE book.bookid = borrow.bookid

AND borrow.cardid = reader.cardid

AND reader.name = “刘勇”

 

三、Java语言

 

JAVA多线程开启的三种方式

1、继承Thread类,新建一个当前类对象,并且运行其start()方法 

2、实现Runnable接口,然后新建当前类对象,接着新建Thread对象时把当前类对象传进去,最后运行Thread对象的start()方法

3、实现Callable接口,新建当前类对象,在新建FutureTask类对象时传入当前类对象,接着新建Thread类对象时传入FutureTask类对象,最后运行Thread对象的start()方法

方法一代码:

public class Main {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start(); // 启动新线程
    }
}
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("start new thread!");
    }
}

方法二代码:

public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start(); // 启动新线程
    }
}
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("start new thread!");
    }
}

方法三代码:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableDemo {
 
    public static void main(String[] args) throws Exception{
        //参数表示此线程池里有多少可用的线程数量
        ExecutorService es = Executors.newFixedThreadPool(3);
        //提交线程任务,返回一个Future接口,参数为Callable实现类对象
        Future future = es.submit(new MyThreadClass());
        //获取返回值
        String s = future.get();
        System.out.println(s); 
    } 
}

public class MyThreadClass implements Callable{
    //V call()  由于该方法的返回值是个泛型V,所以具体的返回类型可以自己定义,下面返回值设置为了String,
    @Override
    public String call() throws Exception {
         return "笑笑";
    }
}

Integer和int的区别

  • Integer是int的包装类,int则是java的一种基本数据类型
  • Integer变量必须实例化后才能使用,而int变量不需要
  • Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
  • Integer的默认值是null,int的默认值是0

判断一个类是否“无用”,则需同时满足三个条件:

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例;
  • 加载该类的ClassLoader已经被回收
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

java类的加载:加载、链接、初始化

一:加载

(1)Java虚拟机将.class文件读入内存,并为之创建一个Class对象。

(2)任何类被使用时系统都会为其创建一个且仅有一个Class对象。

(3)这个Class对象描述了这个类创建出来的对象的所有信息,比如有哪些构造方法,都有哪些成员方法,都有哪些成员变量等。

二: 链接

链接包括验证、准备以及解析三个阶段。

(1)验证阶段。主要的目的是确保被加载的类(.class文件的字节流)满足Java虚拟机规范,不会造成安全错误。

(2)准备阶段。负责为类的静态成员分配内存,并设置默认初始值。

(3)解析阶段。将类的二进制数据中的符号引用替换为直接引用。

三:初始化

初始化,则是为标记为常量值的字段赋值的过程。换句话说,只对static修饰的变量或语句块进行初始化。

如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。

如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。

主方法

import java.util.scanner;

import java.util.*;

public class test{ 

    public static void main(String args[]){ 

        System.out.println("Hello, 欢迎学习JAVA"); 

   }

        }

输入和输出

Scanner sc = new Scanner(System.in);          构造一个输入对象

            System.out.println("enter your name:");  输出

            String name = sc.nextLine();             输入字符创

            System.out.println("enter your age:");

            int age = sc.nextInt();                    输入整数型数据

            System.out.println("enter your occupation:");

            Double occ = sc. nextDouble();             输入双精度型数

创建字符串

1)通过引用字符数组来创建字符串

char a[]={'A','b','c','E'};

String str1=new String(a);

System.out.println(str1);

 

2)先定义后赋值

String str2;

str2="this is a book";

System.out.println(str2);

 

3)通过截取字符数组的一部分来创建字符串

char a3[]={'a','b','c','D','6','p'};

String str3=new String(a3,2,4);

System.out.println(str3);

 

4)通过类的实例化对象方法实例化一串字符来创建字符串

String str4=new String("this is a book");

System.out.println(str4);

 

创建数组

一、声明并赋值

int[] arr = {1,2,4, …};

注意这里的花括号不是语句块,而且而且花括号后的分号也不能省

 

二、声明数组名开辟空间并且赋值

int[] arr;

arr = new int[]{1,2,3, …};

 

三、声明数组时指定元素个数然后赋值

int[] arr1= new int[3];

数据类型转换

字符串转化为整形数组

    String str="123456";
    int[] a = new int[str.length()];
    for(int i=0;i
        a[i]  = str.charAt(i)-'0';
    }

字符串转化为字符数组

    String str="123456";
    char[] c = str.toCharArray() ;
    System.out.println(c);

字符数组转化为字符串

    char[] c = {'a','s','d','4','5',};
    String str = new String(c);
    System.out.println(str);

字符数组转化为整型数组

    char[] c = { '1', '2', '3', '4', '5', };
    int[] a = new int[c.length];
    for (int i = 0; i < 5; i++) {
        a[i] = c[i] - '0';
        System.out.println(a[i]);
    }

整型数转化为字符串

1.String str = Integer.toString(i);  将整数型转换为字符串
2.String s = String.valueOf(i);  这个可以将double类型转换为字符串
3.String s = "" + i;

字符串转化为整型数

1、int i = Integer.valueOf(str).intValue();
2、double b = Double.parseDouble(str); 将字符串转换为double型
3、int b = Integer.parseInt(str);   将字符串转换为int型

如果

String str1 = “ad45nfdf”;

str1.charAt(0) 是为 “a”;

str1.charAt(7)是为”f”;

 

java的三大特性是:封装、继承、多态。

 

多态:

多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作

 

多态性是对象多种表现形式的体现。

现实中,比如我们按下 F1 键这个动作:

  • 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
  • 如果当前在 Word 下弹出的就是 Word 帮助;
  • 在 Windows 下弹出的就是 Windows 帮助和支持。

同一个事件发生在不同的对象上会产生不同的结果。

 

多态存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象

多态的实现方式

方式一:重写

方式二:接口

方式三:抽象类和抽象方法

 

继承的注意事项:

1,使用关键字 extends 让类与类之间 产生继承关系

2, 父类私有的成员,子类不能继承,因为根本看不到

3,不能为了继承某个功能而随意进行继承操作, 必须要符合 is a 的关系

苹果 is a 水果

男人 is a 

   is a 人 , 这种情况就不能继承了

继承中的成员变量关系:

不同名的变量:子类直接继承使用

同名的变量:默认访问的是子类自己的成员变量想访问父类中的同名变量,请使用 super.成员变量;

 

继承中的成员方法关系:

不同名的方法:子类直接继承使用

同名的方法:默认访问的是子类自己的成员方法,想访问父类中的同名方法,请使用 super.成员方法();

l super:用来表示当前对象中包含的父类对象空间的引用

调用父类的成员变量:

super.成员变量;

调用方法的成员方法:

super.成员方法();

 

方法重写(override) 在子父类中,出现了方法声明相同的情况,也叫做方法覆盖,方法复写

方法重写的注意事项:

1 子类的方法声明要与父类相同

2、子类要重写父类的方法,方法的权限修饰符不能比父类的更低

访问权限从高到低:public  protected   默认(什么都不写)  private

3, 父类私有的方法,子类不能够进行方法重写

 

方法重载(overload):指 在同一个类中,多个方法名称相同,它们的参数列表不同(个数不同,数据类型不同)

 

抽象

抽象方法: 方法只有声明部分,没有方法体

抽象类: 包含抽象方法的类,一定是抽象类

      使用 abstract 修饰的类,是抽象类

抽象类的特点:  

1,抽象类与抽象方法都必须使用 abstract来修饰  

2,抽象类不能直接创建对象

3,抽象类中可以有抽象方法,也可以没有抽象方法

4,抽象类的子类

a,实现了抽象方法的具体类

b,抽象类

抽象类面试题:

1,抽象类中是否可以没有抽象方法?如果可以,那么,该类还定义成抽象类有意义吗?为什么?

可以没有抽象方法,有意义,不会让其他人直接创建该类对象

 

抽象类总结

抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。

抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。

构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。

抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

JAVA 接口和抽象类的区别

本质:从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范

区别:

1.接口的方法默认是public,所有方法在接口中不能有实现,抽象类可以有非抽象的方法

2.接口中的实例变量默认是final类型的,而抽象类中则不一定

3.一个类可以实现多个接口,但最多只能实现一个抽象类

4.一个类实现接口的话要实现接口的所有方法,而抽象类不一定

5.接口不能用new实例化,但可以声明,但是必须引用一个实现该接口的对象

 

参数

抽象类

接口

默认的方法实现

它可以有默认的方法实现

接口完全是抽象的。它根本不存在方法的实现

实现

子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。

子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现

构造器

抽象类可以有构造器

接口不能有构造器

与正常Java类的区别

除了你不能实例化抽象类之外,它和普通Java类没有任何区别

接口是完全不同的类型

访问修饰符

抽象方法可以有publicprotecteddefault这些修饰符

接口方法默认修饰符是public。你不可以使用其它修饰符。

main方法

抽象方法可以有main方法并且我们可以运行它

接口没有main方法,因此我们不能运行它。

多继承

抽象方法可以继承一个类和实现多个接口

接口只可以继承一个或多个其它接口

速度

它比接口速度要快

接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。

添加新方法

如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。

如果你往接口中添加方法,那么你必须改变实现该接口的类。

 

序列化和反序列化

  • 定义:
    • Java序列化就是指把Java对象转换为字节序列的过程。Java反序列化就是指把字节序列恢复为Java对象的过程。
  • 作用
    • 序列化:在传递和保存对象时,保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。
    • 反序列化:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
  • 总结
    • 核心作用就是对象状态的保存和重建。

泄漏诊断

在大多数情况下,诊断内存泄漏需要非常详细地了解相关应用程序。警告:该过程可能很长并且是迭代的。

我们寻找内存泄漏的策略将相对简单:

  1. 识别症状
  2. 启用详细垃圾回收
  3. 启用分析
  4. 分析踪迹

3.1 识别症状

正如所讨论的,在许多情况下,Java进程最终会抛出一个OOM运行时异常,这是一个明确的指示,表明您的内存资源已经耗尽。在这种情况下,您需要区分正常的内存耗尽和泄漏。分析OOM的消息并尝试根据上面提供的讨论找到罪魁祸首。

通常,如果Java应用程序请求的存储空间超过运行时堆提供的存储空间,则可能是由于设计不佳导致的。例如,如果应用程序创建映像的多个副本或将文件加载到数组中,则当映像或文件非常大时,它将耗尽存储空间。这是正常的资源耗尽。该应用程序按设计工作(虽然这种设计显然是愚蠢的)。

但是,如果应用程序在处理相同类型的数据时稳定地增加其内存利用率,则可能会发生内存泄漏。

3.2 启用详细垃圾收集

断言确实存在内存泄漏的最快方法之一是启用详细垃圾回收。通常可以通过检查verbosegc输出中的模式来识别内存约束问题。

具体来说,-verbosegc参数允许您在每次垃圾收集(GC)过程开始时生成跟踪。也就是说,当内存被垃圾收集时,摘要报告会打印到标准错误,让您了解内存的管理方式。

此GC跟踪文件中的每个块(或节)按递增顺序编号。要理解这种跟踪,您应该查看连续的分配失败节,并查找随着时间的推移而减少的释放内存(字节和百分比),同时总内存(此处,19725304)正在增加。这些是内存耗尽的典型迹象。

3.3 启用分析

不同的JVM提供了生成跟踪文件以反映堆活动的不同方法,这些方法通常包括有关对象类型和大小的详细信息。这称为分析堆。

3.4 分析路径

本文重点介绍Java VisualVM生成的跟踪。跟踪可以有不同的格式,因为它们可以由不同的Java内存泄漏检测工具生成,但它们背后的想法总是相同的:在堆中找到不应该存在的对象块,并确定这些对象是否累积而不是释放。特别感兴趣的是每次在Java应用程序中触发某个事件时已知的临时对象。应该仅存少量,但存在许多对象实例,通常表示应用程序出现错误。

Java主动调用gc的方法

  1. System.gc();

  2. // 或者下面,两者等价

  3. Runtime.getRuntime().gc();

JAVA的反射机制

一 反射机制的概念:

指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制.

二  反射机制的应用:

生成动态代理,面向切片编程(在调用方法的前后各加栈帧).

三  反射机制的原理:

1  首先明确的概念: 一切皆对象----类也是对象.

2  然后知道类中的内容 :modifier  constructor  field  method.

3  其次明白加载: 当Animal.class在硬盘中时,是一个文件,当载入到内存中,可以认为是一个对象,是java.lang.class的对象.

死锁

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。

死锁发生原因

a. 竞争资源

b. 进程间推进顺序非法

解决死锁的基本方法

预防死锁:

资源一次性分配:一次性分配所有资源,这样就不会再有请求了:(破坏请求条件)
只要有一个资源得不到分配,也不给这个进程分配其他的资源:(破坏请保持条件)
可剥夺资源:即当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)
资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

避免死锁:
预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全的状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。
银行家算法:首先需要定义状态和安全状态的概念。系统的状态是当前给进程分配的资源情况。因此,状态包含两个向量Resource(系统中每种资源的总量)和Available(未分配给进程的每种资源的总量)及两个矩阵Claim(表示进程对资源的需求)和Allocation(表示当前分配给进程的资源)。安全状态是指至少有一个资源分配序列不会导致死锁。当进程请求一组资源时,假设同意该请求,从而改变了系统的状态,然后确定其结果是否还处于安全状态。如果是,同意这个请求;如果不是,阻塞该进程知道同意该请求后系统状态仍然是安全的。
检测死锁
首先为每个进程和每个资源指定一个唯一的号码;
然后建立资源分配表和进程等待表。
解除死锁:
当发现有进程死锁后,便应立即把它从死锁状态中解脱出来,常采用的方法有:

剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。


死锁检测方法
1、Jstack命令

jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息。 Jstack工具可以用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

2、JConsole工具

Jconsole是JDK自带的监控工具,在JDK/bin目录下可以找到。它用于连接正在运行的本地或者远程的JVM,对运行在Java应用程序的资源消耗和性能进行监控,并画出大量的图表,提供强大的可视化界面。而且本身占用的服务器内存很小,甚至可以说几乎不消耗。

 

四、数据结构和算法

 

堆栈空间分配区别:

1、栈(操作系统):由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;

2、堆(操作系统):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

堆栈缓存方式区别:

1、栈使用的是一级缓存,他们通常都是被调用时处于存储空间中,调用完毕立即释放;

2、堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

堆栈数据结构区别:

堆(数据结构):堆可以被看成是一棵树,如:堆排序;

栈(数据结构):一种先进后出的数据结构。

存储过程和触发器的区别有:

存储过程可以采用输入参数而触发器不可以;存储过程可以返回零或n值而触发器无法返回值,存储过程中可以使用事务,而触发器不允许

Hash表即散列表

其最突出的优点是查找和插入删除具有常数时间的复杂度

其实现原理是:把Key通过一个固定的算法函数即所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的

单向链表反转的多种实现方法

方法一:头节点插入法
实现步骤:

创建一个带头节点的链表resultList
定义一个循环链表变量p,p的初始值为待反转的链表
遍历待反转的链表,遍历条件为 (p !=null)
3.1 定义一个临时链表变量tempList保存p->next的值(因为p->next值会改变),用于下一次循环。
3.2 把p当前指向的首节点和resultList链表的头节点之后的节点拼接起来。
3.3 把3.2步骤中拼接的节点 再拼接到resultList头节点后。
3.4 p重新赋值为3.1步骤中保存的tempList的值。
返回resultList->next.即反转后的链表。


方法二:就地反转

实现步骤

创建一个带头节点的链表resultList,头结点指向待反转的链表。
创建p、pNext两个用于循环操作,分别指向两个待反转节点的位置,初始值如图所示,指向1和2
遍历带反转的链表,循环条件是pNext!=null.
3.1 从链表中分割出pNext节点,也就是让p指向pNext->next。
3.2 让pNext指向经过3.1操作之后的resultList.next(1->3->4->5)
3.3 让resultList头结点指向pNext(2->1->3->4->5)
3.4 让pNext指向p的下一个节点
难点在于理解循环中resultList.next指向性的变化,以及p和pNext两个变量的变化,p指向的链表首结点永远是1,只是节点1在resultList链表中位置在发生变化,而pNext是随着p移动的,脑子中间可以有一个摆绳模型,在起始点位置发力,绳子的高点位置会移到绳尾,那个最高点就是p变量位置。
 

数组和链表的区别

我们知道遍历数组和链表的时间复杂度是O(n),但是在实际中确实数组的速度要比链表快,这是为什么呢?

1.首先,数组是具有相同的数据类型且按一定次序排列的一组变量的集合体,构成一个数组的这些变量称为数组元素

        数组在内存中的地址是连续相邻的,而链表在内存的地址是散列的,不连续的

2. CPU缓存会把一片连续的内存空间读入, 因为数组结构是连续的内存地址, 所以数组全部或者部分元素被连续存

    在CPU缓存里面,而链表的节点是分散在堆空间里面的,这时候CPU缓存帮不上忙,只能是去读取内存,

    而缓存的速率要比内存快。

3. CPU --》寄存器--》缓存 --》内存

        cpu 取数据,处理数据,都要放到寄存器中处理(存放指令),缓存就是吧内存中提取的数据暂时保存在里面。

        如果寄存器要获取内存中同一位置的数据,就从缓存中获取,如果寄存器获取的不是同一个内存地址的数

        据(或者获取的内存地址缓存中不存在),就从内存中查找获取 

从上述比较中,我们可以看出数组的查询,要比链表的快
 

先、中、后序遍历

测试、测试开发面试准备和复习_第3张图片

 

红黑树

  • 结点是红色或黑色
  • 根结点始终是黑色
  • 叶子结点(NIL结点)都是黑色
  • 红色结点的两个直接孩子结点都是黑色(即从叶子到根的所有路径上不存在两个连续的红色结点)
  • 从任一结点到每个叶子的所有简单路径都包含相同数目的黑色结点

 现在有100W个账户密码,要存起来,要求查找时速度尽可能快,你选择什么数据结构?为什么?

参考回答:

选择hash_map,因为其查找速度与数据量基本无关,是常数级别,但是对空间的要求很高,所以是已空间换时间

 

查找方法和复杂度

查找方法

平均查找长度

适用范围

 

顺序查找

n+1/2

 

 

折半查找

Log2(n+1)-1

有序表

 

静态树表查找

Onlogn

 

 

二叉查找树

0log2n

 

 

平衡二叉树

 

 

 

测试、测试开发面试准备和复习_第4张图片

1、最简单的排序方法(直接插入排序法)

 

排序方法

复杂度

最大移动次数

最坏的情况(比较次数) 最好情况(比较次数)

 

直接插入排序法

 

(n-1)(n+4)/2

(n-1)(n+2)/2 n-1

最简单的排序方法

冒泡排序法

 

 

  n-1

 

快速排序法

 

 

  O(n*log2n)

 

希尔排序法

On²)

 

   

 

直接选择排序法

On²)

3(n-1)

均为n(n-1)/2

 

折半插入排序法

On²)

 

均是 n*log2n(2为底)

 

 

冒泡排序

/*冒泡排序 */
1 public class BubbleSort{
 2      public static void main(String[] args){
 3          int score[] = {67, 69, 75, 87, 89, 90, 99, 100};
 4          for (int i = 0; i < score.length -1; i++){    //最多做n-1趟排序
 5              for(int j = 0 ;j < score.length - i - 1; j++){    //对当前无序区间score[0......length-i-1]进行排序
 6                  if(score[j] < score[j + 1]){    //把小的值交换到后面
 7                      int temp = score[j];
 8                      score[j] = score[j + 1];
 9                      score[j + 1] = temp;
10                  }
11              }            
12              System.out.print("第" + (i + 1) + "次排序结果:");
13              for(int a = 0; a < score.length; a++){
14                  System.out.print(score[a] + "\t");
15              }
16              System.out.println("");
17          }
18              System.out.print("最终排序结果:");
19              for(int a = 0; a < score.length; a++){
20                  System.out.print(score[a] + "\t");
21         }
22      }
23  }

 

选择排序法

public class afrr4{
      public static void main(String[] args){
         int score[] = {67, 69, 75, 87, 89, 90, 99, 100,8,9,45,98};
         System.out.print("原始的序列:"+"\t");
         for(int b = 0; b < score.length; b++){
        	 
         System.out.print(score[b] + "\t");
         }
         System.out.println("");
         for (int i = 0; i < score.length; i++){    //最多做n-1趟排序
              for(int j = i+1 ;j < score.length; j++){    //对当前无序区间score[0......length-i-1]进行排序(j的范围很关键,这个范围是在逐步缩小的)
                 if(score[i] < score[j]){    //把小的值交换到后面,也就是把大的值放在第i位
                     int temp = score[j];
                     score[j] = score[i];
                     score[i] = temp;
                  }
             }            
              System.out.print("第" + (i + 1) + "次排序结果:");
             for(int a = 0; a < score.length; a++){
                 System.out.print(score[a] + "\t");
             }
             System.out.println("");
          }
              System.out.print("最终排序结果:");
             for(int a = 0; a < score.length; a++){
                  System.out.print(score[a] + "\t");
        }
      }
  }

 

归并排序法 

import org.junit.Test;
public class MergeSort {
    //两路归并算法,两个排好序的子序列合并为一个子序列
    public void merge(int []a,int left,int mid,int right){
        int []tmp=new int[a.length];//辅助数组
        int p1=left,p2=mid+1,k=left;//p1、p2是检测指针,k是存放指针

        while(p1<=mid && p2<=right){
            if(a[p1]<=a[p2])
                tmp[k++]=a[p1++];
            else
                tmp[k++]=a[p2++];
        }

        while(p1<=mid) tmp[k++]=a[p1++];//如果第一个序列未检测完,直接将后面所有元素加到合并的序列中
        while(p2<=right) tmp[k++]=a[p2++];//同上

        //复制回原素组
        for (int i = left; i <=right; i++) 
            a[i]=tmp[i];
    }

    public void mergeSort(int [] a,int start,int end){
        if(start

这里写图片描述

二分法查找

public static int search(int[] arr, int key) {
       int start = 0;
       int end = arr.length - 1;
       while (start <= end) {
           int middle = (start + end) / 2;
           if (key < arr[middle]) {
               end = middle - 1;
           } else if (key > arr[middle]) {
               start = middle + 1;
           } else {
               return middle;
           }
       }
       return -1;
   }

 

设计模式

模式 & 描述 包括
1 创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
  • 工厂模式(Factory Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 单例模式(Singleton Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)
2 结构型模式
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 过滤器模式(Filter、Criteria Pattern)
  • 组合模式(Composite Pattern)
  • 装饰器模式(Decorator Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)
3 行为型模式
这些设计模式特别关注对象之间的通信。
  • 责任链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 解释器模式(Interpreter Pattern)
  • 迭代器模式(Iterator Pattern)
  • 中介者模式(Mediator Pattern)
  • 备忘录模式(Memento Pattern)
  • 观察者模式(Observer Pattern)
  • 状态模式(State Pattern)
  • 空对象模式(Null Object Pattern)
  • 策略模式(Strategy Pattern)
  • 模板模式(Template Pattern)
  • 访问者模式(Visitor Pattern)
4 J2EE 模式
这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。
  • MVC 模式(MVC Pattern)
  • 业务代表模式(Business Delegate Pattern)
  • 组合实体模式(Composite Entity Pattern)
  • 数据访问对象模式(Data Access Object Pattern)
  • 前端控制器模式(Front Controller Pattern)
  • 拦截过滤器模式(Intercepting Filter Pattern)
  • 服务定位器模式(Service Locator Pattern)
  • 传输对象模式(Transfer Object Pattern)

 

设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

3、依赖倒转原则(Dependence Inversion Principle)

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

5、迪米特法则,又称最少知道原则(Demeter Principle)

最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

 

五、测试常识

软件测试流程:

1、需求分析  2、软件测试计划(写测试计划书)   3、软件测试设计阶段(写测试用例)  4、软件测试执行阶段  5、评估阶段(出具测试报告)

压力测试和负载测试

软件在一些超负荷情况下的运行情况属于压力测试,或者说属于负载测试应该也是合理的。而压力测试和负载测试属于性能测试,所以选B

压力测试是通过逐步增加系统负载的方式来测试系统性能的变化,最终确定在什么负载条件下系统性能处于失效状态

下面是依据的文档:

单元测试,详细设计文档

集成测试,概括设计文档

系统测试,系统设计文档

SOW:statement of work,工作任务说明书

HLD: High Level Design,概要设计说明书

LLD: Low Level Design,详细设计说明书

UTC: Unit Testing Cases,单元测试用例

单元测试的策略:

  1. 逻辑覆盖、
  2. 循环覆盖、
  3. 同行评审、
  4. 桌前检查、
  5. 代码走查、
  6. 代码评审、
  7. 景泰数据流分析

 

设计用例的方法、依据有那些

  • 白盒测试
    • 白盒测试用例设计有如下方法:语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖和路径覆盖。依据就是代码结构。
  • 黑盒测试
    • 黑盒测试用例设计方法:基于用户需求的测试、等价类划分方法、边界值分析方法、错误推测方法、因果图方法、判定表驱动分析方法、正交实验法、场景法。依据是用户需求规格说明书,详细设计说明书。

等值分析测试=等价类划分+边界值分析测试

 

单元测试、集成测试、系统测试

  • 粒度不同
    • 单元测试粒度最小,集成测试粒度居中,系统测试粒度最大。
  • 测试方式不同
    • 单元测试一般由开发小组采用白盒方式来测试,集成测试一般由开发小组采用白盒加黑盒的方式来测试,系统测试一般由独立测试小组采用黑盒方式来测试。
  • 测试内容不同
    • 单元测试主要测试单元是否符合“设计”,集成测试既验证“设计”,又验证“需求”,系统测试主要测试系统是否符合“需求规格说明书”。
  • 使用阶段不同
    • 单元测试为开发人员在开发阶段要做的事情,集成测试和系统测试为测试人员在测试周期内级层做的工作。

 

有效等价类和无效等价类

无效等价类是指对于软件规格说明而言,是没有意义的、不合理的输入数据集合。利用无效等价类可以找出程序异常说明情况,检查程序的功能和性能的实现是否有不符合规格说明要求的地方。

有效等价类是指输入数据完全满足程序输入的规格说明,是有效、有意义的输入数据所构成的集合。利用有效等价类可以检验程序是否满足规格说明所规定的功能和性能。

 

六、操作系统

 

对文件和目录进行操作的命令

  • pwd
  • cd
  • ls
  • touch
  • mkdir
  • rmdir
  • cp
  • mv
  • rm
  • wc
  • du

pwd:显示工作目录路径

命令语法:pwd [选项]

选项 含义
-L 目录链接时,输出链接路径
-P 输出物理路径

cd:更改工作目录路径

命令语法:cd[选项][目录]

选项 含义
cd或cd ~ 回到用户主目录
cd .. 变当前工作目录路径位置至当前目录的父目录。
cd -P 如果是链接路径,则进入链接路径的源物理路径
cd ~li 改用户工作目录路径位置至用户li的主目录。

ls:列出目录和文件信息

选项 选项含义
-a 显示指定目录下所有子目录的文件,包括隐藏文件
-A 显示指定目录下所有子目录与文件,包括隐藏文件,但不列出“.”和“..”
-c 配合-lt:根据车体么排序并显示ctime
-d 如果参数是目录,只显示其名称而不显示其下的歌文件和子目录
-F 显示文件类型
-i 在输出的第一列显示文件的inode号
-l 以长格式显示文件的详细信息
-r 逆序排列
-t 根据修改时间排序
-s 一块数形式先生每个文件分配的尺寸
-S 根据文件大小排序

例子:显示目录/var下文件的子目录的简单信息

~]# ls /var

显示/root目录下所以文件和子目录的详细信息,包括隐藏文件

~]# ls -al /root

显示/etc目录下的文件和子目录信息,用标记标出文件类型

~]# ls -F /etc

touch:创建空文件、更改文件时间

命令语法:touch [选项] [文件]

选项 选项含义
-a 只更改访问时间(atime)
-m 更改文件的修改时间记录(mtime)
-c 假如目标文件存在,则不会建立新的文件
-r<文件> 使用指定文件的时间属性而非当前时间
-d<字符串> 使用指定字符串表示时间而非当前时间
-t<日期时间> 使用[CC]YY]MMDDhhmm[.ss]格式的时间而非当前时间

例如:在当前目录下创建文件file1、file2、file3

[root@localhost ~]# touch file1
[root@localhost ~]# touch file2 file3
[root@localhost ~]# ls -l file1 file2 file3
-rw-r--r--. 1 root root 5 Aug  3 22:12 file1
-rw-r--r--. 1 root root 6 Aug  3 22:12 file2
-rw-r--r--. 1 root root 0 Aug  3 22:12 file3

将文件file1的时间记录改为9月17日19点30分

[root@localhost ~]# ls -l /root/file1
-rw-r--r--. 1 root root 5 Aug  4  2019 /root/file1
[root@localhost ~]# touch -c -t 09171930 /root/file1
[root@localhost ~]# ls -l /root/file1
-rw-r--r--. 1 root root 5 Sep 17  2019 /root/file1

时间格式是MMDDHHmm,如果要加上2019年年份

[root@localhost ~]# touch -c -t 09171930 /root/file1

mkdir:创建目录

命令语法:mkdir [选项] [目录]

选项 选项含有
-m<权限模式> 对新创建的目录设置权限,在没有-m选项时,默认权限是755
-v 每次创建新目录都显示信息
-p 可以是一个路径名称。此时若路径中的某些目录尚不存在,加上此选项后,系统将自动创建那些尚不存在的目录,即以此可以建立多个目录

例子:创建目录newdir1 ,其默认权限为755

[root@localhost ~]# touch -c -t 09171930 /root/file1
   [root@localhost ~]# ls -ld newdir1
drwxr-xr-x. 2 root root 6 Jun 22 22:27 newdir1

创建目录newdir2,其权限为777

[root@localhost ~]# mkdir -m 777 newdir2
[root@localhost ~]# ls -ld newdir2
drwxrwxrwx. 2 root root 6 Aug  3 22:39 newdir2

rmdir:删除空目录 命令语法:rmdir [选项] [目录]

选项 选项含义
-p 递归删除目录,当子目录删除后其父目录为空时,也一同被删除
-v 输出处理的目录详情

例子:同时删除/root/newdir2和/root/newdir2/newdir3这两个空目录

[root@localhost ~]# mkdir /root/newdir2
[root@localhost ~]# mkdir /root newdir2/newdir3
[root@localhost ~]# rmdir -pv /root/newdir2/newdir3
rmdir: removing directory, ‘/root/newdir2/newdir3’
rmdir: removing directory, ‘/root/newdir2’
rmdir: removing directory, ‘/root’
rmdir: failed to remove directory ‘/root’: Device or resource busy

cp:复制文件的和目录

命令语法:cp [选项] [源文件|目录] [目标文件|目录]

选项 选项含义
-a 在复制目录时保留链接、文件属性、并递归地复制目录,等同于-dpr选项
-d 复制时保留链接
-f 在覆盖目标文件之前不给出提示信息要求用户确认
-i 和-f选项相反看,在覆盖目标文件之前给出提示信息,要求用户确认
-p 出复制源文件的内容外,还把其修改时间和访问权限也复制到新文件中
-l 不做复制,只是链接文件
-r 如果给出的源文件是一个目录文件,将递归复制该目录下所有的子目录和文件。此时目标必须为一个目录名

例子:将/etc/grub2.cfg文件复制到/root目录下,并改名为grub

[root@localhost ~]# cp /etc/grub2.cfg /root/grub
cp: overwrite ‘/root/grub’? y
[root@localhost ~]# ls
anaconda-ks.cfg  grub  newdir1

将/etc/grub2.cfg文件复制到/root目录下

[root@localhost ~]# cp /etc/grub2.cfg /root
[root@localhost ~]# ls
anaconda-ks.cfg  grub  grub2.cfg  newdir1
[root@localhost ~]# 

将/boot目录以及该目录中的所有文件和子目录都复制到/root目录中

[root@localhost ~]# cp -r /boot /root
[root@localhost ~]# ls -l /root
total 24
-rw-------. 1 root root 1260 Jun  9 14:21 anaconda-ks.cfg
dr-xr-xr-x. 5 root root 4096 Jun 22 23:21 boot
-rw-r--r--. 1 root root 4287 Jun 22 23:15 grub
-rw-r--r--. 1 root root 4287 Jun 22 23:18 grub2.cfg
drwxr-xr-x. 2 root root    6 Jun 22 22:27 newdir1

mv:文件和目录改名、移动文件和目录路径

命令语法:mv [选项] [源文件|目录] [目标文件|目录]

选项 选项含义
-i 覆盖前询问
-f 覆盖前不询问
-n 不覆盖已存在的文件
-u 只有在源文件文件比目标文件新,或目标文件不存在时才进行移动
-T 将目标文件视作普通文件处理

例子:将/root/pic目录下所以的后缀名为“.png”的文件移动到/usr/local/share/pic目录下

[root@localhost ~]# mv -f /root/pic/*.png /usr/local/share/pic

把/root/pic/kpic.png文件改名为/root/pic/life.png

[root@localhost ~]# mv /root/pic/kpic.png /root/pic/life.png
[root@localhost ~]# ls /root/pic
{kpic.png  life.png

把/root/pic目录名称更改为/root/mypic

root@localhost ~]# mv /root/pic /root/mypic
[root@localhost ~]# ls /root
123.png}  anaconda-ks.cfg  boot  grub  grub2.cfg  mypic  newdir1

rm:删除文件或目录

命令语法:rm [选项] [文件|目录]

选项 选项含义
-f 强制删除。忽略不存在的文件,不给出提示信息
-r 递归删除目录及其内容
-i 在删除前需要确认

例子:删除当前目录下的file4文件

root@localhost ~]# rm file4
rm: remove regular empty file ‘file4’? y
[root@localhost ~]# ls
123.png}  anaconda-ks.cfg  boot  grub  grub2.cfg  mypic  newdir1

连同/root/ab/a文件和/root/ab目录一起删除

[root@localhost ~]# mkdir /root/ab
[root@localhost ~]# touch /root/ab/a
[root@localhost ~]# ls -l /root/ab/a
-rw-r--r--. 1 root root 0 Jun 22 23:51 /root/ab/a
[root@localhost ~]# rm -rf /root/ab
[root@localhost ~]# ls /root
123.png}  anaconda-ks.cfg  boot  grub  grub2.cfg  mypic  newdir1

wc:统计文件行数、单词数、字节数和字符数

命令语法:wc [选项] [文件]

选项 选项含义
-l 统计行数
-w 统计单词数
-c 统计字节数
-m 统计字符数
-L 统计文件中最长行的长度

例子:统计/root/aa文件的行数、单词数和字节数

[root@localhost ~]# wc -l /root/aa/ce.log
3 /root/aa/ce.log

统计/root目录下有多少子目录和文件

[root@localhost ~]# ls /root|wc -l
8

du:计算机文件或目录的容量

命令语法:du [选项]...[文件或目录]...

选项 选项含义
-h 人性化显示容量信息
-a 查看所有目录以及文件的容量信息
-s 仅显示总容量
-c 显示总计信息
-l 如果是硬连接,就多次计算其尺寸
-x 跳过处于不同文件系统之上的目录
-S 不包括子目录的占用量
-L 找出任何符号链接指示的真正目的地

查看/root目录及子目录的容量信息

[root@localhost ~]# du /root
[root@localhost ~]# du -a /root

查看/root所占磁盘空间总和

[root@localhost ~]# du -sh /root
100M	/root

以MB为单位显示/root目录磁盘占用量

[root@localhost ~]# du -sh /root
100M	/root
选项 选项含义
-h 人性化显示容量信息
-a 查看所有目录以及文件的容量信息
-s 仅显示总容量
-c 显示总计信息
-l 如果是硬连接,就多次计算其尺寸
-x 跳过处于不同文件系统之上的目录
-S 不包括子目录的占用量
-L 找出任何符号链接指示的真正目的地

查看/root目录及子目录的容量信息

[root@localhost ~]# du /root
[root@localhost ~]# du -a /root

查看/root所占磁盘空间总和

[root@localhost ~]# du -sh /root
100M	/root

以MB为单位显示/root目录磁盘占用量

[root@localhost ~]# du -sh /root
100M	/root

linux系统显示的命令

  • uname
  • hostname
  • free
  • du

uname:显示计算机及操作系统相关信息

命令语法:uname [选项]

选项 选项含义
-a 显示全部的信息
-m 显示计算机硬件架构名称
-n 显示在网络上的主机名称
-r 显示操作系统的内核发行号
-s 显示操作系统名称

例子:显示操作系统的内核发行号

[root@localhost ~]# uname -r
3.10.0-957.el7.x86_64

显示操作系统的全部信息

[root@localhost ~]# uname -a
Linux localhost.localdomain 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

hostname:显示或修改计算机主机名

命令语法:

  • hostname [选项] [主机名|-F <文件>]

  • hostname [选项]

选项 选项含义
-s 显示短主机名
-i 显示IP地址
-f 显示长主机名
-d 显示DNS

例子:显示当前计算机主机名

[root@localhost ~]# hostname
localhost.localdomain

设置当前计算机的主机名为linux[1]

[root@localhost ~]# hostname linux
[root@localhost ~]# hostname
linux

free:查看内存信息

命令语法:free [选项]

选项 选项含义
-c <次数> 显示指定次数结果数据
-t 显示内存加上swap总的容量
-b 以字节为单位显示内存使用情况
-k 以KB为单位显示内存使用情况
-m 以MB为单位显示内存使用情况
-g 以GB为单位显示内存使用情况

例子:查看系统物理内存和swap使用情况

[root@localhost ~]# free
              total        used        free      shared  buff/cache   available
Mem:         995896      148252      403780        7828      443864      621672
Swap:       2097148           0     2097148

显示系统的物理内存加上swap总的容量

[root@localhost ~]# free -t
              total        used        free      shared  buff/cache   available
Mem:         995896      147960      404052        7828      443884      621964
Swap:       2097148           0     2097148
Total:      3093044      147960     2501200

 

linux命令,找出关键字出现的次数

  • 语法:grep 字符串 文件名|wc -l ,grep输出,wc -l按行统计
  • 例子:
    • 统计task-hbase-transform.log中NullPointerException出现的次数:grep NullPointerException task-hbase-transform.log|wc -l
    • 如果是多个字符串出现次数,可使用: grep 'objStr1\|objStr2' filename|wc -l#直接用 | 链接起来即可。

常用命令

  • "|": 管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。连续使用管道意味着第一个命令的输出会作为第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。
  • grep:-v 不显示匹配上的内容;-n 显示匹配上的内容
    • grep -v down,显示不包含down的内容。
    • grep -n down,显示包含down的内容。
  • du:(disk use)显示每个文件和目录的磁盘使用空间。
  • df:(disk free)显示磁盘分区上可以使用的磁盘空间。

进程和线程

  • 区别:
    • 进程是资源分配的最小单位,线程是程序执行的最小单位(资源调度的最小单位)
    • 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
    • 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
    • 但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
  • 进程与线程的资源
    • 线程共享:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。
    • 线程独有:栈(保存其运行状态和局部自动变量)、程序计数器。
  • 进程与线程的同步
    • 进程:无名管道、有名管道、信号、共享内存、消息队列、信号量
    • 线程:互斥量、读写锁、自旋锁、线程信号、条件变量
  • 僵尸进程
    • 定义:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或者waitpid获取子进程的状态信息,那么子进程的进程描述符等一系列信息还会保存在系统中。这种进程称之为僵死进程。
    • 危害:在Unix系统管理中,当用ps命令观察进程的执行状态时,经常看到某些进程的状态栏为defunct,这就是所谓的“僵尸”进程。“僵尸”进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。由于进程表的容量是有限的,所以,defunct进程不仅占用系统的内存资源,影响系统的性能,而且如果其数目太多,还会导致系统瘫痪。
    • 处理方法:
      • 改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
      • 把父进程杀掉。父进程死后,僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。
  • 孤儿进程
    • 父进程运行结束,但子进程还在运行(未运行结束)的子进程就称为孤儿进程。孤儿进程最终会被init进程(进程号为1)所收养,因此init进程此时变成孤儿进程的父进程,并由init进程对它们完成状态收集工作。(linux下,init是内核启动的第一个用户级进程,init有许多很重要的任务,比如像启动getty(用于用户登录)、实现运行级别、以及处理孤立进程。)

Linux命令

  • "|": 管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。连续使用管道意味着第一个命令的输出会作为第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。
  • grep:-v 不显示匹配上的内容;-n 显示匹配上的内容
    • grep -v down,显示不包含down的内容。
    • grep -n down,显示包含down的内容。
  • du:(disk use)显示每个文件和目录的磁盘使用空间。
  • df:(disk free)显示磁盘分区上可以使用的磁盘空间。

显示终端上的所有进程

 ps -a

Linux杀死某个进程的方法

1.定位进程

ps -aux | grep ***

2.杀死进程

我们可以通过 进程的名字和进程的ID(PID)来结束进程。

结束命令:

kill:通过进程ID来结束进程

killall:通过进程名字结束进程

最常使用的结束进程的信号是:

Signal Name

Single Value Effect
SIGHUP  1  挂起
SIGINT 2 键盘的中断信号
SIGKILL 9 发出杀死信号
SIGTERM   15 发出终止信号
SIGSTOP 17, 19, 23 停止进程

 我们可以通过Single Value的值来代替信号的名字。所以我们现在来杀死python进程:

kill SIGNAL PID

SIGNAL 是要发送的信号,PID是进程号。

kill -9 14992

上面的命令就是杀死python进程的。如果有多个python程序在运行,想要全部结束的话,可以

killall -9 python

 

七、智力题

1、10个堆,每堆10个苹果,其中9个堆里苹果是50g/个,一个堆里苹果是40g/个,有一杆秤只能称一次,所称重量为x,求40g苹果所在堆。

    • 将堆编码为1-10;然后每堆拿出k个,最后少了k*10克,则知道是第几堆的苹果。

2、5L和6L水桶,得到三升水。

    • 1、6L的水桶装满水,倒满5L的桶。 2、将5L桶里的水倒了,将6L桶里剩余的1L放入5L桶。 3、6L的桶装满水,倒满5L桶里,6L桶里还剩2L(6-4)水。 4、 将5L桶里的水倒了,将6L桶里剩余的2L水放入5L桶里。 5、将6L桶装满水,倒满5L的桶,这时6L的桶里还剩3L水。

3、两个一小时蚊香怎么得到15分钟的记时

    • 同时点燃AB两只蚊香,其中A蚊香点燃两头,等A蚊香烧完后(30分钟),点燃B蚊香的另一头。

4、4分钟沙漏和7分钟沙漏怎么漏出9分钟

    • 4分钟的和7分钟的同时开始,4分钟的完后又倒过来开始。7分钟的沙漏完后立马倒过来,(4分钟的沙漏还剩1分钟)。等4分钟的沙漏完后,将7分钟的又立马倒过来,等漏完就是9分钟。

5、八个球,其中有一个是其余球重量的1.5倍,有什么方案找出来

    • 3次。 AB两边,一边放4个,如果A重,则把B端的去了,A端的4个分成AB端一边两个。在把轻的那端去了,重的那端的2个分成一边一个,重的那个球就找出来了。

6、桌上100个球,每次可以拿一到五个, 现在我们两个人依次拿球,你先拿,使用怎样的拿球策略,可以使你最终能拿到最后一个球?

    • 第一次拿四个,后来每个你拿球的时候只要保证剩下的球是6的倍数就行了如果他拿n个球 ,你就拿6-n个球。

7、有10个石头,每人每次可以拿1-2个,轮流拿,最后一个拿的人算输,有什么必赢的方案。

    • 对方先拿、保证两个人每一轮回拿满3个(对方拿一个,我拿两个、对方拿两个,我拿一个)。

8、一亿数据获取前1000个最大值 https://zhuanlan.zhihu.com/p/73233544

    • 把一亿个数字的前100个 首先放入数组。 然后把最小值放在ary[0]。然后再循环100到一亿之间的。 每次循环判断当前数字是否大于ary[0]当大于时,当前数字放入ary[0] 并再次重构数组最小值进入ary[0]以此类推 。当循环完这一亿个数字后。 最大的前100个数字就出来了。

9、经典智力题:飞机加油问题

你可能感兴趣的:(测试,测试开发面试复习,mysql,linux,java,面试,经验分享)