考研中文面试专业问题

考研中文面试专业问题

堆与栈区别

栈是一个先进后出的数据结构,后进先出,一般由系统自动分配,存放存放函数的参数值,局部变量等,自动清除。每个函数进入的时候分一小块,函数返回的时候就释放了。存放的变量生命周期一旦结束就会被释放。变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。

堆是一个可动态申请的内存空间,存放静态和全局变量,new 变量。存储的是实体,实体用于封装数据,如果数据消失,这个实体没有消失,还可以用,堆不会随时释放的,堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。所有使用new构造出来的对象都在堆中存储,其内存中的数据是无序的,释放时也可以没有先后顺序。

JAVA虚拟机

虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

解释字节码,跨平台,性能低

为什么B+树比B树更适合做系统的数据库索引和文件索引

  1. B+树的磁盘读写代价更低因为B+树内部结点没有指向关键字具体信息的指针,内部结点相对B树小

  2. B+树的查询更加稳定因为非终端结点并不是指向文件内容的结点,仅仅是作为叶子结点的关键字索引,因此所有的关键字查询都会走一条从根节点到叶子结点的路径。即s所有关键字查询的长度是一样的,查询效率稳定。

B树的作用

B树是一种查找树,目的都是为了解决某种系统中,查找效率低的问题。二叉查找树的特点是每个非叶节点都只有两个孩子节点。然而这种做法会导致当数据量非常大时,二叉查找树的深度过深,搜索算法自根节点向下搜索时,需要访问的节点也就变的相当多。随着树高度的增加,频繁的I/O操作一定会降低查询的效率。对于外存储器的信息读取最大的时间消耗在于寻找磁盘页面。那么一个基本的想法就是能不能减少这种读取的次数,在一个磁盘页面上,多存储一些索引信息。B树的基本逻辑就是这个思路,它要改二叉为多叉,每个节点存储更多的指针信息,以降低I/O操作数。

B树和B+树区别

  1. B+树中只有叶子节点会带有指向记录的指针(ROWID),而B树则所有节点都带有,在内部节点出现的索引项不会再出现在叶子节点中。

  2. B+树中所有叶子节点都是通过指针连接在一起,而B树不会。

异常的作用

提高了程序的健壮性,更好的容错,更好的防止程序崩溃,易于调试。运行时异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

OSI/TCP/IP

OSI模型核心:

服务:定义指明了该层该做什么,而不是上一层的实体如何访问这一层,或者这一层是如何工作的。

接口:定义它上层的进程如何访问该层。

协议:对等协议定义了它内部的事情。

共同点:

都以分层协议栈的概念为基础,协议栈中的协议彼此相互独立。

传输层以及传输层以上的各层都为希望进行通信的进程提供了一种端到端的,与网络无关的服务。

区别OSI模型有7层,TCP/IP只有4层。

无连接的和面向对象的通信范围有所不同,OSI模型的网络层同时支持无连接的和面向连接的通信,但是传输层只支持面向连接的通信。TCP/IP模型的网络层上只有一种模式:无连接模式,但是在传输层上同时支持两种通信模式。

OSI参考模型是在协议发明之前已经产生的,TCP/IP是在在协议出现之后出现的,而且它只是已有协议的一个描述而已。

什么是静态链表

对于没有指针的编程语言,可以用数组替代指针,来描述链表。让数组的每个元素由data和cur两部分组成,其中cur相当于链表的next指针,这种用数组描述的链表叫做静态链表,这种描述方法叫做游标实现法。

文件系统实现

目录实现方法是使用存储文件名和数据块指针的线性表。创建新文件时,必须首先搜索目录表以确定没有同名的文件存在,然后在目录表后增加一个目录项。哈希表根据文件名得到一个值,并返回一个指向线性列表中元素的指针。

文件分配对应于文件的物理结构,是指如何为文件分配磁盘块。常用的磁盘空间分配方式有三种:连续分配、链接分配和索引分配。

静态与动态区别

static全局变量与普通全局变量的区别

