面试记录
1.面向对象和面向过程的区别,面向对象的三个特性,并解释。
面向过程就是分析出解决问题所需要的步骤,把这些步骤编写成一个一个的函数,然后依次调用这些函数解决掉问题即可;面向对象就是把解决问题的事务分解为各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
面向过程代码复用性不佳(不同过程中相似的代码不好进行复用)、扩展不易、耦合度高,优点是性能比面向对象高,因为类调用需要实例化,开销比较大,比较消耗资源。
面向对象代码复用性佳,耦合性低,逻辑易理解,容易维护。缺点是性能比面向过程低。
多态 封装和继承
封装:封装指的是将数据和相关操作封装在对象内部,提供给外部访问的接口。封装为信息隐藏和保护提供了支持。
多态:多态指的不同类型的对象执行同一种操作可以产生不同的行为和结果。子类可以继承父类的方法并在需要的情况下对某些方法进行重写,提供自己的实现,当通过父类的指针或引用调用不同的子类对象时会根据实际调用对象中实现的方法产生不同的行为。
继承:通过继承关系,可以使现有的类继承父类的所有功能,并且在无需重新编写原来类的情况下对类的功能进行扩展。
2.C++和python的区别
编译型 解释型
C++是一种静态的语言,需要在编译时确定变量类型,代码段用大括号分割,语句结尾用分号,相比较,python是一种动态语言,可以在运行时确定变量类型,采用缩进标志代码块,语句结尾不需要有分号。内存管理:python有垃圾自动回收机制,使用垃圾自动收集器管理内存,c++需要程序员自己管理内存;
c++是编译型语言,python是解释型语言,二者分别为:
编译型语言是一次性地编译成机器码,所以可以脱离开发环境独立运行,而且通常运行效率较高;解释型语言每次执行解释型语言的程序都需要进行一次编译,因此解释型语言的程序运行效率通常较低,而且不能脱离解释器独立运行。但解释型语言有一个优势:跨平台比较容易,只需提供特定平台的解释器即可,每个特定平台上的解释器负责将源程序解释成特定平台的机器指令即可。参考
python是解释执行的,和物理机CPU之间多了解释器这层,而C++是编译执行的,直接就是机器码,编译的时候编译器又可以进行一些优化。因此在运行效率上,C++要远好于python
(解释器就是高级语言的转换器)解释器是一种翻译程序,是一种能够执行用其他计算机语言编写的程序的软件,例如python解释器,
编译和解释的区别:编译会将所有程序代码一次性转换为机器可以执行的指令,而解释是转换一行运行一行,边转换边执行。
3.http和https的区别
http中文名叫超文本传输协议,https中文名叫超文本传输安全协议,工作在应用层,规定了浏览器和服务器之间的通信规范,常采用TCP连接。
(1)前者以明文的方式传输消息,后者https就是http+ssl加密,与http相比能够提供对网站服务器的身份认证,保证数据传输的隐私和完整性。
(2)http协议默认端口号为80,https默认端口号为443。
(3)在具体传输方式与效率方面,http只需要进行三次握手与服务端进行连接即可发送数据,客户端和服务端之间总共交换3个包,而https除了TCP连接的三次握手还有ssl的9个包。
(4)https就是建立在ssl/tsl加密协议上的http,因此比https更消耗服务器资源
下图是https加密的工作原理
4.http请求的结构体是怎样的,method包括哪些
http请求包括:请求行 首部行(请求报头) 空行和请求正文(消息主体) 四个部分
请求行的内容:请求行包含请求方法,URL和协议版本,中间以空格隔开,URL的作用就是把请求定位到服务端要处理请求的地址,协议版本是HTTP的版本号,请求方法包括get post等。
首部行内容及格式:首部行为请求行增加了一些附加信息,由“名: 值”对组成,名和值之间使用冒号+空格连接。
首部行有以下几种报头:普通报头、请求报头、响应报头、实体报头。这些报头各自具有不同的作用和目的,可以同时使用。
普通报头:可以应用于所有请求和响应消息,且和请求体与响应体无关的信息就存放在普通报头中
- Cache-Control(缓存控制):用于控制缓存的行为。
- Connection(连接):指定是否需要持久连接。
- Date(日期):指定报文创建的日期和时间。
- Pragma(特定实现):用于向后兼容的目的,尽管现在已经很少使用。
- Trailer(尾部):指定在分块传输编码中,尾部分块的报头字段。
- Transfer-Encoding(传输编码):指定报文的传输编码方式。
- Upgrade(升级):用于升级协议的请求。
- Via(经由):指定代理服务器的途径和版本信息。
- Warning(警告):提供关于可能存在的消息问题的警告信息
请求报头:客户端向服务端传递请求的附加信息以及客户端自身的信息存放在请求报头中
- Accept(接受类型):指定客户端能够处理的媒体类型。
- Accept-Encoding(接受编码):指定客户端能够接受的内容编码方式。
- Accept-Language(接受语言):指定客户端能够理解的自然语言。
- Authorization(授权信息):用于进行身份验证的凭证。
- Cookie(Cookie数据):包含之前由服务器通过Set-Cookie设置的Cookie值。
- Host(主机):指定请求的目标服务器的域名或IP地址。
- Referer(引用页面):指定当前请求的来源页面的URL。
- User-Agent(用户代理):包含发送请求的用户代理应用程序的信息
响应报头:是http响应中的一种报头,用于传递响应相关的信息给客户端。响应报头描述了服务器返回的响应的属性和元数据。
- Content-Type(内容类型):指定响应主体的媒体类型。
- Content-Encoding(内容编码):指定响应主体的内容编码方式。
- Content-Length(内容长度):指定响应主体的字节数。
- Location(重定向位置):用于重定向请求的URL地址。
- Server(服务器):指定响应的服务器软件信息。
- Set-Cookie(设置Cookie):在响应中设置Cookie值。
- Cache-Control(缓存控制):用于控制缓存的行为。
- Expires(过期时间):指定响应的过期时间。
实体报头:是http请求和响应中的一种报头,用于描述请求或响应中的实体(请求的资源或响应的数据)的相关信息。
- Content-Type(内容类型):指定请求或响应主体的媒体类型。
- Content-Encoding(内容编码):指定请求或响应主体的内容编码方式。
- Content-Length(内容长度):指定请求或响应主体的字节数。
- Content-Language(内容语言):指定请求或响应主体的自然语言。
- Content-Disposition(内容处理方式):指定请求或响应主体的处理方式。
- ETag(实体标识):指定请求或响应主体的实体标识符。
- Last-Modified(最后修改时间):指定请求或响应主体的最后修改时间。
- Expires(过期时间):指定请求或响应主体的过期时间。
在一个完整的Http请求和响应过程中,可以同时包含这些报头类型。普通报头通常在请求和响应的起始行之后,在请求报头或响应报头之前。请求报头和响应报头用于传递请求和响应的特定属性和要求,而实体报头用于描述请求或响应中的实体的相关信息。
空行是位于首部行和请求正文中间的,标志着首部行的结束。
请求正文:一般用于http的post方法,通过实体报头规定消息主体的格式和内容。
以下为http请求报文结构:
以下为http响应报文结构:状态行、响应头、空行、响应正文
状态行包括协议版本、状态码和原因短语
响应头包括搭建服务器的软件、发送响应的时间、响应数据的格式等信息
响应正文就是响应的数据
5.说一下知道的排序算法以及他们的复杂度和稳定性,描述一下快速排序,快速排序可能存在什么问题,怎么改进。
快速排序算法可能存在的问题:1.时间复杂度不稳定,由于分割点的选取是随机的,可能每次都只有一小段,这种情况下复杂度可能退化到O(n2),甚至数据量更大一些由于硬件条件的限 制可能快排无法处理
2.空间复杂度较高,快排需要一个递归栈来维护递归的过程,如果待排序数组很长,那么递归栈需要的空间可能会随之增加,导致空间复杂度很高
3.不稳定
6.某个项目中登录功能是怎么实现的
7.递归和for循环哪个效率更高
for循环效率高。递归涉及到在栈中分配空间来保存参数、返回的地址和临时变量,向栈中压入数据和弹出数据都会花费时间,并且如果递归的层数太深还可能出现栈溢出。此外,递归会涉及到大量重复计算,影响性能。
8.链表与数组的区别
存储结构:数组在内存中连续,使用数组前要事先规定数组大小,数组元素实际被存储在堆中,但其引用变量存储在栈中;链表在堆上分配内存,采用动态内存分配的方式,支持动态增加和删除元素,需要注意内存泄漏。
访问效率方面:数组在内存中顺序存储,可以通过下标访问,访问效率高;链表在内存中不连续,只能通过遍历来访问,访问效率低。
插入和删除:数组插入和删除需要移动相应节点后的所有元素,链表的插入删除非常简单,不需要移动节点,只需要改变相关节点中的后继节点指针即可,和节点实际存储位置无关。
9.sleep wait join yield 哪个方法会释放锁?-->wait join, join底层调用了wait. wait会使当前线程回到线程池中等待,释放锁,当被其他线程使用notify,notifyAll唤醒时进入可执行状态
线程有五种状态:新建new,就绪runnable,运行runing,阻塞blocked,死亡dead
阻塞状态是指 线程因为某种原因需要放弃CPU使用权,暂停或运行,阻塞时,线程不能进入排序队列,只有当阻塞的原因消除后,线程才转化为就绪状态并转入就绪队列中等待,当再次获得时间片后从上次中止的地方继续运行。从阻塞状态只能进入到就绪状态。
线程阻塞的原因有三大类:1.A线程需要锁,但该锁被其他线程占用,A线程进入到等待锁的阻塞队列,这种情况只有当某个线程释放该锁的时候才能唤醒A线程,notify不会唤醒该线程;
2.正在占用锁的线程调用了wait()方法,就会进入wait阻塞队列,只有obj.notify()通知该线程后,才会唤醒这个队列中的线程,普通的释放锁操作不能唤醒该线程;
3.正在执行中的线程调用了join() sleep()或IO就会进入另一个线程阻塞队列,睡眠时间到或者IO结束,线程才会继续进入到就绪状态。join()作用是阻塞主线程。当线程调用另外一个线程的join方法时,当前线程就会进入阻塞状态。直到另外一个线程执行完毕,当前线程才会由阻塞状态转为就绪状态。sleep方法不释放锁。
yield方法,会使当前线程放弃使用CPU时间片,把机会让给相同或者具有更高优先级的线程。但是当前线程不会阻塞,而是直接进入就绪状态,随时获得CPU时间片后再次执行。可以看出yield方法是不释放锁资源的。