后端开发面试题

虽然面试的是Java职位,但问题不局限于Java语言。

  技术无关:
  面试过程中只有两个技术无关的话题:
  自我介绍。
  感觉自己有什么优缺点?
  这类的话题一般稍微准备一下,都不会有什么问题。
  
  技术相关:
  1. Spring MVC 如何接受并处理一个请求的?

  首先我们会在 web.xml 中注册一个 DispatcherServlet ,并令这个 servlet 接收所有的请求,项目启动后Spring会扫描配置文件,根据配置加载和实例化类,其中扫描到的带有 @Controller 或者 @RestController 注解的类则是请求要映射到的类,Spring MVC扫描里面所有和请求映射有关的注解, 如 @RequestMapping 、 @ResponseBody 、 @RequestParam 等。当接收到一个请求时,它会根据请求的url映射到对应的controler,并根据返回值判断是渲染jsp页面还是返回普通文本,亦或是返回json。

  2. AOP实现原理。

  AOP是通过动态代理来实现的,有两种常用的技术,一是 JDK的动态代理 ,二是 CGLIB ,而无论是前者还是后者,都是生成动态生成类的字节码来实现的。 JDK的动态代理只能处理接口实现的方法 ,而CGLIB则没有这个限制。因为字节码是动态生成的,所以可以在生成的字节码当中,在目标方法前后插入定义好的方法的调用。

  3. 注解是怎么用的?为什么要使用注解?

  当在一个类、方法或者字段上标上注解后,可以通过 obj.getClass().isAnnotationPresent(..) 来判断一个目标是否被特定的注解标识,通过 obj.getClass().getAnnotation(..) 来获取标志是注解,以此获得注解上的信息。使用注解可以帮助我们在项目的编译期或运行时给类、方法或对象添加一个额外的信息,给编程增加了很大的灵活性。比如用 @Override 来标志这是重写父类的方法,那么编译器就可以在编译期检查该方法是否真的是重写父类的方法,将错误扼杀在编译器。

  4. 线程有几种状态?生命周期是怎样的?

  线程有五种状态: 创建 、 就绪 、 运行 、 阻塞 、 死亡 。

  调用 start 方法时,线程就会进入就绪状态。

  在线程得到 cpu时间片 时进入运行状态。

  线程调用 yield 方法可以让出cpu时间回到就绪状态。

  线程运行时可能由于 IO 、调用 sleep 、 wait 、 join 方法或者 无法获得同步锁 等原因进入阻塞状态。

  当线程获得到等待的资源资源或者引起阻塞的条件得到满足时(调用 notify 或 notifyAll ),会从阻塞状态进入就绪状态。

  当线程的 run 方法执行结束或者调用 interrupt 方法时,线程就进入死亡状态。

  5. Java中如何实现同步。

  Java实现同步的方法有:

  使用 synchronized 关键字为方法或代码块加锁。

  使用 volatile 修饰变量,但是 volatile不保证原子性 。

  使用 ReentrantLock 或者 ReentrantReadWriteLock , 这种方法比 synchronized 更灵活。

  使用 Semaphore ,允许最多n个线程同时访问资源。

  6. HashMap 与 Hashtable 的区别。

  HashMap 是 线程不安全 的, Hashtable 是线程安全的。

  HashMap 的key和value接受null, Hashtable 不接受。

  HashMap 继承自 AbstractMap , Hashtable 继承自 Directory 。

  7. JVM是否了解?

  这里我回答了最近正在看《深入理解Java虚拟机》一书,本想着这方面的问题能答上一些的,没想到面试官直接说

  那看样子还不是很了解,就不问这块的问题了= =

  但是我估摸着大概如果问的话会问:

  7.1. JVM的内存模型。

  JVM的内存一共分为5个部分:

  程序计数器

  方法区

  虚拟机栈

  本地方法区

  堆

  7.2. 常用的虚拟机参数。

  -Xmx

  -Xms

  -Xmn

  -XX:NewSize

  -XX:NewRatio

  -XX:MaxHeapSize

  -XX:+PrintGC

  -XX:+PrintGCDetails

  -Xloggc

  7.3. 垃圾回收算法。

  引用技术算法

  该算法对每一个对象都有一个引用计数,没增加一次引用就+1,减少一次引用-1,在回收时将引用计数为0的对象清理掉。这种算法简单,但是无法解决循环引用的问题(比如: A引用B, B也引用A,但是A和B都没有被其它任何对象引用)。

  标记-清除算法

  该算法分为两个阶段, 第一阶段遍历找出所有需要被回收的对象,并做上标记,第二阶段对清理所有被标记的对象,这种算法效率比较低,并且会产生较多的内存碎片。

  标记-整理算法

  该算法的第一阶段和标记-清除算法是一样的,而第二阶段它不是直接清理掉垃圾对象,而且将存活的对象往同一侧移动,移动完成后清理掉另一侧所有的对象。这种算法不会产生内存碎片,但是效率低下。

  复制算法

  该算法将内存分为两个区域,进行垃圾回收时,就将还活着的对象复制到另一块内存区域中,然后再将整片内存区域清空。这种算法简单快速,而且不会产生内存碎片,但是因为将内存分成两块,所以可用的内存会少很多。

  分代收集算法

  将内存细分为多个区域,不同区域GC的频率,并对不同的区域采用适当的收集算法。如JVM将内存分为年轻代和老年代,普通对象最开始分配在年轻代(大对象会直接分配到老年代),同一个对象在经过几次GC后还存活着,就认为这个对象的生命周期会比较长,将其移入老年代,GC主要发生在年轻代。

  7.4 类加载机制。

  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类,不仅使项目变得混乱,而且不安全。

  8. MyBatis和Hibernate各有什么优缺点?

  我个人因为只简单接触过而没有实际应用过 Hibernate ,所以没能从比较好的角度来回答这个问题。

  Hibernate 的优点是它是一个完全的 ORM框架 ,使用 Hibernate 可以做到不用手写SQL,而且无须关心使用何种数据库,可移植性较好,当需要更变数据库时需要做的修改很少甚至为0。其缺点是需要根据数据库的设计在实体进行又一次的配置,且帮程序员做了太多事,如果需要进行调优的话需要对 Hibernate 有比较深的了解。

  MyBatis 的优缺点差不多和 Hibernate 相反,我们需要 手写SQL 语句和 配置结果集和实体类的映射 ,即使是简单的单表操作也需要写SQL(可以通过 拦截器 来实现CommonMapper,或者可以使用生成器来生成代码),因此 MyBatis 要进行SQL调优也简单直接。其次是 MyBatis 的 二级缓存 功能较弱,是针对 namespace 的。

  9. MySQL平时是怎么分析效率和进行SQL优化的?

  较常使用的方法是 explain SQL 查看执行计划,根据查询计划可以知道是否使用了索引 ,是否进行来 全表扫描 以及查询的顺序,依此我们可以建立适当的索引和连接查询调优。

  还有一个是开启慢查询记录执行时间长的SQL语句。

  通常会在 WHERE 、 JOIN ON 和 ORDER BY 使用到字段上加上索引。

  避免查询时判断 NULL ,否则可能会导致全表扫描。

  避免使用 OR 来连接查询条件,否则可能导致全表扫描,可以改用 UNION 或 UNION ALL 。

  避免 LIKE 查询,否则可能导致全表扫描。

  不使用 SELECT * ,只查询必须的字段,避免加载无用数据。

  能用 UNION ALL 的时候就不用 UNION , UNION 过滤重复数据要耗费更多的cpu资源。

  10. MySQL除了InnoDB还有哪些引擎,有什么区别?

  因为平时都是用的 InnoDB ,对其它引擎的了解甚少,所以这个问题没答上= =,这里直接贴一个链接好了。

  相关链接: MySQL存储引擎介绍

  11. 如何动态改变页面上的元素?

  $(..).css({..})

  $(..).attr(..)

  $(..).html(..)

  $(..).text(..)

  $(..).remove(..)

  $(..).append(..)

  12. 分页的实现。

  如果是使用 JSP 等后端模板的话,一般会将需要分页的 JSP代码 抽成一个单独的JSP文件 ,并在页面中动态计算分页按钮的展示方式,在母页中 include 该 JSP文件,然后在前端点击分页按钮时,通过 AJAX 请求下一页的内容,服务器端将渲染后的HTML 返回给前端,前端通过 $(..).html() 等方式替换展示内容。

  如果是在前后端分离的项目中,一般会使用一些前端的框架,如: React.js 、 Vue.js 等,每次只向后台请求分页的数据,一般数据交互格式使用 JSON ,并替换已有的数据,触发页面内容的改变。

  13. 解释一下RESTful,平时是怎么用的

  RESTful 是无状态的,采用 URL + HTTP请求方法 来描述 资源 和 行为 。

  一般在前后端分离的项目中,后端会提供 REST接口 给前端,其 HTTP请求方法 一般为:

  GET

  POST

  PUT

  DELETE

  其次, RESTful 由于是无状态的,一般会采用 JWT 或 OAuth 的方式来认证一个用户, Token 是保存在前端的,为了安全性一般会配合 HTTPS 使用。

  14. 有没有抓过包?GET和POST格式是怎么样的?

  HTTP请求 分为三部分: 请求行 、 请求头 、 请求体 :

  请求行 : 第一行是 METHOD URL protocal ,如 GET http://abc.com HTTP/1.1 。

  请求头 : 从第二行开始,每一行的内容都是一个请求头参数值,直到遇到一个 空行为止。

  请求体 : 请求头和请求体中间隔着一行 空行 作为分界,请求体包含着本次请求携带的内容。

  GET 方式的请求没有请求体,其是将参数追加到 URL 后面, URL 中 ? 后面的内容为请求参数。

  POST 方式则三部分都有,且 POST 的请求头应当包含 Content-Type 来指明请求体中内容的类型。

  15. 如果是上传文件的话又是怎样的?后端如何处理?

  上传文件的话会设置 Content-Type 为 multipart/form-data ,并指定 boundary的值来标识请求体中内容的分界,而在请求体中,不同的内容(如:文件A和文件B)之间使用 boundary 的值来标识分界,并且请求体中每部分内容都会有 Content-Disposition 和 Content-Type 来指明这部分内容的类型和信息。

  后端的话使用 ServletFileUpload 来解析请求,获得 FileItem 的 List ,遍历 Item ,然后通过 Item 获得输入流,从输入流中读取上传文件的数据,再构建 FileOutputStream 输出到磁盘中保存。

  如果使用 Spring MVC ,则可以在接收请求的方法中接收 CommonsMultipartFile,并使用 transferTo 方法保存到磁盘中。

  16. AJAX实现原理。

  AJAX是利用浏览器的AJAX引擎来实现的异步请求,通过 XMLHttpRequest 对象来发送请求,由AJAX引擎向服务器发送和接收响应,再回调给用户处理,达到不阻塞用户界面和无刷新的目的。

  资料来源: AJAX工作原理及其优缺点 。

  17. Linux下怎么查找一个文件?

  如果是查找二进制文件,可以使用 whereis 。

  如果是查找命令,可以使用 which 。

  如果是其他文件,可以使用 find 命令(其实什么都可以找), -name 指定搜索的名称或者匹配串, -maxdepth 指定搜索的深度。

  也可以使用 locate 命令查找,但是最新变动的文件可能会找不到,因为该命令实际上是搜索数据库,该数据库每天自动更新,可以手动执行 updatedb 更新。

  18. Linux怎么查找一个进程?

  使用 ps 命令可以查看进程状态, ps -ef 查看所有进程,配合 grep 命令可以进行筛选, 如查看 tomcat 进程的命令是: ps -ef | grep tomcat 。

  19. Linux下只知道文件所在目录和内容,如何查找文件?

  这题没也没答上= =

  使用 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?

  20. Redis你用它来做什么?

  Redis 在我接触过的项目中主要做了两件事:

  缓存

  存储需要计算的信息

  Redis 也可以用来做 消息订阅 、 队列 等。

  21. Redis如果运行过程中崩溃了怎么办。

  这个问题我估摸着面试官想问的是 Redis 的数据保障的方法,不然崩溃了除了重启还能怎么办?

  Redis 有提供数据持久化的功能,一种是 快照 ,一种是 AOF 。

  快照 是在某一个时间点将所有数据写入到磁盘中, AOF 是将被执行的命令复制到硬盘中, 快照 的文件体积要比 AOF 的文件体积小。前者在 恢复时速度 比后者快,但是因为是 间隔持久化 ,所以会有一定量的 数据丢失 。后者因为是 实时写入的,所以数据的完整性比较好,如果丢失的话一般也就丢失一秒的数据。

  其次需要做主从复制,这样一份数据可以保存在多台服务器上,且可以避免 Redis崩溃到重启完成这段时间内无法提供正常服务,同时从服务器可以分担主服务器的读压力。

  22. Redis集群。

  没配置过所以没答上= =

  相关连接: Redis集群教程 。

  23. 剩下的问题都是偏向个人的,没有什么通用性的回答,大概问了我:

  前一家公司的时候主要做什么?

  讲一下做过的项目?

  项目中有没有遇到什么难点?怎么解决的?

  有没有做过什么有亮点的东西?

  其中在问题3根据我的回答,继续将情况复杂化让我给出解决方案,一步一步问。

  最后

  最后. 如果不是熟悉的技术真的不要往简历上写= = 我因为在项目需要,学习过Android,但是项目完成后就没碰过了(近一年),把对Android有一定的了解写上简历,结果问了三个问题就答不上了= =

  虽然最终拿到了offer,但是因为各方面原因,最后还是放弃了,在此也提醒一下,秋招千万不要错过= =,拖到这个时候,好的工作的真不好找(成都)。
  学习技术不能知其然而不知其所以然,日后会持续更新面试内容。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值