这两者在存储方式上没有区别,是静态存储方式。

区别在于

非静态全局变量的作用域是整个源程序,当一个源程序是由多个源文件组成时,声明的非静态全局变量在每个源文件中都是有效的。

而静态全局变量则限制了其作用域,只在其声明的源文件中有效,在同一源程序中不能使用它。

局部变量与静态变量的区别

  1. 存储位置

    动态变量:存储在内存出栈数据区
    静态变量:存储在全局数据区(静态数据区)

  2. 生命期

    动态变量:超出范围变量将失效
    静态变量:程序结束时才释放,静态变量只在程序中初始化一次,在调用时下一次依据上一次的值。

  3. 作用域

    动态变量:超出范围变量将失效
    静态变量:当前文件中有效静态static函数与普通函数的区别static函数在内存中只存在一份,普通函数在每个被调用中维护一份复制品。

强类型和弱类型的区别

强类型定义语言:强制数据类型定义的语言,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了。

弱类型定义语言:数据类型可以被忽略的语言。它与强类型定义语言相反, 一个变量可以赋不同数据类型的值。

多态

多态是同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。

就是用基类的引用指向子类的对象。

High cohesion low coupling

为什么

代码的复用,还可以解决项目中紧偶合的问题,提高程序的可扩展性,通过对系统的分析把他分解成一个一个子模块,子模块提供稳定的接口,达到降低系统耦合度的的目的,模块模块之间尽量使用模块接口访问,而不是随意引用其他模块的成员变量。

好处

应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。

派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。

异常和错误区别

异常:在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发人员)已经犯了个错误,现在有一个机会来修改它。Java中使用异常类来表示异常,不同的异常类代表了不同的异常。但是在Java中所有的异常都有一个基类,叫做Exception。

错误:它指的是一个合理的应用程序不能截获的严重的问题。大多数都是反常的情况。错误是VM的一个故障(虽然它可以是任何系统级的服务)。所以,错误是很难处理的,一般的开发人员是无法处理这些错误的。比如内存溢出;和异常一样,在Java中用错误类来表示错误,不同的错误类代表了不同的错误。在Java中所有的错误都有一个基类,叫做Error。

综上,我们可以知道异常和错误最本质的区别就是异常能被开发人员处理而错误是系统本来自带的,一般无法处理也不需要我们程序员来处理。

软件工程定义

研究以系统性的、规范化的、可定量的方法去开发运行和维护软件,也就是将工程运用到软件,和对各种方法的研究

软件的生命周期

需求分析、体系结构设计、详细设计、软件构造、软件测试、软件维护

谈谈对软件工程的理解

软件工程就是按照工程学的管理方式,有组织、有计划的,在一定的质量基础、时间限度和成本范围内,实现功能明确的软件系统。软件的核心是人,这是软件工程与传统工程最大的不同,如果说软件的核心是机器,软件工程也不会是如此困难了,因为机器是可度量的,可操控的,就像流水线上的机器,你让它干一整天,它不会说生气不干了,并且每一台机器每天的产量是一样的。但是软件开发是一个创造性的过程,也只有人类拥有创造性思维。所以软件开发绝大部分是受到人为因素影响的,而世界上的每个人又不同,如何物色、管理、运用这些人?让他们发挥其最大的价值?

软件是人类智慧创造的结晶,只可惜它不像传统工程显而易见,当你拿着手机在淘宝上购买商品时,你看到的只是软件UI交互部分,指引你发生购买行为,但是整个过程涉及到的技术以及代码量,你是无法想象到的,就算给你源码看,难度也堪比登天。这也就出现了让我们程序员啼笑皆非的提问“开发一个像淘宝一样的APP需要多少钱?也就是显示商品,然后点击购买。”这一时半会很真的很难评估……因为这里面涉及到太多东西了。所以软件评估量化真的很难,而且实现方法原理都有所不同,这也就说明了软件是高度复杂的。

