营销型网站和传统网站区别,佛山网站建设thual,wordpress 跳转插件,做自动发卡密网站的教程帝王之气#xff0c;定是你和万里江山#xff0c;我都护得周全 文章目录 前言1. 网络原理get与post的区别TCP/IP各层是如何传输数据的IP头部包含哪些内容TCP头部为什么有浮动网络层协议1. 路由协议2. 路由信息3. OSPF与RIP的区别Cookie与Session#xff0c;Token的区别http与… 帝王之气定是你和万里江山我都护得周全 文章目录 前言1. 网络原理get与post的区别TCP/IP各层是如何传输数据的IP头部包含哪些内容TCP头部为什么有浮动网络层协议1. 路由协议2. 路由信息3. OSPF与RIP的区别Cookie与SessionToken的区别http与https的区别http的状态码401与403区别http1.0与1.12的区别http协议有哪些方法网络延时体现在哪些方面呢输入url到显示的全过程( DNS域名解析三次握手浏览器是如何渲染的)常用的端口号有哪些弱网测试介绍下tcp的滑动窗口和拥塞控制 2. 测试题测开和研发的区别为什么选择测开测试开发的职责测试的分类白盒测试和黑盒测试的介绍。水杯的测试用例。视频播放器的测试用例朋友圈评论的测试用例抖音评论设计测试用例软件测试的流程是什么软件测试类型开源的测试工具信息安全测试设计一个蓝牙耳机的测试用例怎样设计测试用例接口测试测试用例设计方法集成测试和系统测试的区别具体提的bug开发不认怎么办 Java语法手撕代码快排(因为面试的太快了所以进行了加试又让多写一个代码)删除list链表的指定元素。二分查找java多态的好处和如何实现多态哈希算法MD5SHA-256hashmap1. 底层架构2. 常用方法3. 哈希函数设计4. C语言实现避免死锁数组和链表的区别super与this的区别static的用法抽象类和接口你刚说的ConcurrentHashMap是如何保证线程安全的呢深拷贝与浅拷贝数据库的索引有哪些都有什么区别数据库的内、外链接的区别如何在10000个数中查找一个数Thread和Runnbale的区别hashmap线程安全有哪些线程安全的集合git中commit和push的区别 java的锁机制数据库怎么提高查询效率Linuxhead和显示文档的前10行什么时候应该建索引什么时候不应该建索引Linux用端口号查看进程Linux查找重复单词出现次数linux常用命令linux如何查看线程状态Linux查看进程和端口号Java多线程实现方式线程池有几种 前言 
秋招在即测试开发岗的伙伴看过来啦~~ 1. 网络原理 
get与post的区别 
获取数据GET请求用于从服务器获取读取数据而POST请求用于向服务器提交发送数据。 
数据参数GET请求将数据参数附加在URL上以查询字符串的形式传输例如http://www.example.com?nameJohnage25。而POST请求将数据参数包含在请求体中不会在URL中显示。 
安全性由于GET请求将数据参数暴露在URL上因此相对不太安全例如密码等敏感信息可以在URL中被看到而POST请求将数据参数包含在请求体中相对较安全。 
请求长度限制GET请求对URL的长度有限制不同浏览器和服务器的限制长度不同通常为2KB至32KB而POST请求没有长度限制可以发送较大的数据。 
缓存处理GET请求可以被浏览器缓存下次在相同的请求下可以直接从缓存获取数据而POST请求不会被缓存每次都需要向服务器发送请求。 
书签、历史记录由于GET请求将数据暴露在URL上可以在浏览器的历史记录中被看到并可以添加到书签中而POST请求不会暴露在URL中不能被添加到书签和历史记录中。 
总结GET请求适用于获取数据、导航、查询等操作数据传输较少安全要求较低的情况下使用POST请求适用于提交数据、修改数据、进行敏感操作数据传输较多安全要求较高的情况下使用。 
TCP/IP各层是如何传输数据的 
在TCP/IP协议栈中数据从一个层传输到另一个层是通过封装和解封装的方式进行的。以下是数据从应用层到物理层的传输过程 
应用层Application Layer 
应用层数据被封装为应用层协议数据单元Application Layer Protocol Data Unit简称APDU。 应用层协议如HTTP、FTP等处理这些APDU并在需要时添加协议头部信息。 传输层Transport Layer 
应用层的数据被传递给传输层传输层将数据封装为传输层协议数据单元Transport Layer Protocol Data Unit简称TPDU。 传输层的协议如TCP、UDP负责提供端到端的可靠传输或不可靠传输。 网络层Network Layer 
传输层的TPDU被传递给网络层网络层将数据封装为网络层协议数据单元Network Layer Protocol Data Unit简称NPDU。 网络层的协议如IP负责将数据包从源主机发送到目标主机。 数据链路层Data Link Layer 
网络层的NPDU被传递给数据链路层数据链路层将数据封装为数据链路层协议数据单元Data Link Layer Protocol Data Unit简称DPDU。 数据链路层的协议如以太网、Wi-Fi等处理这些DPDU并在需要时添加帧头部和帧尾部以便在物理介质上传输。 物理层Physical Layer 
数据链路层的DPDU被传递给物理层物理层负责将数据转化为比特流并通过物理介质进行传输。这可以涉及电气、光学或无线信号的传输。 
IP头部包含哪些内容 
IPInternet Protocol头部包含以下内容 
1️⃣ 版本Version指示IP协议的版本通常为IPv4或IPv6。 
2️⃣ 首部长度Header Length指示IP首部的长度以32位字4字节为单位。由于IP首部长度可变这个字段用于确定首部的结束位置。 
3️⃣ 服务类型Type of Service用于指定IP包的优先级、QoSQuality of Service和流量管理。 
4️⃣ 总长度Total Length指示整个IP包包括首部和数据的长度以字节为单位。 
5️⃣ 标识Identification用于分片和重新组装IP包。当一个IP数据包太大无法一次传输时它会被分割成多个片段并使用相同的标识进行标记。 
6️⃣ 标志Flags包含3个位字段用于控制IP包的分片和重新组装。其中包括DFDon’t Fragment位和MFMore Fragments位。 
7️⃣ 片偏移Fragment Offset指示当前片段相对于原始IP包起始位置的偏移量以8字节为单位。 
8️⃣ 生存时间Time to Live指定IP包在网络上可以经过的最大跃点数通常是路由器。每经过一个路由器生存时间减1直到生存时间为0时包会被丢弃。 
9️⃣ 协议Protocol指示IP包中承载的上层协议如TCP6、UDP17或ICMP1。 首部校验和Header Checksum用于检测IP首部在传输过程中是否出现错误。 
1️⃣1️⃣ 源IP地址Source IP Address标识IP包的发送者的IP地址。 
1️⃣2️⃣ 目标IP地址Destination IP Address标识IP包的接收者的IP地址。 
TCP头部为什么有浮动 
TCP报文头部的长度是可变的即它可以根据需要动态调整大小。这种可变长度的设计主要是为了支持TCP的选项Options功能。 
TCP报文头部最小长度是20个字节不包括选项部分其中包括源端口号、目标端口号、序列号、确认号以及其他必需的字段。如果没有使用任何选项TCP头部就只有20个字节。 
然而TCP允许在头部中包含一些可选的扩展功能这些功能被称为TCP选项。选项可以用于提供额外的功能或向通信的对等方发送特定的控制信息。常见的TCP选项包括窗口大小调节、时间戳、选择确认等。 
由于选项部分的长度可变当TCP报文头部中包含了选项时头部的总长度就会增加。因此TCP头部的长度可以根据选项内容的增减而浮动。 
在TCP头部的最后有一个字段称为选项长度Options Length它指示了选项部分的长度。通过这个字段接收方可以确定TCP头部的总长度和如何解析选项部分的内容。 
总的来说TCP头部的浮动长度是为了支持选项部分的可变性从而使TCP协议能够根据不同的需求和功能进行灵活的配置和扩展。 
网络层协议 
1. 路由协议 
路由协议是用于在计算机网络中确定数据包传输路径的一组规则和算法。它们定义了网络中的路由器如何交换路由信息、如何选择最佳路径以及如何更新和维护路由表。 
当数据包从源主机发送到目标主机时它必须经过多个路由器才能到达目标。路由协议的作用是帮助路由器决定数据包应该从哪个接口发送并确定下一跳的路由器。这样在整个网络中数据包会沿着一条或多条路径被正确地转发最终到达目标主机。 
常见的路由协议包括 
链路状态路由协议Link State Routing Protocol如OSPF开放最短路径优先、IS-IS中间系统到中间系统它们基于每个路由器相互通告的链路状态信息来计算最优路径。 
距离矢量路由协议Distance Vector Routing Protocol如RIP距离矢量路由信息协议、EIGRP增强的内部网关路由协议它们基于每个路由器从邻居路由器收到的距离矢量来计算最优路径。 
路径矢量路由协议Path Vector Routing Protocol如BGP边界网关协议它是一种互联网络间的路由协议用于在不同自治系统AS之间交换路由信息。 
这些路由协议根据不同的网络需求和拓扑结构选择最佳路径优化数据包的传输效率和网络性能。 
2. 路由信息 
路由信息是指在计算机网络中路由器用来确定数据包传输路径的相关信息。它包括了网络中各个路由器之间相互交换的路由表、网络拓扑结构、地址信息和路由策略等。 
路由器通过路由信息来判断数据包的下一跳和最佳路径。这些信息告诉路由器如何将数据包从源主机转发到目标主机。 
常见的路由信息包括 
路由表Routing Table它是路由器中存储的一张表格记录了目的网络地址和下一跳路由器的关系。路由表中的每一项称为路由条目它包含了目的网络地址、子网掩码、下一跳路由器的地址和接口等信息。 
网络拓扑Network Topology它描述了网络中各个节点路由器、主机之间的连接关系。网络拓扑可以是物理拓扑如链式、星型、网状或逻辑拓扑如树型、网状。 
路由协议的交换信息路由器通过路由协议相互交换路由信息。这些信息可以包括链路状态、距离矢量、路径矢量等用于计算最佳路径并更新路由表。 
地址信息路由信息也涉及到网络中设备的地址如IP地址、MAC地址等。这些地址用于标识网络上的不同主机和路由器以便路由器可以根据这些地址进行转发和路由选择。 
3. OSPF与RIP的区别 
OSPF开放最短路径优先和 RIP距离矢量路由协议是两种常见的路由协议它们有一些区别和特点 
算法类型 
OSPF是一种链路状态路由协议它通过交换链路状态数据库在链路状态路由协议中每个路由器维护自己的链路状态数据库其中包含了该路由器所连接的链路以及邻居节点的状态。这些状态信息可以包括链路的可用性、带宽、延迟、拓扑结构等来计算最短路径。 RIP是一种距离矢量路由协议它根据跳数hop count来选择路径。 路由更新 
OSPF只在网络状态发生变化时进行路由更新这种响应式的方式可以减少路由更新的频率降低网络开销。 RIP则定期广播整个路由表无论网络状态是否发生变化这会导致在大型网络中产生较高的网络开销。 收敛速度 
OSPF收敛速度较快当网络状态发生变化时仅需更新受影响区域的路由表。此外在OSPF中每个路由器都维护了一个完整的网络拓扑图这样可以更快地计算出最短路径。 RIP的收敛速度相对较慢因为它需要等待定时更新或收到广播消息才能进行路由表更新并且无法快速适应网络的变化。 在OSPF中有以下几种类型的链路状态广告Link State AdvertisementLSA 
类型1 LSA路由器LSA用于广播每个OSPF路由器的链接状态和连接到的网络。 类型2 LSA网络LSA用于表示通过DRDesignated Router连接到的网络。 类型3 LSA网络汇总LSA用于表示区域间的路由信息。 类型4 LSAASBR汇入LSA用于表示ASBRAS边界路由器引入的外部路由。 类型5 LSA外部LSA用于表示外部网络。 
Cookie与SessionToken的区别 
CookieCookie Cookie 是服务器在客户端通常是浏览器存储的小型文本文件。它由服务器发送到客户端并由客户端存储在本地。每当客户端与同一服务器进行通信时它会将 Cookie 附加到请求中发送回服务器。 Cookie 通常用于在不同请求之间跟踪用户会话状态存储用户喜好设置以及身份验证凭证等信息。 
会话Session 会话是服务器上存储的用户会话信息。当用户首次访问服务器时服务器会为该用户创建一个唯一的会话 ID。该会话 ID 存储在客户端的 Cookie 中或通过 URL 重写传递给客户端。用户在访问应用程序的不同页面时会将该会话 ID 作为输入发送回服务器服务器使用该会话 ID 来查找和恢复与用户相关的会话数据。会话通常用于存储敏感数据和验证用户身份。 
令牌Token 令牌是一种代表用户身份验证信息的加密字符串。令牌通常由服务器生成并在用户成功进行身份验证后提供给客户端。客户端在后续请求中将令牌包含在请求中服务器使用令牌来验证用户的身份和权限。令牌能够独立于会话存储用户状态因此可以在分布式系统中使用并具有高度的安全性。 
当涉及到 Cookie、会话Session和令牌Token时下面是它们的几个主要区别点 
存储位置 Cookie 存储在用户的浏览器中以文本文件的形式。 会话信息存储在服务器端的内存或数据库中。 令牌通常在客户端如浏览器中存储可以是在内存中或本地存储中。 安全性 Cookie 可以设置为仅通过安全的 HTTPS 连接传输并且可以设置为仅在特定的域和路径下被访问。它们可以被浏览器篡改或盗用。 会话信息存储在服务器端客户端只有会话 ID相对较安全但仍然有可能被劫持。 令牌可以使用加密算法生成并通过 HTTPS 进行传输具有较高的安全性。令牌通常使用 JSON Web TokenJWT标准来包含用户身份信息和其他相关数据。 生命周期和持久性 Cookie 可以设置过期时间可以是永久的持久性 Cookie或在浏览器关闭后被删除会话 Cookie。 会话 ID 存储在服务器端其有效期由服务器管理通常在用户注销或一段时间不活动后失效。 令牌可以设置有效期并且可以灵活地进行管理。客户端存储的令牌不会在浏览器关闭后被删除除非显式删除或令牌过期。 无状态/有状态 Cookie 和会话都是有状态的机制服务器需要在其存储状态以跟踪用户会话。 令牌是无状态的机制服务器不需要在其存储任何信息令牌自包含身份验证信息因此可以在分布式系统中更容易地扩展和处理。 这些是 Cookie、会话和令牌的一些主要区别具体使用哪种技术取决于你的应用程序需求和安全性要求。 
http与https的区别 
端口号HTTP默认使用80端口而HTTPS默认使用443端口。 安全性HTTP是一种不加密的明文协议数据可以被第三方窃听和篡改而HTTPS通过使用在HTTP的基础上 采用SSL或TLS协议加密传输数据确保数据在传输过程中不会被窃听和篡改。 
数据传输速度由于HTTPS需要进行加密解密操作导致其传输速度比HTTP要慢一些。 
端口号默认情况下HTTP使用80端口HTTPS使用443端口。 
证书为了使用HTTPS网站需要购买数字证书并安装到服务器上以保障通信的安全性。而HTTP不需要证书。 
认证方式通过HTTPS连接访问的网站在建立连接时会进行双向认证即浏览器验证服务器证书的真实性同时服务器也会验证浏览器的身份。而HTTP没有认证机制。 
http的状态码 
HTTPHypertext Transfer Protocol协议定义了一系列状态码用于表示服务器对请求的处理结果。以下是一些常见的HTTP状态码及其含义 
1xx信息类状态码表示服务器已接收到请求正在处理。 100 Continue服务器已收到请求的初始部分并且客户端应继续发送其余部分。 
2xx成功类状态码表示服务器成功接收、理解并处理请求。 200 OK请求已成功正常返回结果。 201 Created请求已成功并在服务器上创建了新的资源。 204 No Content服务器成功处理了请求但未返回任何内容。 
3xx重定向类状态码表示需要进行进一步操作才能完成请求。 301 Moved Permanently请求的资源已永久移动到新的URI。 302 Found请求的资源已暂时移动到新的URI。 304 Not Modified请求的资源未改变可使用缓存的版本。 
4xx客户端错误类状态码表示客户端发送的请求有错误。 400 Bad Request请求无效服务器无法理解。 401 Unauthorized请求要求身份验证。 403 Forbidden禁止访问意味着服务器理解请求但拒绝执行。 404 Not Found请求的资源不存在。 
5xx服务器错误类状态码表示服务器在处理请求时发生错误。 500 Internal Server Error服务器遇到了意外情况无法完成请求。 503 Service Unavailable服务器当前无法处理请求一段时间后可能恢复正常。 
401与403区别 
500表示服务器内部错误通常是指在处理请求时发生了未知的错误或异常。 
401表示未授权意味着客户端没有提供有效的身份验证凭据。这意味着客户端需要提供有效的凭据如用户名和密码才能访问受限资源。 
403表示禁止访问意味着服务器理解请求但拒绝执行。它表明请求者有权限访问所请求的资源但服务器拒绝执行该请求。这可以是由于对该资源的访问权限被明确拒绝或者由于请求者没有足够的权限执行该操作。 
http1.0与1.12的区别 
当然以下是HTTP 1.0、HTTP 1.1和HTTP 2之间的区别 
HTTP 1.0  HTTP 1.0是最早发布的HTTP协议版本之一。  它是一个简单的请求-响应协议每个请求都需要建立一个新的TCP连接。  不支持持久连接每次请求完成后都会断开连接。  不支持请求头部的压缩因此在请求中可能会有大量重复的信息。  不支持流水线处理即客户端必须等待服务器响应后才能发送下一个请求。 
HTTP 1.1  HTTP 1.1是HTTP协议的一个重要更新版本目前仍然广泛使用。  支持持久连接在单个TCP连接上可以发送和接收多个请求和响应减少了连接建立的开销。  引入了HTTP头部的压缩通过使用gzip或deflate等压缩算法来减少请求和响应的大小。  支持流水线处理允许客户端同时发送多个请求而无需等待响应。  引入了一些新特性如虚拟主机、分块传输编码等。 
HTTP 2  HTTP 2是HTTP协议的最新版本于2015年发布。  采用二进制协议而不是文本协议通过对头部和主体数据进行二进制编码来提高效率。  支持多路复用通过在同一个连接上同时传输多个请求和响应提高并发性能。  头部压缩得到了进一步优化减少了数据传输的大小。  引入服务器推送服务器可以在客户端请求之前主动推送相关的资源。  支持优先级和流控制允许客户端指定请求的优先级并避免拥塞。 
http协议有哪些方法 
GET从服务器获取指定资源的表示。GET方法是幂等的即多次调用不应产生副作用。 
POST向服务器提交数据用于创建新资源。POST方法不是幂等的每次调用可能会产生不同的结果。 
PUT向服务器发送数据用于更新指定资源。PUT方法通常用于完整替换资源。 
DELETE从服务器删除指定资源。 
HEAD与GET方法类似但只返回响应头部不返回实际数据主体。用于获取资源的元数据或检查资源是否存在。 
PATCH对资源进行部分更新。与PUT方法类似但只更新指定的字段或属性。 
OPTIONS用于获取服务器支持的HTTP方法和资源的通信选项。 
网络延时体现在哪些方面呢 
网页加载速度网络延时会导致网页加载缓慢用户需要等待较长时间才能完全加载页面内容。 
数据传输速度网络延时会使数据传输速度减慢导致文件上传、下载、视频流媒体等过程变得缓慢需要更多的时间才能完成。 
实时通信延迟在实时通信应用程序中如在线游戏、视频通话或语音聊天网络延时会导致传输的音频和视频信号有延迟影响参与者之间的互动体验。 
云服务和远程访问对于使用云服务的用户或需要远程访问服务器或远程办公的用户网络延时会导致连接变慢降低工作效率和响应速度。 
物联网设备和智能家居网络延时会影响物联网设备和智能家居的响应速度如智能灯泡、智能音响等的操作延迟增加。 
输入url到显示的全过程( DNS域名解析三次握手浏览器是如何渲染的) DNS域名解析当用户在浏览器中输入URL时浏览器首先进行DNS域名解析。它会向本地DNS服务器发送一个查询请求该请求包含要访问的域名。本地DNS服务器会查找域名对应的IP地址并将其返回给浏览器。  建立TCP连接一旦浏览器获得目标服务器的IP地址它会使用TCP/IP协议的三次握手来建立与服务器的连接。这个过程中浏览器会发送一个连接请求给服务器服务器接受请求并回复一个确认最后浏览器再发送一个确认给服务器建立了TCP连接。  发送HTTP请求建立了TCP连接后浏览器会向服务器发送HTTP请求。这个请求中包含了用户想要获取的资源的信息例如请求的方法GET、POST等、请求头、请求体等。  服务器处理请求并返回响应服务器接收到浏览器发送的HTTP请求后会根据请求的内容进行相应的处理。处理完毕后服务器会生成HTTP响应并将其发送回浏览器。  浏览器渲染页面一旦浏览器收到服务器返回的HTTP响应它会解析响应的内容。如果响应中包含HTML、CSS、JavaScript等资源浏览器会根据这些资源开始渲染页面。具体的渲染过程包括解析HTML结构、加载和解析CSS样式构建DOM树和CSSOM树执行JavaScript脚本等。  显示页面浏览器根据渲染得到的页面布局和样式信息将页面内容显示在用户的屏幕上。这包括将文本、图片、视频等内容进行布局排版并应用相应的样式使其可见。  
常用的端口号有哪些 
以下是一些常见的端口号及其对应的应用 
21FTP文件传输协议 22SSH安全外壳协议 23Telnet远程登录服务 25SMTP简单邮件传输协议 80HTTP超文本传输协议 443HTTPS安全超文本传输协议 110POP3邮局协议版本3 143IMAP互联网消息访问协议 53DNS域名系统服务 67/68DHCP动态主机配置协议 3306MySQL数据库服务 3389远程桌面协议 8080备用HTTP端口 
弱网测试 
介绍下tcp的滑动窗口和拥塞控制 
2. 测试题 
测开和研发的区别为什么选择测开 
测开测试开发和研发开发工程师是软件开发团队中的两个不同角色分别负责不同的任务和职责。 
职责不同: 
测开主要负责编写自动化测试脚本、执行测试用例、分析测试结果等以确保软件质量。 研发主要负责编写项目功能代码、解决技术问题、开发新功能等。 技能需求不同: 
测开需要具备良好的软件测试基础知识如黑盒测试、白盒测试、性能测试等以及相关测试工具和技术的熟练掌握。 研发需要具备扎实的编程能力和开发经验熟悉项目所使用的编程语言、框架和相关技术。 工作重点不同: 
测开的主要目标是发现软件中的缺陷和问题并通过自动化测试减少人工测试的工作量提高效率。 研发的主要目标是根据项目需求、设计文档等开发出符合要求的功能模块或系统并保证代码的质量和可维护性。 提前介入阶段不同: 
测开在项目开发之初就参与关注需求文档和设计文档的编写提出测试建议并编写测试用例和测试计划。 研发则在需求和设计确定后参与负责具体的模块或功能的开发实现项目的具体需求。 需要注意的是测开和研发在某些情况下可能需要共同合作例如在开发过程中测开可以与研发一起制定自动化测试策略和测试框架研发也可以与测开一起分析测试结果和修复错误。 
测试开发的职责 
测试开发在质量保障中扮演着重要的角色对项目开发和项目迭代过程有以下帮助 
自动化测试测试开发人员可以使用脚本和工具来自动执行各种测试包括单元测试、集成测试、系统测试等。自动化测试可以提高测试效率和覆盖范围并减少人为错误和测试漏测的可能性。 
提前介入测试开发人员可以在开发早期参与项目帮助识别潜在的问题和风险并在需求定义和设计阶段提供测试的角度和建议。这有助于确保项目在实施之前就考虑到质量要求和规范减少后期修复的成本和风险。 
持续集成与持续交付测试开发人员可以与开发人员紧密合作构建持续集成和持续交付的流程。他们可以编写自动化测试脚本并将其整合到持续集成框架中以确保每次代码提交后自动运行测试。这有助于尽早发现和解决问题加快交付速度同时提供更稳定和可靠的软件版本。 
性能和负载测试测试开发人员可以使用专业工具和技术进行性能测试和负载测试以模拟和评估系统在不同负载条件下的表现和性能。这可以帮助检测潜在的性能瓶颈优化系统设计并确保系统在真实环境中正常运行。 
缺陷跟踪和管理测试开发人员可以使用缺陷跟踪系统记录和追踪项目中的问题和缺陷。他们可以协助开发人员定位和修复问题并与团队合作确保问题得到妥善解决。此外他们还可以进行缺陷分析检测和报告常见的缺陷模式和趋势以改进软件质量。 
测试的分类白盒测试和黑盒测试的介绍。 
白盒测试White Box Testing是一种测试方法旨在检查软件的内部结构和实现细节。测试人员了解软件的内部逻辑、代码和架构以设计测试用例和验证程序的正确性。白盒测试通常由开发人员或具有编程经验的测试人员执行。这种测试方法的目标是覆盖尽可能多的代码路径以发现潜在的错误或漏洞。 
黑盒测试Black Box Testing是一种测试方法主要关注软件的功能和行为而不涉及内部实现细节。测试人员在不了解软件内部设计的情况下基于预期的输入和输出设计测试用例并运行测试。黑盒测试侧重于验证软件是否符合规格说明、业务需求和用户期望。这种方法的目标是对软件的外部行为进行全面和独立的测试。 
总结起来白盒测试强调软件的内部结构和覆盖率侧重点在于代码级别的准确性和优化。而黑盒测试则侧重于功能和用户需求的验证关注的是软件在用户视角下的行为表现。 
水杯的测试用例。 
倾倒测试检查水杯的倾倒性能包括倾倒角度和流出速度。 承重测试测试水杯的最大承重能力以确定其耐久性。 渗漏测试将水杯充满液体放置一段时间后检查是否有渗漏。 耐热测试将热水倒入水杯中测试其耐高温能力。 耐寒测试将冷水倒入水杯中将其放置在低温环境下测试其耐寒能力。 摔落测试从不同高度将水杯摔落检查其是否会破裂或损坏。 清洁测试测试水杯的清洁性包括手洗和洗碗机洗涤后的外观和质量是否有变化。 味道测试倒入水后测试水杯是否会影响水的味道或产生异味。 安全测试检查水杯是否有尖锐的边缘或易碎的部分以确保使用时不会导致伤害。 材料测试对水杯的材料进行分析和测试确保符合相关的安全和质量标准。 
视频播放器的测试用例 
朋友圈评论的测试用例 
正常情况下发表评论  输入有效的评论内容并确认评论成功。 
空评论  不输入任何评论内容确认系统会拒绝发表空评论。 
包含敏感词的评论  输入包含敏感词的评论内容确认系统会拒绝发表评论或对敏感词进行过滤和处理。 
多行评论  输入多行评论内容确认系统能够正确处理和显示多行文本。 
长评论  输入超过评论字数限制的内容确认系统会限制字数或以省略号表示超出字数的部分。 
回复评论  对他人的评论进行回复确认回复评论的功能正常。 
删除评论  删除自己发表的评论确认评论被成功删除。 
点赞评论  对他人的评论点赞确认点赞功能正常。 
错误输入  输入特殊字符、表情符号或其他非法字符确认系统能够正确处理并防止错误输入。 
并发测试  在同一时间段内多用户对同一评论进行操作发表、回复、删除、点赞确认系统在并发情况下能够正确处理。 
抖音评论设计测试用例 
发布评论如果页面没有显示会是什么问题 
软件测试的流程是什么 
测试流程 1、评审版本版本需要增加的需求评估,软件需求和规格说明书。根据需求定义测试目标和范围。 2、测试计划分配qa测试需求,制定测试计划包括测试策略、资源规划和时间安排。 3、编写case分配给qa测试的需求进行编写测试方案、测试用例case 4、case评审方案评审case评审通过把case给开发进行自测 4.1 case评审时间开发提测前3天为什么提前3天如果产品改需求或者改方案 4.2 如果case没有评审通过或者出现其他问题重新编写case评估评审时间 4.3 评审通过就可以把case发给开发让他进行自测。 5、提测提测产品的需求他们开发5天或者xxxx几天预期多长时间交付提测提测要求p0-p1的case自测通过相当于冒烟测试 5.1 qa进行打包开始冒烟测试 6、冒烟测试开发提测后qa进行冒烟测试测试p0-p2的case 6.1 如果冒烟测试不通过打回从新自测从新提测 6.2 重新提测后按照6开始第二轮测试以此类推、3轮、四轮xxxxx轮 7、进行提交bug发现bug提交bug的生命周期、bug的优先级 7.1 直至当前的需求功能没有bug为止进行验收 7.2 编写测试报告 8、验收UI设计 、pm产品、运营验收包含需求功能、埋点、版本的功能 8.1 验收通过发测试报告测试通过 8.2 验收不通过重新测试把验收不通过的bugfix让开发解决重新验证关闭后 重新让产品、UI、运营验收产品需求 9、回归测试staging、pre、prod 9.1 回归自己负责的需求被分配的模块功能 9.2 没有blockerbug、没有验证的bug回归完成给产品同步下回归测试完成了简单验收下  禁止偷懒不回归case实话实说漏测就是漏测 10、上线pre、prod 10.1 上线是包含后端的需求 10.2 先上后端在上前端 一定要记住 需要做回归测试上一个节点回归一个节点 10.3 上线时间早上10点-下午5点左右能提前的发现问题如果是高峰期无法去解决 10.4 上线时间 周一、周二、周三、周四、周五不能上周六没人上班无法跟进问题  要同步产品上precn、us、eu了自己的需求回归没问题同步下产品 prod一样要同步产品上prodcn、us、eu了自己的需求回归没问题同步下产品 11、发版准备 
软件测试类型 
常见的软件测试类型包括 
单元测试单元测试是对软件中最小可测单元通常是函数或方法进行的测试目的是验证其功能的正确性。 
集成测试集成测试是在单元测试之后进行的它测试不同模块或组件之间的接口和交互。目标是验证各个模块能够正确地协同工作并且集成后的系统功能正常。 
系统测试系统测试是对整个软件系统进行的测试目的是验证系统是否按照需求规格进行设计和实现功能是否正常、性能是否可接受以及是否满足用户需求。 
验收测试验收测试是在所有其他测试类型完成后进行的最终测试用于确认系统是否满足用户需求和合同要求。它通常由用户、客户或相关利益相关者进行并基于预定的验收标准和场景进行验证。 
回归测试回归测试是在对软件进行更改、修复或功能扩展后进行的测试以确保已有功能仍然正常工作。它有助于捕捉潜在的故障引入并确保系统的稳定性和兼容性。 
性能测试性能测试是评估软件系统在不同负载条件下的性能表现。它包括测试系统的响应时间、吞吐量、资源利用率和稳定性等方面以确保系统能够在现实环境中满足性能要求。 
安全测试安全测试用于评估软件系统的安全性包括检查系统的漏洞、弱点和潜在的安全风险。它涵盖身份验证、授权、数据保护、网络安全等方面以确保系统能够有效防御潜在的安全威胁。 
开源的测试工具 
Selenium用于Web应用程序的自动化测试工具。它支持多种编程语言和浏览器并提供了丰富的API和功能用于模拟用户交互和验证应用程序的行为。 
JUnitJava中流行的单元测试框架用于编写和运行单元测试。它提供了断言、测试套件、测试修饰符等功能用于验证代码的正确性和可靠性。 
Appium用于移动应用程序的自动化测试工具。它支持Android和iOS平台可以用于测试原生应用程序、混合应用程序和移动网页应用程序并提供了跨平台的API进行交互和验证。 
JMeter用于性能测试和负载测试的工具。它可以模拟大量的用户并发操作并收集应用程序的性能数据用于分析和评估应用程序的性能指标。 
Cucumber一种行为驱动开发BDD工具用于编写可读性强的自动化测试。它使用简单易懂的自然语言来描述应用程序的行为将业务需求和自动化测试集成在一起。 
Apache JMeter一个用于负载测试、压力测试和性能测试的Java工具。它可以模拟多种类型的请求包括HTTP、FTP、数据库和其他服务并提供了强大的报告功能。 
Robot Framework一个通用的自动化测试框架可用于Web、移动、桌面和接口测试。它具有简单的关键字驱动语法和可扩展性支持多种测试库和插件。 
WireMock用于模拟和测试API的轻量级HTTP服务。它可以模拟RESTful API的行为包括请求和响应并提供了丰富的定制化选项。 
信息安全测试 
进行信息安全测试是评估系统、应用程序或网络的安全性的一种常用方法。下面是一些常见的信息安全测试方法 
漏洞扫描使用自动化工具扫描系统、应用程序或网络以发现已知的漏洞和安全弱点。这些工具可以帮助检测常见的漏洞如未经身份验证的访问、未经授权的操作、注入攻击等。 
✨ 漏洞扫描工具有很多种以下是一些常见的漏洞扫描工具 
1️⃣ Nessus一款功能强大的综合性漏洞扫描工具能够检测网络设备和应用程序中的安全漏洞。 
2️⃣ OpenVAS一款开源的漏洞扫描工具提供全面的漏洞扫描和漏洞管理功能。 
3️⃣ Nexpose一款商业漏洞扫描工具具有广泛的漏洞检测能力和用户友好的界面。 
4️⃣ QualysGuard一种基于云的漏洞扫描工具可以扫描网络、Web应用程序和云环境中的漏洞。 
5️⃣ Acunetix一款专注于Web应用程序漏洞扫描的工具能够检测常见的Web漏洞如跨站脚本XSS和SQL注入等。 
渗透测试通过模拟真实的攻击来评估系统的安全性。渗透测试是由专业的安全测试人员进行他们会尝试利用系统的漏洞和弱点来获取未经授权的访问或执行恶意操作。渗透测试可以帮助发现系统中的潜在安全问题并提供修复建议。 渗透测试是评估系统或应用程序安全性的过程以下是进行渗透测试的一般步骤 
1️⃣ 确定目标明确要评估的目标例如网络、应用程序、服务器等。 
2️⃣ 收集信息收集关于目标的信息包括IP地址、域名、子域名等。 
3️⃣ 制定方案制定渗透测试的计划和目标包括测试范围、方法、时间和人员。 
4️⃣ 扫描和识别使用漏洞扫描工具如Nessus、OpenVAS等扫描目标系统识别潜在的漏洞和安全弱点。 
5️⃣ 获取访问权限根据识别到的漏洞尝试获得系统的访问权限例如尝试默认密码破解、利用已知漏洞等。 
6️⃣ 探测和扩展通过探测内部网络、提升权限等方式进一步扩大对系统的访问权限。 
7️⃣ 维持访问尽可能地维持对目标系统的访问权限例如创建持久性后门、设置特权帐户等。 
8️⃣ 涵盖痕迹清理渗透测试过程中的痕迹以减少被发现的概率。 
9️⃣ 编写报告记录渗透测试的过程、发现的漏洞和建议的修复措施并生成一份详尽的报告。 建议修复根据渗透测试报告中的建议对发现的漏洞进行修复和加固。 
社会工程学测试社会工程学测试是通过模拟攻击者使用欺骗和人际交往技巧来尝试获取敏感信息或越过安全措施。这种测试方法主要针对人为因素如员工的安全意识和行为。 
代码审查对应用程序的代码进行审查以发现潜在的安全缺陷和漏洞。代码审查可以帮助识别可能导致安全问题的错误、不安全的编码实践或注入攻击点。 
安全配置审查审查系统和应用程序的配置以确保安全最佳实践的遵循。检查是否存在默认或弱密码、未加密的通信、过多的权限以及其他不安全的配置设置。 
网络流量分析通过监控和分析网络流量识别异常活动和潜在的安全威胁。这包括检测异常的数据传输、非法访问尝试、恶意软件传播等。 
应急响应演练模拟各种安全事件和攻击情景并测试应急响应计划的有效性和组织的响应能力。这有助于评估系统在面临安全威胁时的准备和反应。 
这些安全测试方法可以组合使用根据实际情况选择适合的测试方式。重要的是确保安全测试由经验丰富的专业人员进行以确保测试的有效性和缺陷的准确评估。 
设计一个蓝牙耳机的测试用例 
当设计蓝牙耳机的测试用例时可以考虑以下方面 
连接测试: 
确保耳机能够成功连接到蓝牙设备。 测试连接时的稳定性和速度。 测试在断开连接后重新连接是否正常工作。 测试同时连接多个设备时的表现。 音质测试: 
检查耳机的音频输出质量。 测试低音、中音和高音的清晰度和平衡性。 测试噪音过滤和降噪功能。 控制功能测试: 
测试耳机按钮的功能如播放/暂停音乐、调节音量、切换曲目等。 测试麦克风的录音和通话功能。 电池寿命测试: 
测试耳机的待机时间和持续播放音乐的时间。 检查充电时间和充电指示灯的准确性。 兼容性测试: 
测试耳机与不同的蓝牙设备如手机、平板电脑、电脑之间的兼容性。 测试不同蓝牙协议的支持如A2DP、HFP、AVRCP等。 特殊场景测试: 
在信号弱的环境下测试耳机的连接和音质表现。 在有其他无线干扰源的情况下测试耳机的性能。 测试在运动或户外使用时的舒适性和稳定性。 耐久性测试: 
测试耳机的耐用性如抗摔、抗水、耐汗等。 测试按键和接口的可靠性和耐用性。 软件升级测试: 
测试耳机固件的升级过程和稳定性。 检查软件更新后的功能和性能改进。 
怎样设计测试用例 
确定测试目标明确测试的目标和目的。了解被测试系统或功能的预期行为以及测试的范围和约束条件。 
确定测试类型根据测试目标和被测试系统的特点确定适合的测试类型。常见的测试类型包括功能测试、性能测试、安全测试、兼容性测试等。 
确定测试条件根据测试的目标和测试类型确定测试的输入条件、前置条件、环境配置等。确保测试用例的可执行性和可重复性。 
划分测试情景将测试条件分解为不同的测试情景或测试功能点。考虑正常情况、异常情况、边界情况、用户角色等不同方面的情况。 
设计测试用例为每个测试情景设计测试用例包括输入数据、预期输出、执行步骤和验证方法。确保测试用例具有可读性和完整性。 
考虑覆盖范围使用适当的测试技术和策略确保测试用例可以覆盖关键路径、主要功能和可能存在的缺陷点。常用的技术包括等价类划分、边界值分析、状态转换图等。 
确定优先级和关联关系根据测试目标和项目需求确定测试用例的优先级和关联关系。将重点放在核心功能和高风险区域上。 
约束和限制考虑测试资源、时间和成本的约束合理安排测试用例的数量和深度。根据项目进度和需求变更调整测试用例的设计和执行计划。 
编写测试步骤和预期结果在测试用例中清晰地描述测试的执行步骤并定义预期的测试结果或期望的系统行为。 
审查和验证与团队成员、产品所有者或相关方一起审查测试用例确保其准确性和有效性。 
执行和记录测试结果按计划执行测试用例并记录测试步骤、实际结果和任何问题或缺陷。确保测试结果可追溯和可重现。 
分析和反馈根据测试结果分析问题原因并提供有关改进和修复的反馈。与团队合作解决问题并更新测试用例以反映修复后的系统行为。 
定期维护和更新随着项目的进展和变化及时维护和更新测试用例。确保测试用例与系统的最新需求和功能保持一致。 
接口测试测试用例设计方法 
确定接口的功能和目标了解接口的预期功能和所需的输入输出。这包括请求的参数、响应的数据结构以及可能的错误信息。 
划分测试条件根据接口的功能和目标将测试条件划分为不同的测试情景。考虑正常情况下的输入、边界情况、异常情况和错误处理等。 
设计测试用例根据划分的测试条件为每个情景设计相应的测试用例。测试用例应包括请求的输入数据、期望的响应和验证方式。 
考虑复杂度和覆盖范围根据时间和资源的限制确定测试用例的复杂度和覆盖范围。可以采用等价类划分、边界值分析、正交实验等方法来优化测试用例的数量和效果。 
确定前置条件和后置条件对于每个测试用例确定必要的前置条件和后置条件例如环境设置、数据准备、数据库清理等。 
编写测试脚本或测试数据根据设计的测试用例编写相应的测试脚本或准备测试数据。可以使用接口测试工具或编程语言如Postman、cURL、Python等。 
执行测试并记录结果执行编写的接口测试用例并记录每个测试的结果、日志和错误信息。 
分析和修复问题分析测试结果查找并修复出现的问题。根据问题的严重程度和优先级重新设计和执行相关的测试用例。 
定期更新测试用例随着接口的功能和需求的变化定期检查和更新测试用例确保测试的完整性和准确性。 
集成测试和系统测试的区别具体 
集成测试和系统测试是软件测试中两个重要的阶段它们有以下区别 
范围不同集成测试的重点是验证不同模块或组件之间的接口和交互正确性确保它们能够协同工作。而系统测试的范围更广泛旨在测试整个系统的功能、性能、安全性等以验证系统是否满足用户需求。 
执行时间不同集成测试通常在开发阶段的后期进行当各个模块完成开发并集成在一起时。而系统测试在集成测试之后进行当整个系统开发完成并准备发布之前。 
测试目标不同集成测试侧重于发现模块之间的错误、接口问题和数据传递问题以确保模块的正常集成。系统测试的目标是验证系统的完整性、一致性和可靠性包括功能是否符合要求、性能是否满足预期、安全性是否达标等。 
测试环境不同集成测试通常在开发环境中进行使用模拟的或部分真实的数据主要集中在模块之间的接口交互上。而系统测试需要在更接近实际生产环境的环境中进行使用真实数据和实际用户操作来模拟真实场景。 
缺陷定位不同集成测试主要用于定位模块之间的集成问题和接口错误以便由相应的开发团队修复。系统测试则更多关注整体系统的问题包括功能缺陷、性能瓶颈、安全漏洞等需要整个开发团队共同参与修复。 
提的bug开发不认怎么办 提交bug后如果开发团队未能及时认可该问题您可以考虑以下步骤 
1️⃣ 重新确认bug描述确保您提供了清晰、详细的bug描述包括复现步骤、预期结果和实际结果。有时候不清晰或不完整的描述可能导致误解或忽略。 
2️⃣ 沟通和解释与开发团队进行沟通并解释bug的重要性以及它对系统功能、用户体验或安全性可能产生的影响。提供实际的例子或数据来支持您的观点。 
3️⃣ 寻求他人支持如果您与开发团队之间的沟通遇到困难尝试寻求其他团队成员、主管、项目经理或质量保证团队的支持。有时候其他人的权威和干预可能会促使问题被认可并解决。 
4️⃣ 提供更多上下文如果可能提供更多相关的上下文信息例如日志文件、错误消息或其他相关的数据以便开发人员更好地理解和调查问题。 
5️⃣ 寻求上级支持如果上述努力仍未取得进展可以考虑与您的上级或相关部门的负责人一起讨论请求他们的介入和支持。 
6️⃣ 寻找替代解决方案如果问题仍未得到开发团队的认可并且对系统或用户产生了重大影响您可能需要寻找其他解决方案例如通过配置更改、工作流程调整或实施临时补丁来减轻问题的影响。 
Java语法 
手撕代码快排(因为面试的太快了所以进行了加试又让多写一个代码)删除list链表的指定元素。 
二分查找 public static int find(int key,int[] arr){int index  0;int left  0;int right  arr.length-1;while(left  right){int mid  left(right-left)/2;if(arr[mid]  key){right  mid-1;}else if(arr[mid]  key){left  mid1;}else{index  mid;return index;}}return -1;}针对二分查找设计测试用例 当设计测试用例时可以考虑以下几种情况 
正确的查找目标元素传入的数组中包含目标元素并且目标元素在不同的位置如数组 {2, 5, 8, 12, 16, 23, 38, 56, 72, 91} 中查找目标元素 23 和 56。 
目标元素不存在于数组中传入的数组中不包含目标元素如数组 {2, 5, 8, 12, 16, 23, 38, 56, 72} 中查找目标元素 91。 
空数组传入一个空数组进行查找。 
数组只有一个元素传入只有一个元素的数组进行查找比如数组 {5} 中查找目标元素 5。 
边界条件传入的数组为空或只有一个元素分别查找目标元素和不在数组中的元素。 
java多态的好处和如何实现多态 
哈希算法 
MD5 MD5Message Digest Algorithm 5是一种常见的哈希算法。哈希算法将输入数据转换为固定长度的哈希值通常用于验证数据完整性和安全性。 
✅ MD5算法将任意长度的输入数据转换为128位的哈希值。它具有以下特点 
不可逆性无法从哈希值反推出原始输入数据。 唯一性不同的输入数据生成不同的哈希值。 快速计算相对于其他哈希算法MD5的计算速度较快。 ️ 尽管MD5在过去被广泛使用但由于其安全性方面的一些弱点如碰撞漏洞和性能问题它在当前的加密领域中已经不推荐使用。 
⚠️ MD5在密码存储方面不安全因为黑客可以使用预计算的MD5哈希值进行暴力破解或彩虹表攻击。 对于安全性要求较高的场景应该使用更强大的哈希算法如SHA-256Secure Hash Algorithm-256或SHA-3。 
SHA-256 SHA-256Secure Hash Algorithm 256-bit是一种常用的密码哈希函数用于将输入数据转换为固定长度的哈希值。它是SHA-2系列哈希函数中的一员提供更高的安全性和强大的抗碰撞能力。 
✅ SHA-256的特点包括 
安全性SHA-256是一个具有强大安全性的哈希算法在当前的密码学和数据完整性验证领域被广泛使用。 唯一性SHA-256确保不同的输入数据会生成不同的哈希值。 固定长度SHA-256生成256位32字节的哈希值。 ⚙️ SHA-256的应用领域包括数字签名、数据完整性验证、密码存储和传输安全等。它被认为是目前非常安全和可靠的哈希算法之一。 
 在密码存储方面使用SHA-256等安全哈希算法与适当的盐salt结合使用可以提高密码的安全性防止彩虹表攻击和暴力破解。 
