转载请注明出处: 贴一贴个人后端开发面试题。本文是面试回寝室后凭记忆罗列出来的问题,大概90%的问题都在这里面了,有几个问题的实在是想不起来了= =,有些问题自我感受回答的很差,因此我是查了资料后从新整理了再贴上答案的。若有错误或不适合的,欢迎你们评论点出,谢谢!css
虽然面试的是Java实习生职位,但问题不局限于Java语言。html
面试过程当中只有三个技术无关的话题:前端
这类的话题通常稍微准备一下,都不会有什么问题。java
首先咱们会在web.xml
中注册一个DispatcherServlet
,并令这个servlet
接收全部的请求,项目启动后Spring会扫描配置文件,根据配置加载和实例化类,其中扫描到的带有@Controller
或者@RestController
注解的类则是请求要映射到的类,Spring MVC扫描里面全部和请求映射有关的注解, 如@RequestMapping
、@ResponseBody
、@RequestParam
等。当接收到一个请求时,它会根据请求的url映射到对应的controler,并根据返回值判断是渲染jsp页面仍是返回普通文本,亦或是返回json。
AOP是经过动态代理来实现的,有两种经常使用的技术,一是JDK的动态代理
,二是CGLIB
,而不管是前者仍是后者,都是生成动态生成类的字节码来实现的。JDK的动态代理只能处理接口实现的方法
,而CGLIB则没有这个限制。由于字节码是动态生成的,因此能够在生成的字节码当中,在目标方法先后插入定义好的方法的调用。
当在一个类、方法或者字段上标上注解后,能够经过obj.getClass().isAnnotationPresent(..)
来判断一个目标是否被特定的注解标识,经过obj.getClass().getAnnotation(..)
来获取标志是注解,以此得到注解上的信息。使用注解能够帮助咱们在项目的编译期或运行时给类、方法或对象添加一个额外的信息,给编程增长了很大的灵活性。好比用@Override
来标志这是重写父类的方法,那么编译器就能够在编译期检查该方法是否真的是重写父类的方法,将错误扼杀在编译器。
线程有五种状态:建立
、就绪
、运行
、阻塞
、死亡
。
调用start
方法时,线程就会进入就绪状态。
在线程获得cpu时间片
时进入运行状态。
线程调用yield
方法可让出cpu时间回到就绪状态。
线程运行时可能因为IO
、调用sleep
、wait
、join
方法或者没法得到同步锁
等缘由进入阻塞状态。
当线程得到到等待的资源资源或者引发阻塞的条件获得知足时(调用notify
或notifyAll
),会从阻塞状态进入就绪状态。
当线程的run
方法执行结束或者调用interrupt
方法时,线程就进入死亡状态。
Java实现同步的方法有:linux
- 使用
synchronized
关键字为方法或代码块加锁。- 使用
volatile
修饰变量,可是volatile不保证原子性
。- 使用
ReentrantLock
或者ReentrantReadWriteLock
, 这种方法比synchronized
更灵活。- 使用
Semaphore
,容许最多n个线程同时访问资源。
HashMap
与Hashtable
的区别。
HashMap
是线程不安全
的,Hashtable
是线程安全的。HashMap
的key和value接受null,Hashtable
不接受。HashMap
继承自AbstractMap
,Hashtable
继承自Directory
。
这里我回答了最近正在看《深刻理解Java虚拟机》一书,本想着这方面的问题能答上一些的,没想到面试官直接说
那看样子还不是很了解,就不问这块的问题了= =.. 心塞
可是我估摸着大概若是问的话会问:程序员
JVM的内存一共分为5个部分:web
程序计数器
: 里面存放着线程执行的指令。方法区
: 存放类的信息,如:类名、方法、成员变量等,也存放着常量池。虚拟机栈
: 存放着局部变量表、操做数栈、方法出口信息等方法执行所需信息。本地方法栈
: 存放程序调用native方法的信息。堆
: 这五个部分中最大的,对象的内存分配都是在堆内存中。
-Xmx
: 指定最大堆内存-Xms
: 指定初始化堆内存大小。-Xmn
: 指定年轻代内存初始内存大小,同时也是最大内存大小。-XX:NewSize
: 指定年轻代内存大小。-XX:NewRatio
: 指定年轻代和老年代的内存比例。-XX:MaxHeapSize
: 指定程序最大内存。-XX:+PrintGC
: 打印GC日志。-XX:+PrintGCDetails
: 打印详细的GC日志。-Xloggc
: 打印GC日志保存位置。
引用计数算法
:该算法对每个对象都有一个引用计数,没增长一次引用就+1,减小一次引用-1,在回收时将引用计数为0的对象清理掉。这种算法简单,可是没法解决循环引用的问题(好比: A引用B, B也引用A,可是A和B都没有被其它任何对象引用)。
标记-清除算法
:该算法分为两个阶段, 第一阶段遍历找出全部须要被回收的对象,并作上标记,第二阶段对清理全部被标记的对象,这种算法效率比较低,而且会产生较多的内存碎片。
标记-整理算法
:该算法的第一阶段和标记-清除算法是同样的,而第二阶段它不是直接清理掉垃圾对象,并且将存活的对象往同一侧移动,移动完成后清理掉另外一侧全部的对象。这种算法不会产生内存碎片,可是效率低下。
复制算法
:该算法将内存分为两个区域,进行垃圾回收时,就将还活着的对象复制到另外一块内存区域中,而后再将整片内存区域清空。这种算法简单快速,并且不会产生内存碎片,可是由于将内存分红两块,因此可用的内存会少不少。
分代收集算法
:将内存细分为多个区域,不一样区域GC的频率,并对不一样的区域采用适当的收集算法。如JVM将内存分为年轻代和老年代,普通对象最开始分配在年轻代(大对象会直接分配到老年代),同一个对象在通过几回GC后还存活着,就认为这个对象的生命周期会比较长,将其移入老年代,GC主要发生在年轻代。
Java中主要有Bootstrap类加载器
、ExtClassLoader
、AppClassLoader
,其中Bootstrap类加载器
主要加载JAVA_HOME/lib
目录下的类库,ExtClassLoader
加载JAVA_HOME/lib/ext
目录下的类库,AppClassLoader
加载classpath
指向目录下的类库。Java的类加载器使用
双亲委派模型
,除了顶层的Bootstrap类加载器
外,其他的类加载器都有父类加载器,当一个类加载器要加载一个类时,它不会直接去加载,而是委托父类加载器尝试加载,父类加载器若是没法完成,则继续委托其父类加载器加载,若是在期间有某一个类加载器发现已经加载过这个类,则会将已经加载的类返回,子类再也不加载。若全部的类加载器都未加载过这个类,那么最开始尝试加载的加载器才会去加载这个类。使用这样的加载机制的好处是: 对于同一个类,如:java.lang.String
,能保证整个程序中都是使用的这一个类,不然若是用户在本身的项目中也写了一个java.lang.String
类,那么项目中将存在两个String类,一个是java提供的String类,一个是用户自定义的String类,不只使项目变得混乱,并且不安全。面试
我我的由于只简单接触过而没有实际应用过Hibernate
,因此没能从比较好的角度来回答这个问题。redis
Hibernate
的优势是它是一个彻底的ORM框架
,使用Hibernate
能够作到不用手写SQL,并且无须关心使用何种数据库,可移植性较好,当须要更变数据库时须要作的修改不多甚至为0。其缺点是须要根据数据库的设计在实体进行又一次的配置,且帮程序员作了太多事,若是须要进行调优的话须要对Hibernate
有比较深的了解。
MyBatis
的优缺点差很少和Hibernate
相反,咱们须要手写SQL
语句和配置结果集和实体类的映射
,即便是简单的单表操做也须要写SQL(能够经过拦截器
来实现CommonMapper,或者可使用生成器来生成代码),所以MyBatis
要进行SQL调优也简单直接。其次是MyBatis
的二级缓存
功能较弱,是针对namespace
的。
较常使用的方法是
explain SQL
查看执行计划,根据查询计划能够知道是否使用了索引
,是否进行来全表扫描
以及查询的顺序,依此咱们能够创建适当的索引和链接查询调优。
还有一个是开启慢查询记录执行时间长的SQL语句。算法
- 一般会在
WHERE
、JOIN ON
和ORDER BY
使用到字段上加上索引。- 避免查询时判断
NULL
,不然可能会致使全表扫描。- 避免使用
OR
来链接查询条件,不然可能致使全表扫描,能够改用UNION
或UNION ALL
。- 避免
LIKE
查询,不然可能致使全表扫描。- 不使用
SELECT *
,只查询必须的字段,避免加载无用数据。- 能用
UNION ALL
的时候就不用UNION
,UNION
过滤重复数据要耗费更多的cpu资源。
由于平时都是用的InnoDB
,对其它引擎的了解甚少,因此这个问题没答上= =,这里直接贴一个连接好了。
相关连接: MySQL存储引擎介绍
- 使用
$(..).css({..})
来改变元素的样式。- 使用
$(..).attr(..)
改变元素的属性。- 使用
$(..).html(..)
改变元素的html内容。- 使用
$(..).text(..)
改变元素的文本内容。- 使用
$(..).remove(..)
删除元素。- 使用
$(..).append(..)
添加元素。
若是是使用JSP
等后端模板的话,通常会将须要分页的JSP代码
抽成一个单独的JSP文件
,并在页面中动态计算分页按钮的展现方式,在母页中include
该JSP文件
,而后在前端点击分页按钮时,经过AJAX
请求下一页的内容,服务器端将渲染后的HTML
返回给前端,前端经过$(..).html()
等方式替换展现内容。
若是是在先后端分离的项目中,通常会使用一些前端的框架,如:React.js
、Vue.js
等,每次只向后台请求分页的数据,通常数据交互格式使用JSON
,并替换已有的数据,触发页面内容的改变。
RESTful
是无状态的,采用URL
+HTTP请求方法
来描述资源
和行为
。
通常在先后端分离的项目中,后端会提供REST接口
给前端,其HTTP请求方法
通常为:
GET
: 获取资源。POST
: 更新资源。PUT
: 建立资源。DELETE
: 删除资源。其次,
RESTful
因为是无状态的,通常会采用JWT
或OAuth
的方式来认证一个用户,Token
是保存在前端的,为了安全性通常会配合HTTPS
使用。
HTTP请求
分为三部分:请求行
、请求头
、请求体
:
请求行
: 第一行是METHOD URL protocal
,如GET http://abc.com HTTP/1.1
。
请求头
: 从第二行开始,每一行的内容都是一个请求头参数值,直到遇到一个空行
为止。
请求体
: 请求头和请求体中间隔着一行空行
做为分界,请求体包含着本次请求携带的内容。
GET
方式的请求没有请求体,其是将参数追加到URL
后面,URL
中?
后面的内容为请求参数。
POST
方式则三部分都有,且POST
的请求头应当包含Content-Type
来指明请求体中内容的类型。
上传文件的话会设置Content-Type
为multipart/form-data
,并指定boundary
的值来标识请求体中内容的分界,而在请求体中,不一样的内容(如:文件A和文件B)之间使用boundary
的值来标识分界,而且请求体中每部份内容都会有Content-Disposition
和Content-Type
来指明这部份内容的类型和信息。后端的话使用
ServletFileUpload
来解析请求,得到FileItem
的List
,遍历Item
,而后经过Item
得到输入流,从输入流中读取上传文件的数据,再构建FileOutputStream
输出到磁盘中保存。
若是使用Spring MVC
,则能够在接收请求的方法中接收CommonsMultipartFile
,并使用transferTo
方法保存到磁盘中。
这个也没答上来,平时都是使用jQuery
封装的AJAX
或者其余AJAX
框架。
AJAX是利用浏览器的AJAX引擎来实现的异步请求,经过XMLHttpRequest
对象来发送请求,由AJAX引擎向服务器发送和接收响应,再回调给用户处理,达到不阻塞用户界面和无刷新的目的。
资料来源: AJAX工做原理及其优缺点。
若是是查找二进制文件,可使用whereis
。
若是是查找命令,可使用which
。
若是是其余文件,可使用find
命令(其实什么均可以找),-name
指定搜索的名称或者匹配串,-maxdepth
指定搜索的深度。
也可使用locate
命令查找,可是最新变更的文件可能会找不到,由于该命令其实是搜索数据库,该数据库天天自动更新,能够手动执行updatedb
更新。
使用ps
命令能够查看进程状态,ps -ef
查看全部进程,配合grep
命令能够进行筛选, 如查看tomcat
进程的命令是:ps -ef | grep tomcat
。
这题没也没答上= =
使用grep
命令能够实现:
grep -rn /path/to/target/dir -e "pattern"
-r
: 递归
-n
: 显示行数
-w
: 彻底匹配
例子:grep -rn. -e "ERROR"
输出:./面试:143:输出: ./面试:144:上面的命令搜索当前目录及其子目录中的文件,并输出含有ERROR内容的行
详细答案及来源: How to find all files containing specific text on Linux?
Redis
在我接触过的项目中主要作了两件事:
缓存
。存储须要计算的信息
。
Redis
也能够用来作消息订阅
、队列
等。
这个问题我估摸着面试官想问的是Redis
的数据保障的方法,否则崩溃了除了重启还能怎么办?
Redis
有提供数据持久化的功能,一种是快照
,一种是AOF
。
快照
是在某一个时间点将全部数据写入到磁盘中,AOF
是将被执行的命令复制到硬盘中,快照
的文件体积要比AOF
的文件体积小。前者在恢复时速度
比后者快,可是由于是间隔持久化
,因此会有必定量的数据丢失
。后者由于是实时写入
的,因此数据的完整性比较好,若是丢失的话通常也就丢失一秒的数据。其次须要作主从复制,这样一份数据能够保存在多台服务器上,且能够避免
Redis
崩溃到重启完成这段时间内没法提供正常服务,同时从服务器能够分担主服务器的读压力。
没配置过因此没答上= =
相关链接: Redis集群教程。
- 前一家公司实习的时候主要作什么?
- 讲一下作过的项目?
- 项目中有没有遇到什么难点?怎么解决的?
- 有没有作过什么有亮点的东西?
其中在问题3根据个人回答,继续将状况复杂化让我给出解决方案,一步一步问。
最后. 若是不是熟悉的技术真的不要往简历上写= = 我由于在项目须要,学习过Android,可是项目完成后就
没碰过了(近一年),把对Android有必定的了解写上简历,结果问了三个问题就答不上了= =
虽然最终拿到了offer,可是由于各方面缘由,最后仍是放弃了,在此也提醒一下,秋招千万不要错过= =,拖到这个时候,好的实习的真很差找(成都)。
学习技术不能知其然而不知其因此然,往后不只会持续更新面试内容,同时本专栏会持续发布Java
、数据库
、Linux
、算法
等方面的学习文章。欢迎关注。
最后,若有错误或不适合的,请你们评论点出,共同进步,谢谢!