这也就牵扯到一个问题,软件开发过程中的程序员不能随意更换,否则重新理解阅读软件源码和学习开发框架是有成本风险的,这也是为什么软件工程需要制定规范,撰写文档等等。从某种意义上,软件工程更希望我们像一颗螺丝钉,坏了立马可以更换。

任何新的技术和方法都不会无缘无故出现,都是为了更好的服务于某一种活动。我们熟知的面向对象,敏捷开发等各种方法,各种语言,各种框架,其实都是为了解决软件工程的难题。所以,有时候我们不必盲目崇拜新的技术和方法,这都需要我们进行评估,你不可能用node.js来写CPU密集型的程序吧?如果项目组没人会go语言,我看还是用熟悉的语言吧,不然学习成本和风险太大了。

在给定成本、进度的前提下,开发出具有适用性、有效性、可修改性、可靠性、可理解性、可维护性、可重用性、可移植性、可追踪性、可互操作性和满足用户需求的软件产品。这才是我们需要思考的问题。

TCP三次握手、四次挥手

TCP服务器进程时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;

TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文

TCP服务器收到请求报文后,如果同意连接,则发出确认报文。

TCP客户进程收到确认后,还要向服务器给出确认。

当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。

为什么TCP客户端最后还要发送一次确认呢?

一句话,主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。

如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。

客户端进程发出连接释放报文,并且停止发送数据。

服务器收到连接释放报文,发出确认报文,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。

客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

客户端收到服务器的连接释放报文后,必须发出确认。此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。

为什么客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值

第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。

而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

TCP和IP区别

IP提供基本的数据传送,而高层的TCP对这些数据包做进一步加工,如提供端口号等等。

TCP:又叫传输控制协议(Transmission Control Protocal)是一种面向连接的、端对端的、可靠的、基于IP的传输层协议。

IP:又叫因特网协议(Internet Protocol),IP协议位于网络层,IP协议规定了数据传输时的基本单元(数据包)和格式,IP协议还定义了数据包的递交办法和路由选择。

什么是微服务

微服务架构是一种将单应用程序作为一套小型服务开发的方法

微服务是指开发一个单个小型的但有业务功能的服务,每个服务都有自己的处理和轻量通讯机制,可以部署在单个或多个服务器上。微服务也指一种种松耦合的、有一定的有界上下文的面向服务架构。也就是说,如果每个服务都要同时修改,那么它们就不是微服务,因为它们紧耦合在一起;如果你需要掌握一个服务太多的上下文场景使用条件,那么它就是一个有上下文边界的服务,这个定义来自DDD领域驱动设计。

一组小的服务

服务粒度要小,而每个服务是针对一个单一职责的业务能力的封装,专注做好一件事情。

独立部署运行和扩展

每个服务能够独立被部署并运行在一个进程内。这种运行和部署方式能够赋予系统灵活的代码组织方式和发布节奏,使得快速交付和应对变化成为可能。

独立开发和演化

技术选型灵活,不受遗留系统技术约束。合适的业务问题选择合适的技术可以独立演化。服务与服务之间采取与语言无关的API进行集成。相对单体架构,微服务架构是更面向业务创新的一种架构模式。

独立团队和自治

团队对服务的整个生命周期负责,工作在独立的上下文中,自己决策自己治理,而不需要统一的指挥中心。团队和团队之间通过松散的社区部落进行衔接。

微服务优点

每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求。

微服务能够被小团队单独开发,这个小团队是2到5人的开发人员组成。

微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。

微服务能使用不同的语言开发。

微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins, bamboo

一个团队的新成员能够更快投入生产。

微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。

微服务允许你利用融合最新技术。

微服务只是业务逻辑的代码,不会和HTML,CSS 或其他界面组件混合。

微服务能够即时被要求扩展。

微服务能部署中低端配置的服务器上。

易于和第三方集成。

每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库。

微服务架构的缺点微服务架构可能带来过多的操作。

需要DevOps技巧

可能双倍的努力。

分布式系统可能复杂难以管理。

因为分布部署跟踪问题难。

当服务数量增加,管理复杂性增加。

什么是DevOps