️ 尽管SHA-256被广泛使用但随着时间的推移计算能力的增加某些攻击可能会出现因此密钥长度的选择和密码学的最佳实践仍然非常重要。 
hashmap 
1. 底层架构 
HashMap 是 Java 中常用的数据结构它基于哈希表实现用于存储键值对。下面是 HashMap 的底层逻辑 
存储结构HashMap 内部使用一个数组bucket来存储元素每个元素又以链表或红黑树形式组织称为桶bucket或者桶数组。数组的初始大小是16默认负载因子为0.75。 
哈希函数当你插入一个键值对时HashMap 使用键的哈希码通过 hashCode() 方法计算来计算一个桶的索引位置。哈希码经过处理后得到一个合法的数组索引。 
哈希冲突处理由于不同的键可以得到相同的哈希码可能会导致多个键值对被映射到同一个桶中这就是哈希冲突。当发生哈希冲突时HashMap 会使用链表或红黑树来解决冲突。 
链表在 Java 8 之前所有冲突的键值对都会以链表的形式存储在桶中按照插入顺序连接。这种解决冲突的方式称为链表法。但当链表长度达到一定阈值默认为8时链表会自动转换成红黑树。 
红黑树从 Java 8 开始当链表的长度超过一定阈值时链表会转换成红黑树这可以提高在大规模数据集中查找、插入和删除操作的性能。红黑树是一种平衡二叉搜索树它保持着相对平衡的高度使得这些操作的时间复杂度保持在 O(log n)。 
扩容与再哈希当 HashMap 中元素的数量超过容量与加载因子的乘积时默认为 0.75 * 16  12会触发扩容操作。扩容是为了减少哈希冲突将数组容量增加一倍并重新计算每个元素在新数组中的位置这个过程称为再哈希。 
总的来说HashMap 通过哈希函数将键映射到数组桶的索引位置使用链表或红黑树处理桶中的哈希冲突并且在需要时进行扩容和再哈希操作以提供高效的键值对存取功能。 
2. 常用方法 
哈希表Hash table是一种基于哈希函数实现的数据结构它提供了高效的查找、插入和删除操作。以下是哈希表常用的方法 
put(key, value): 将指定的键值对插入到哈希表中。如果键已经存在则更新对应的值。 
get(key): 根据键获取对应的值。如果键不存在则返回 null。 
remove(key): 根据键从哈希表中删除对应的键值对。 
containsKey(key): 检查哈希表中是否包含指定的键。如果存在则返回 true否则返回 false。 
containsValue(value): 检查哈希表中是否包含指定的值。如果存在则返回 true否则返回 false。 
size(): 获取哈希表中键值对的数量。 
isEmpty(): 检查哈希表是否为空。如果为空则返回 true否则返回 false。 
clear(): 清空哈希表中的所有键值对使其为空。 
keySet(): 获取哈希表中所有键的集合。 
values(): 获取哈希表中所有值的集合。 
entrySet(): 获取哈希表中所有键值对的集合。 
hashmap存取数据是怎么进行的 
3. 哈希函数设计 
设计一个好的哈希函数是哈希表性能的关键之一。好的哈希函数应该能够尽可能地将输入的键均匀地分布到哈希表的桶中以减少冲突的发生。下面是一些常用的哈希函数设计方法 
取模运算法将键除以哈希表的大小取余数作为索引值。例如index  key % table_size。这是最简单常见的哈希函数适用于键的范围比较均匀的情况。 
乘法哈希法使用键与一个常数相乘再取整的方式。这种方法可以更好地利用键的各位特征减少冲突的概率。例如index  (int)(key * A) % table_size其中 A 是介于 0 到 1 之间的常数。 
字符串哈希法对于字符串键可以将每个字符的 ASCII 值进行加权求和。例如hash  (int)(str[0] * weight1  str[1] * weight2  …  str[n-1] * weightn) % table_size其中 weight1 到 weightn 是适当选择的常数权重。 
折叠法将长键分割成几个部分然后进行折叠求和。例如将键分成长度均为 k 的若干段然后相加得到哈希值。如果键的长度不能整除 k则在最后一段中包含剩余的字符。 
位运算法对于整型键可以通过位移、异或或者其他位运算操作来混洗键的各个位以获取更均匀的哈希值。 
无论使用哪种方法都应当根据实际应用场景来选择合适的哈希函数。根据键的类型和分布特征可能需要不同的函数设计策略。同时不同的哈希函数可能会导致不同的性能表现因此在实际使用中对于关键的哈希函数选择和优化也需要进行实验和性能测试。 
4. C语言实现 
#include stdio.h
#include stdlib.h#define TABLE_SIZE 100// 单链表节点
typedef struct Node {int key;int value;struct Node* next;
} Node;// 哈希表
typedef struct HashTable {Node* buckets[TABLE_SIZE];
} HashTable;// 创建哈希表
HashTable* createHashTable() {HashTable* hashTable  (HashTable*)malloc(sizeof(HashTable));for (int i  0; i  TABLE_SIZE; i) {hashTable-buckets[i]  NULL;}return hashTable;
}// 哈希函数
int hash(int key) {return key % TABLE_SIZE;
}// 插入键值对
void insert(HashTable* hashTable, int key, int value) {int index  hash(key);// 创建新节点Node* newNode  (Node*)malloc(sizeof(Node));newNode-key  key;newNode-value  value;newNode-next  NULL;// 将节点插入链表头部newNode-next  hashTable-buckets[index];hashTable-buckets[index]  newNode;
}// 查找键对应的值
int find(HashTable* hashTable, int key) {int index  hash(key);Node* currentNode  hashTable-buckets[index];// 在链表中遍历查找键while (currentNode ! NULL) {if (currentNode-key  key) {return currentNode-value;}currentNode  currentNode-next;}// 没找到return -1;
}// 删除键值对
void remove(HashTable* hashTable, int key) {int index  hash(key);Node* currentNode  hashTable-buckets[index];Node* prevNode  NULL;// 在链表中遍历查找键while (currentNode ! NULL) {if (currentNode-key  key) {if (prevNode  NULL) {// 节点位于链表头部hashTable-buckets[index]  currentNode-next;} else {prevNode-next  currentNode-next;}// 释放节点内存free(currentNode);return;}prevNode  currentNode;currentNode  currentNode-next;}
}// 销毁哈希表
void destroyHashTable(HashTable* hashTable) {for (int i  0; i  TABLE_SIZE; i) {Node* currentNode  hashTable-buckets[i];while (currentNode ! NULL) {Node* temp  currentNode;currentNode  currentNode-next;free(temp);}}free(hashTable);
}int main() {HashTable* hashTable  createHashTable();// 插入键值对insert(hashTable, 1, 10);insert(hashTable, 2, 20);insert(hashTable, 3, 30);// 查找键对应的值int value  find(hashTable, 2);if (value ! -1) {printf(Value: %d\n, value);} else {printf(Key not found\n);}// 删除键值对remove(hashTable, 2);// 销毁哈希表destroyHashTable(hashTable);return 0;
}避免死锁 
避免死锁是多线程编程中的重要问题以下是一些常用的方法来避免死锁的发生 
避免使用多个锁尽量设计简单的锁策略避免过多地使用多个锁。如果只需要一个锁来实现某个功能就不要引入多余的锁。 
统一获取锁的顺序如果必须使用多个锁确保在获取锁时始终以相同的顺序获取。这样可以避免不同线程获取锁的顺序不一致而导致的死锁。 
避免长时间占用锁在持有锁的情况下尽量避免进行复杂、耗时的操作。如果需要进行复杂操作可以先释放锁再重新获取锁。 
使用定时锁和尝试锁在获取锁的过程中可以使用定时锁tryLock(timeout)或者尝试锁tryLock()来避免在一段时间内无法获得锁而发生死锁。 
避免循环依赖当多个线程需要获取多个锁时确保不存在循环依赖的情况。即每个线程需要的锁都是按照相同的顺序来获取。 
使用资源分配图进行分析通过绘制资源分配图可以帮助分析潜在的死锁情况了解线程之间的依赖关系并采取相应的措施来避免死锁。 
合理使用同步工具如使用条件变量Condition来替代 synchronized 中的 wait() 和 notify()或者使用可重入锁ReentrantLock提供更灵活的锁控制。 
合理设计并发结构在设计并发结构时考虑到线程之间的依赖关系和资源竞争情况避免出现潜在的死锁场景。 
数组和链表的区别 
存储方式数组是一块连续的内存空间元素在内存中按照索引顺序排列而链表是由节点Node组成的每个节点包含数据和指向下一个节点的指针。 
插入和删除操作的效率在数组中插入和删除元素需要移动其他元素来调整位置平均时间复杂度为O(n)。而链表在插入和删除元素时只需要修改节点的指针指向时间复杂度可以是O(1)只需要常数时间。 
访问元素的效率由于数组的内存是连续的可以通过索引直接访问元素时间复杂度为O(1)。而链表需要从头节点开始遍历直到找到目标节点平均时间复杂度为O(n)。 
空间占用数组需要一块连续的内存空间来存储元素因此需要预先分配足够的空间。而链表可以动态分配内存空间仅在需要时才创建新的节点因此占用的空间可以根据实际需求进行灵活管理。 
super与this的区别 
在Java中super和this是两个关键字用于引用不同的对象具有不同的作用和用法。 
super关键字 
super用于在子类中调用父类的成员方法、字段、构造函数。 使用super可以使子类在重写父类方法时显式地调用父类的方法避免循环调用。 在子类中可以使用super.成员名来访问父类中的成员变量或成员方法。 super()用于在子类中调用父类的构造函数。 this关键字 
this关键字用于引用当前对象即调用它的对象。 在一个类的方法中可以使用this.成员名来访问该对象的成员变量或成员方法。 在构造函数中使用this()来调用当前类的其他构造函数用于构造函数重载。 this还可以用于在方法中明确指定当前对象作为参数传递给其他方法或构造函数。 
static的用法 
在Java中static是一个关键字用于描述类的成员字段、方法、块或内部类。下面是static关键字的用法 
Static字段 
声明为静态字段的成员变量在类的所有对象之间共享。 使用类名加点符号例如ClassName.staticFieldName来访问静态字段而不是通过对象实例访问。 Static方法 
声明为静态方法的方法不依赖于对象的实例可以直接通过类名调用。 静态方法不能访问非静态的成员变量或方法因为它们没有隐式的this引用。 Static块 
静态块是类的静态成员之一使用静态块可以在类加载时执行一段代码。 静态块在类的第一次被加载时执行只执行一次。 静态块通常用于初始化静态字段或执行其他需要在类加载时进行的静态操作。 Static内部类 
声明为静态内部类的内部类可以独立于外部类的对象存在无需依赖外部类的实例。 静态内部类不能直接访问外部类的非静态成员但可以访问外部类的静态成员。 总结 
static关键字用于描述类的成员使其与类本身相关联而不是与类的实例相关联。 静态字段和静态方法在类的所有对象之间共享可以直接使用类名访问。 静态块在类加载时执行一次用于执行静态操作。 静态内部类可以独立于外部类的对象存在但不能直接访问外部类的非静态成员。 
抽象类和接口 
你刚说的ConcurrentHashMap是如何保证线程安全的呢 
ConcurrentHashMap 是 Java 中的一个线程安全的哈希表实现。它采用了一种称为锁分段lock striping的机制来保证线程安全性。 
具体来说ConcurrentHashMap 内部维护了一个由多个独立的锁组成的锁数组。当需要进行读写操作时首先会根据键的哈希值确定要操作的段segment然后只对该段加锁而其他段的数据不会被阻塞。这样多个线程可以同时操作不同的段提高了并发性能。 
每个段都类似于一个小的哈希表具有自己的哈希桶数组。当执行插入、删除或更新操作时只需要锁定对应段的锁。而对于读操作由于 ConcurrentHashMap 的读取方法是线程安全的可以无锁地同时进行。 
通过细粒度的锁分段ConcurrentHashMap 在保证线程安全的同时允许并发地读取数据提高了并发性能。而传统的 Hashtable 和同步化的 HashMap 则使用单个全局锁会导致并发性能较差。 
总结起来ConcurrentHashMap 通过锁分段的机制在保证线程安全的同时提高了并发性能使多个线程能够同时读取不同段的数据从而提高了效率 
深拷贝与浅拷贝 
Java中的深拷贝deep copy和浅拷贝shallow copy涉及到对对象的复制操作。 
浅拷贝是指创建一个新对象新对象的成员变量是原对象的引用也就是说新对象和原对象共享同一份数据。因此当通过浅拷贝修改新对象的成员变量时原对象的对应成员变量也会被修改。在Java中可以使用clone()方法实现浅拷贝。 
class Person implements Cloneable {private String name;public Person(String name) {this.name  name;}public String getName() {return name;}public void setName(String name) {this.name  name;}public Person clone() throws CloneNotSupportedException {return (Person) super.clone();}
}使用浅拷贝的示例 
Person person1  new Person(Alice);
Person person2  person1.clone();System.out.println(person1.getName()); // 输出Alice
System.out.println(person2.getName()); // 输出Aliceperson2.setName(Bob);System.out.println(person1.getName()); // 输出Bob原对象的成员变量被修改
System.out.println(person2.getName()); // 输出Bob深拷贝是指创建一个新对象新对象的成员变量和原对象的成员变量完全相同但是存储在不同的内存地址中。这样在通过深拷贝修改新对象的成员变量时原对象的对应成员变量不会受到影响。在Java中可以通过序列化和反序列化实现深拷贝。 
import java.io.*;class Person implements Serializable {private String name;public Person(String name) {this.name  name;}public String getName() {return name;}public void setName(String name) {this.name  name;}public Person deepCopy() throws IOException, ClassNotFoundException {ByteArrayOutputStream baos  new ByteArrayOutputStream();ObjectOutputStream oos  new ObjectOutputStream(baos);oos.writeObject(this);ByteArrayInputStream bais  new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois  new ObjectInputStream(bais);return (Person) ois.readObject();}
}使用深拷贝的示例 
Person person1  new Person(Alice);
Person person2  person1.deepCopy();System.out.println(person1.getName()); // 输出Alice
System.out.println(person2.getName()); // 输出Aliceperson2.setName(Bob);System.out.println(person1.getName()); // 输出Alice原对象的成员变量不受影响
System.out.println(person2.getName()); // 输出Bob需要注意的是为了使对象能够被序列化需要实现Serializable接口并且对象的所有引用类型成员变量也需要实现Serializable接口。 
数据库的索引有哪些都有什么区别 
数据库的索引是用于提高查询性能的数据结构。常见的数据库索引包括 
B树索引B树或者是B树索引是最常用的索引类型。它适用于磁盘存储具有平衡性和高效的查找性能。B树索引可以用于等值查询、范围查询和排序操作。 
CREATE INDEX idx_student_id ON students (student_id);
SELECT * FROM students ORDER BY student_id;
SELECT * FROM students WHERE student_id BETWEEN 10000 AND 20000;
DROP INDEX idx_student_id ON students;哈希索引哈希索引使用哈希函数将索引列的值映射到哈希表中的桶。哈希索引适用于等值查询但不适合范围查询和排序操作。它通常具有快速的查找速度但对于范围查询和模糊查询效果不佳。 
CREATE INDEX idx_student_id ON students USING HASH (student_id);
DROP INDEX idx_student_id ON students;全文索引全文索引用于对文本数据进行全文搜索例如文章、博客等。它可以根据文本的内容进行关键词搜索而不仅仅是精确匹配。全文索引使用特殊的数据结构来支持高效的文本搜索操作。 
CREATE FULLTEXT INDEX idx_content ON articles (content);
SELECT * FROM articles WHERE MATCH(content) AGAINST(keyword);
ALTER TABLE articles DROP INDEX idx_content;唯一索引唯一索引用于保证索引列的唯一性。它可以防止重复值的插入并提供快速的唯一性检查。唯一索引通常用于主键和唯一约束。 
CREATE UNIQUE INDEX idx_email ON users (email);
ALTER TABLE users DROP INDEX idx_email;数据库的内、外链接的区别 
在数据库中内连接Inner Join和外连接Outer Join是两种常见的表链接操作它们的区别如下 
内连接Inner Join 内连接返回两个表中满足连接条件的记录集合。只有在连接条件成立时才会返回相应的行。 例如如果有两个表A和B内连接可以使用如下语法进行操作 Plain Text
Copy code
SELECT * 
FROM tableA
INNER JOIN tableB 
ON tableA.column  tableB.column;
内连接返回的结果集将仅包含在表A和表B之间存在匹配关系的行。外连接Outer Join 外连接返回两个表中满足连接条件的记录以及不满足连接条件的记录。如果没有匹配的行外连接会在结果中填充空值NULL。 外连接可以分为左外连接Left Outer Join、右外连接Right Outer Join和完全外连接Full Outer Join 
左外连接Left Outer Join 返回左表中的所有记录以及右表中匹配的记录。 
Plain Text
Copy code
SELECT * 
FROM tableA
LEFT OUTER JOIN tableB 
ON tableA.column  tableB.column;结果集将包含在表A中的所有行以及与之匹配的表B中的行如果没有匹配的行则右表中的字段将包含空值。 
右外连接Right Outer Join 返回右表中的所有记录以及左表中匹配的记录。 
SELECT * 
FROM tableA
RIGHT OUTER JOIN tableB 
ON tableA.column  tableB.column;结果集将包含在表B中的所有行以及与之匹配的表A中的行如果没有匹配的行则左表中的字段将包含空值。 
完全外连接Full Outer Join 返回两个表中的所有记录无论是否匹配。 
SELECT * 
FROM tableA
FULL OUTER JOIN tableB 
ON tableA.column  tableB.column;结果集将包含表A和表B中的所有行如果没有匹配的行则对应表的字段将包含空值。 
如何在10000个数中查找一个数 
使用哈希表可以将这10000个数构建成一个哈希表其中数值作为键(key)数值对应的索引位置作为值(value)。构建哈希表的时间复杂度为O(n)其中n为数组的大小。然后可以通过在哈希表中查找给定数值的键来找到该数值在原始数组中的索引位置。哈希表的查找时间复杂度为O(1)因此总体时间复杂度为O(n)。 
Thread和Runnbale的区别 
Thread和Runnable是Java多线程编程中两种常用的并发机制它们之间有以下区别 
继承关系 ThreadThread是一个类它直接继承自Java的java.lang.Thread类。通过继承Thread类可以创建一个可直接运行的线程对象。 RunnableRunnable是一个接口定义在java.lang.Runnable中。通过实现Runnable接口可以将一个类声明为线程任务并创建一个Thread对象来执行该任务。 扩展性 Thread由于Java类的单继承特性当一个类继承了Thread类后就无法再继承其他类。如果有其他类需要被继承使用Thread类就会有限制。 Runnable实现Runnable接口不会有继承上的限制因为Java允许一个类实现多个接口因此使用Runnable接口更加灵活可以应对多种场景。 资源消耗 Thread每个Thread对象在运行时都会占用一定的系统资源包括内存和CPU资源。如果需要创建大量的线程可能会造成资源消耗过大的问题。 Runnable相比之下Runnable对象的资源消耗较少因为它是作为任务被线程执行而不是单独的线程对象。因此在需要创建大量线程的情况下使用Runnable更为轻量。 代码结构 Thread通过继承Thread类线程的逻辑代码与线程对象本身的状态信息混在一起可能导致代码的可读性和维护性下降。 Runnable实现Runnable接口使得线程的逻辑与线程对象的状态信息分离使代码更加清晰、易读、易于扩展。 综上所述Runnable接口相对更加灵活、轻量并且有利于代码的可读性和维护性因此在多线程编程中推荐使用Runnable接口来实现线 
hashmap线程安全有哪些线程安全的集合 
哈希表在一般情况下是不线程安全的因为多个线程同时对哈希表进行写操作可能会导致数据不一致或者其他异常情况的发生。然而许多编程语言和框架提供了线程安全的集合类用于解决多线程环境下的并发访问问题。 
ConcurrentHashMap线程安全的哈希表实现支持高并发读写操作。 
ConcurrentHashMapString, Integer map  new ConcurrentHashMap();CopyOnWriteArrayList线程安全的动态数组适用于读操作频繁、写操作较少的场景。 
CopyOnWriteArraySet线程安全的集合基于CopyOnWriteArrayList实现适用于读操作频繁、写操作较少的场景。 
ConcurrentLinkedQueue线程安全的无界队列基于链表实现支持高并发读写操作。 
ConcurrentSkipListMap线程安全的跳表实现的有序映射支持高并发读写操作。 
ConcurrentSkipListSet线程安全的跳表实现的有序集合支持高并发读写操作。 
BlockingQueue提供了一系列阻塞操作的线程安全队列常用的实现包括ArrayBlockingQueue、LinkedBlockingQueue等。 BlockingQueue是Java中用于实现生产者-消费者模式的线程安全队列。它提供了一些阻塞方法可以在队列满或空的情况下暂停线程的执行。 
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;public class ProducerConsumerExample {private static final int QUEUE_CAPACITY  5;public static void main(String[] args) throws InterruptedException {// 创建一个固定容量的BlockingQueueBlockingQueueInteger queue  new ArrayBlockingQueue(QUEUE_CAPACITY);// 创建生产者线程和消费者线程Thread producerThread  new Thread(new Producer(queue));Thread consumerThread  new Thread(new Consumer(queue));// 启动线程producerThread.start();consumerThread.start();// 等待一段时间后停止生产者线程Thread.sleep(5000);producerThread.interrupt();}// 生产者线程static class Producer implements Runnable {private BlockingQueueInteger queue;public Producer(BlockingQueueInteger queue) {this.queue  queue;}Overridepublic void run() {try {int i  0;while (true) {// 向队列中放入元素queue.put(i);System.out.println(Producer produced:   i);i;Thread.sleep(1000);}} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}// 消费者线程static class Consumer implements Runnable {private BlockingQueueInteger queue;public Consumer(BlockingQueueInteger queue) {this.queue  queue;}Overridepublic void run() {try {while (true) {// 从队列中取出元素int number  queue.take();System.out.println(Consumer consumed:   number);Thread.sleep(2000);}} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}
}git中commit和push的区别 
java的锁机制 
Synchronized关键字可以用于修饰方法或代码块实现对对象的互斥访问。当线程进入synchronized修饰的方法或代码块时会自动获取对象的锁其他线程需要等待前一个线程释放锁才能执行。 
当一个线程进入被synchronized修饰的方法时会自动获取该方法所属对象的锁。其他线程需要等待当前线程释放锁才能执行该方法。 
public synchronized void method() {// 代码块
}使用synchronized修饰的代码块需要一个锁对象可以是任意对象。当线程执行到synchronized代码块时会尝试获取该锁对象的锁其他线程也需要等待当前线程释放锁才能执行代码块。 
public void method() {synchronized (obj) {// 代码块}
}ReentrantLock类是Java提供的可重入锁实现。与synchronized相比ReentrantLock提供了更高级的特性如可中断锁、公平性、条件变量等。使用ReentrantLock需要手动调用lock()方法获取锁并在合适的时候调用unlock()方法释放锁。 
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockDemo {private static ReentrantLock lock  new ReentrantLock();public static void main(String[] args) {Thread thread1  new Thread(new Worker());Thread thread2  new Thread(new Worker());thread1.start();thread2.start();}private static class Worker implements Runnable {Overridepublic void run() {try {lock.lock(); // 获取锁System.out.println(线程   Thread.currentThread().getName()   获取了锁);Thread.sleep(1000); // 模拟执行一些操作} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock(); // 释放锁System.out.println(线程   Thread.currentThread().getName()   释放了锁);}}}
}在上述示例中ReentrantLock对象lock被创建并且在run()方法中通过lock.lock()获取锁在执行需要同步的代码块时其他线程无法获取该锁。在代码块执行完毕后通过lock.unlock()释放锁。这样可以确保同一时刻只有一个线程执行代码块实现了同步访问。 
需要注意的是在使用ReentrantLock时需要显式地获取和释放锁在获取锁之后一定要确保最终会释放锁可以使用finally块来保证。另外ReentrantLock还提供了其他功能如可重入性、公平锁等可以根据需要进行配置和使用。 
ReentrantLock类相比于synchronized关键字提供了更多的灵活性和控制权但使用时需要更加小心确保正确地获取和释放锁避免死锁等问题。 
ReadWriteLock接口是Java并发包中的一种锁机制提供了读写分离的功能。它允许多个线程同时对一个共享资源进行读操作但只允许一个线程进行写操作。ReadWriteLock接口的实现类ReentrantReadWriteLock提供了对应的实现。 
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockDemo {private static ReadWriteLock lock  new ReentrantReadWriteLock();private static int sharedData  0;public static void main(String[] args) {Thread thread1  new Thread(new Reader());Thread thread2  new Thread(new Reader());Thread thread3  new Thread(new Writer());thread1.start();thread2.start();thread3.start();}private static class Reader implements Runnable {Overridepublic void run() {lock.readLock().lock(); // 获取读锁try {System.out.println(线程   Thread.currentThread().getName()   读取 sharedData  sharedData);} finally {lock.readLock().unlock(); // 释放读锁}}}private static class Writer implements Runnable {Overridepublic void run() {lock.writeLock().lock(); // 获取写锁try {sharedData  1;System.out.println(线程   Thread.currentThread().getName()   写入 sharedData  sharedData);} finally {lock.writeLock().unlock(); // 释放写锁}}}
}在上述示例中ReadWriteLock对象lock被创建并且在读操作和写操作中分别通过lock.readLock()和lock.writeLock()获取读锁和写锁。读锁可以被多个线程同时持有但写锁只能被一个线程独占。读锁和写锁的互斥性由实现类来保证。 
在Reader的run()方法中首先通过lock.readLock().lock()获取读锁然后执行读操作最后通过lock.readLock().unlock()释放读锁。在Writer的run()方法中也是类似的流程首先获取写锁执行写操作最后释放写锁。 
使用ReadWriteLock接口可以优化读多写少的场景多个线程可以并发地读取共享数据但在写操作时需要独占访问。这样可以提高并发性能和资源利用率。 
需要注意的是在使用ReadWriteLock时需要根据实际情况选择获取读锁还是写锁并确保最终会释放锁可以使用finally块来保证。此外ReadWriteLock还提供了其他功能如可重入性、读写分离等可以根据需要进行配置和使用。 
Condition接口与Lock配合使用可以实现更灵活的线程间通信。一个Lock对象可以关联多个Condition对象线程可以通过Condition对象的await()方法释放锁并等待条件满足然后通过signal()或signalAll()方法唤醒等待的线程。 
数据库怎么提高查询效率 
1️⃣ 编写优化的查询语句确保查询语句使用适当的索引避免全表扫描和不必要的连接操作。 
2️⃣ 使用合适的索引为经常被用作查询条件的列创建索引可以显著加快查询速度。 
3️⃣ 优化表结构避免冗余数据和重复列合理拆分和规范化表以减少数据量和提高查询效率。 
4️⃣ 配置合理的缓存通过适当调整MySQL的缓存参数如查询缓存(Query Cache)、键值缓存(Key-Value Cache)可以减少IO操作提高查询效率。 
5️⃣ 使用分区表对于大型表可以将其分成多个分区以减少扫描范围和提高查询性能。 
6️⃣ 调整连接池和线程池根据并发连接和线程的需求适当调整连接池和线程池的大小以避免资源浪费和性能下降。 
7️⃣ 定期优化和维护数据库定期进行数据库优化如清理无用的索引和调整表结构可以保持数据库的良好性能。 
Linuxhead和显示文档的前10行 
head -n 10 example.txt什么时候应该建索引什么时候不应该建索引 
建立索引是为了提高数据库查询性能但并不是在所有情况下都需要建立索引。下面是一些应该建立索引和不应该建立索引的情况 
应该建立索引的情况 
频繁用作检索条件的列如果某个列经常用于查询的WHERE子句、JOIN操作或排序操作中建立索引可以显著加快查询速度。 外键列对于外键列建立索引可以提高表关联查询的性能。 经常用于连接操作的列如果有很多表需要连接并且某个列常用于连接操作的条件建立索引可以加速连接操作。 给字段添加唯一约束对于需要保证唯一性的列建立唯一索引可以确保数据完整性并提高查询效率。 大表中的关键字段对于包含大量数据的表可以建立索引来加速对关键字段的查询提高性能。 不应该建立索引的情况 
数据量小的表对于小型表建立索引可能会带来不必要的开销因为查询整个表可能比使用索引更快速。 频繁进行增删改操作的列对于频繁修改的列建立索引会增加额外的维护成本并且可能降低性能。 列的基数唯一值的数量很低如果一列的唯一值很少例如布尔类型或只有几种取值的列建立索引可能不会有明显的性能提升反而增加了存储开销。 在决定是否建立索引时需要综合考虑数据库的使用模式、查询频率、数据量等因素并进行权衡取舍。此外建立索引也并非一劳永逸随着数据的变化和查询模式的改变索引可能需要进行调整和 
Linux用端口号查看进程 
sudo lsof -i :端口号 
Linux查找重复单词出现次数 
要查找文本文件中重复单词的出现次数你可以使用grep命令结合正则表达式和sort命令。下面是一个示例命令 
grep -oE \w 文件名 | sort | uniq -c | sort -nr
将文件名替换为你要查找的实际文件名。执行上述命令后它会按照出现次数从高到低的顺序列出重复单词以及它们的出现次数。这里是每个命令的作用grep -oE \w 文件名匹配文本文件中的单词并输出到下一步处理。
sort按照字母顺序对单词进行排序。
uniq -c统计相同的单词出现的次数。
sort -nr按照出现次数从高到低的顺序进行排序。linux常用命令 
ls列出目录下的文件和子目录。  
cd切换当前工作目录。  
mkdir创建一个新的目录。  
rm删除一个文件或目录。  
cp复制一个文件或目录。 cp file1 file2将file1复制到file2。   cp -r dir1 dir2将dir1目录及其内容递归地复制到dir2。   cp -i file1 dir1将file1复制到dir1如果dir1目录下已存在同名文件则提示用户选择是否覆盖。   cp -a dir1 dir2将dir1目录及其内容递归地复制到dir2并保留所有文件属性包括权限、时间戳等。  cp -v file1 dir1将file1复制到dir1并显示每个成功复制的文件名。  
mv移动一个文件或目录或者更改它的名称。 相当于剪切 
mv file1 file2将file1重命名为file2。
mv file1 dir1将file1移动到dir1目录下同时保留原始文件名。
mv -i file1 dir1将file1移动到dir1目录下如果dir1目录下已存在同名文件则提示用户选择是否覆盖。
mv dir1 dir2将dir1目录重命名为dir2。
mv -v file1 dir1将file1移动到dir1目录下并显示每个成功移动的文件名。cat连接文件并打印到标准输出设备上。  
grep在文件中查找指定的字符串。 
在文件中查找指定字符串  在指定目录及其子目录下找寻指定字符串  
find在文件系统中查找文件。 chmod修改文件或目录的权限。 使用格式为 
chmod [选项] 模式 文件名模式由三个数字组成分别表示所有者权限群组权限及其他用户权限。 
数字描述0没有权限1执行权限2写权限3写和执行权限4读权限5读和执行权限6读和写权限7读、写和执行权限 
如下图修改X1.txt的访问权限。  
chown修改文件或目录的所有者。 
ps列出系统中运行的进程。 
ps auxtop实时显示系统中进程的资源占用情况。 如下图直接输入top即可 ping测试与另一台计算机之间的网络连接。 
ssh远程登录到另一台计算机。 
scp在本地和远程计算机之间复制文件。 
tar将多个文件和目录打包成单个文件可以进行压缩。 将多个文件归档 
tar -cf 归档文件名 文件名在已有归档里添加新文件 
tar -rf 归档文件名 添加文件名查看归档文件中的文件列表 
tar -tf 归档文件名zip: 压缩文件或目录 
zip zipfile.zip file1.txt file2.txt directory1/unzip解压缩zip文件。 
df显示磁盘空间使用情况。 
du显示目录或文件的大小。 
tail: 查看日志  less: 分页查看日志或搜索日志 less是一个Linux中非常有用的命令它可以让用户在终端中查看文件内容支持向前/向后翻页、跳转、搜索等操作。下面介绍一些less的常见使用方法 
查看文件less filename 这个命令会在终端中打印出filename文件的内容并且允许你向上/向下翻页。  
向前/向后翻页空格键(向前翻页)和b键(向后翻页) 按下空格键或b键可以向前/向后翻一页。 
跳转到文件开始或结束处g键或G键 按下g键将跳转到文件的开始处按下G键将跳转到文件的结尾处。 
跳转到特定行输入行号回车键 在less中输入一个数字并按下回车键将跳转到该行。 
搜索文本输入/  匹配模式  回车键 在less中输入/加上想要搜索的模式并按下回车键将进行文本搜索。 
退出lessq键 在less中按下q键可以直接退出该程序。 
这些是less的一些常用命令其他的命令可以通过输入h获取帮助信息来学习。 
在Linux中查询日志的命令主要有以下几种 
tail 命令用于从文件末尾开始显示文件内容。可以使用 -f 参数实时查看日志文件的更新。 
例如tail -f /var/log/messages 
grep 命令用于在文件中搜索指定的字符串。可以配合 tail 命令一起使用以过滤显示特定内容。 
例如tail -f /var/log/messages | grep “error” 
cat 命令用于将文件内容输出到标准输出设备可以用于显示日志文件的全部内容。 
例如cat /var/log/messages 
less 命令用于浏览文件内容可以在文件中进行搜索和翻页操作。 
例如less /var/log/messages 
journalctl 命令用于查看系统日志systemd-journald产生的日志可以根据各种条件进行过滤和搜索。 
例如journalctl -u nginx.service 可以显示与 Nginx 服务相关的日志。 
这些命令只是查询日志的一些基本方法实际上还可以根据不同的需求和具体情况使用其他工具和方法进行日志查询。 
linux如何查看线程状态 
在Linux上你可以使用以下命令来查看线程状态 
ps命令使用ps -eLf命令可以列出当前系统中所有线程的详细信息包括线程ID、父进程ID、CPU占用情况等。你可以通过查看STAT列来获取线程的状态。 
shell Copy code ps -eLf top命令在终端中输入top命令然后按下键盘上的Shift  H可以查看当前系统中所有线程的详细信息包括线程ID、CPU占用情况、内存使用情况等。 
shell Copy code top 
Linux查看进程和端口号 
查看进程使用ps命令可以列出当前系统中运行的进程。常用的选项包括 ps aux显示所有用户的所有进程。 ps -ef显示用户进程树。 ps -e --forest以树状结构显示所有进程。 例如要查看所有用户的所有进程可以运行以下命令 ps aux 查看端口号 使用netstat命令可以查看网络连接、路由表和网络接口等信息。常用的选项包括 
netstat -tuln显示当前网络中所有的TCP和UDP端口号。 netstat -tuln | grep 端口号根据端口号过滤结果。 例如要查看当前监听的TCP和UDP端口号可以运行以下命令 
netstat -tuln 如果你只对某个特定的端口号感兴趣可以使用grep命令进行过滤。例如要查看端口号为8080的进程可以运行以下命令 
netstat -tuln | grep 8080 以上命令将显示监听端口号为8080的进程信息包括进程ID和进程名。 
另外你也可以使用lsof命令来查看特定端口的进程信息。例如要查看端口号为8080的进程信息可以运行以下命令 
lsof -i :8080 以上命令将显示占用端口号8080的进程信息包括进程ID和进程名。 HTTP请求过程  状态码  四次挥手  
Java多线程实现方式 
线程池有几种 
1️⃣ 手动实现线程池这是一种自己从头开始编写线程池的方式。你可以使用编程语言提供的基本线程和同步机制如锁、条件变量等来实现线程池的创建、任务队列管理、线程调度等功能。 
2️⃣ 使用语言提供的线程池库许多编程语言都提供了内置的线程池库你可以直接使用这些库来创建和管理线程池。例如Java 中的java.util.concurrent包提供了ThreadPoolExecutor类C# 中的System.Threading命名空间提供了ThreadPool类等。 
3️⃣ 使用第三方库有许多第三方库可以帮助你实现线程池这些库提供了更高级的功能和更易于使用的接口。例如Java 中常用的线程池库有Apache Commons Pool、Google Guava等。