美文网首页面试
Java面试题总结

Java面试题总结

作者: 山巅自相见 | 来源:发表于2021-05-21 15:15 被阅读0次

SpringMVC执行流程

1.用户发送请求至前端控制器DispatcherServlet
2.DispatcherServlet收到请求调用处理器映射器HandlerMapping
3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet
4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
5.执行处理器Handler(Controller,也叫页面控制器)
6.Handler执行完成返回ModelAndView
7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9.ViewReslover解析后返回具体View
10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)
11.DispatcherServlet响应用户


SpringMVC执行流程图解

mybatis面试题

什么是mybatis

  1. Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,加载驱动、创建连接、创建statement等繁杂的过程,开发者开发时只需要关注如何编写SQL语句,可以严格控制sql执行性能,灵活度高。
  2. 作为一个半ORM框架,MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

称Mybatis是半自动ORM映射工具,是因为在查询关联对象或关联集合对象时,需要手动编写sql来完成。不像Hibernate这种全自动ORM映射工具,Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取。

  1. 通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。
  2. 由于MyBatis专注于SQL本身,灵活度高,所以比较适合对性能的要求很高,或者需求变化较多的项目,如互联网项目。

#{}和${}的区别

{}是字符串替换,#{}是预处理; Mybatis在处理{}时,就是把${}直接替换成变量的值。而Mybatis在处理#{}时,会对sql语句进行预处理,将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
使用#{}可以有效的防止SQL注入,提高系统安全性。

SpringBoot面试题

谈谈你对SpringBoot的理解

SpringBoot主要用来简化使用Spring的难度和繁重的XML配置,他是Spring组件的一站式解决方案,采用了习惯于优于配置的方法。通过.properties或者.yml文件代替了Spring繁杂的XML配置文件,同时支持@ImportResourse注解加载XML配置。SpringBoot还提供了嵌入式HTTP服务器、命令行接口工具、多种插件等等,是的应用程序的测试和开发简单起来。

为什么要用SpringBoot?

SpringBoot优点非常多,例如:独立运行、简化配置、自动配置和无需部署war文件等等。

SpringBoot的核心配置文件有哪几个?它们的区别是什么?

SpringBoot的核心配置文件是application和bootstrap配置文件。
application配置文件主要用于SpringBoot项目的自动化配置文件。
bootstrap配置文件有三个应用场景:

  1. 使用Spring Cloud Config配置中心时,需要在bootstarp配置文件中添加链接到配置中的配置属性,来加载配置中心的配置信息;
  2. 一些固定的不能被覆盖的属性;
  3. 一些加密或解密的场景;

运行SpringBoot有几种方式

  1. 用命令打包或者放容器中运行
  2. 用Maven插件运行
  3. 直接执行main方法运行

SpringBoot有哪几种读取配置的方式

  1. 使用@Value加载单个属性值
  2. 使用@ConfigurationProperties注解可以加载一组属性的值,针对于要加载属性过多的形况,比@Value,注解要更加简洁

Java设计模式

创建型模式:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式;
结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式;
行为型模式:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

Dubbo面试题

Dubbo是什么

Dubbo是阿里巴巴开源的基于Java的高性能RPC分布服务框架,现已成为Apache基金会孵化项目。

为什么要使用Dubbo

使用Dubbo可以将核心业务逻辑抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用灵活扩展,使前端应用能快速地响应多变的市场需求

Dubbo和SpringCloud有什么区别

两个没关联,如果硬要说区别,有以下几点

  1. 通信方式不同
    Dubbo使用的是RPC通信,而SpringCloud使用的是HTTP RESTFul方式。
  2. 组成部分不同

Dubbo需要web容器吗

不需要,如果硬要用web容器,只会增加复杂性,也浪费资源

画一画服务注册与发现的流程图

流程图

Dubbo默认使用什么注册中心

推荐使用Zookeeper作为注册中心,还有Redis、Multicats、Simple注册中心,但不推荐

缓存面试题

用缓存,主要是俩用途:高性能、高并发
如果不用缓存,会是什么效果?
每次查询数据都要从数据库查,严重消耗数据库性能。

缓存-低性能查询举例
为了保证高性能,用了缓存之后
缓存-高性能查询举例
缓存是如何实现高并发的
缓存-如何实现高并发.png

集合面试题

常见的集合类有哪些

conllection接口的子接口包括:Set接口和List接口
Map接口的实现类主要有:HashMap、TreeMap和HashTable等
Set接口的实现类主要有:HashSet、TreeSet和LinkedHashSet等
List接口的实现类主要有:ArrayList、LinkedList和Vector等

集合框架底层数据结构

List

ArrayList:Object数组
Vector:Object数组
LinkedList:双向循环链表

Set

HashSet(无序、唯一):基于HashMap实现的,底层采用HashMap来保存元素
LinkedHashSet:LinkedHashSet继承于HashSet,并且其内部是通过LaskedHashMap来实现的。有点类似于LinkedHashMap其内部是基于HashMap实现一样,不过还是有一点区别的
TreeSet(有序、唯一):红黑树(自平衡的排序二叉树)

Map

HashMap:JDk1.8之前HashMap有数组加链表组成,数组是HashMap的主体,链表则是解决哈希冲突而存在的;JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时。将链表转化为红黑树,以减少搜索时间
LinkedHashMap:继承自HashMap
HashTable:数组加链表组成
TreeMap:红黑树(自平衡的排序二叉树)

那些集合类的线程时安全的

Vector:效率低,不建议使用
statck:堆栈类,先进后出

如何边遍历边移除Conllection中的元素

边遍历边修改Conllection的唯一办法是使用Iterator.remove()方法,如下:

Iterator<Integer> it = list.iterator();
while(it.hasNext()){
  *// do something*
  it.remove();
}

一种最常见的错误代码如下:

for(Integer i : list){
  list.remove(i)
}

运行以上错误代码会报ConcurrentModificationException异常,因为当使用foreach(for(Integer i : list))语句时,会自动生成一个iterator来遍历该list,但同时该list正在被Iterator.remove()修改,Java一般不允许一个线程在遍历Conllection时另一个线程修改它

ArrayList优缺点

优点

  • ArrayList底层以数组实现,是一种随机访问模式,因此查找的时候非常快
  • ArrayList在顺序添加一个元素的时候非常方便

缺点

  • 删除元素的时候,需要做一次元素复制操作,如果要复制的元素有很多,那么就会比较耗费性能
  • 插入元素的时候,同上

ArrayList和Vector的区别

相同

两个类都实现了List接口,都是有序集合

不同

  • 线程安全:Vector线程安全,而ArrayList线程是非安全的
  • 性能:ArrayList在性能方面要优于Vector
  • 扩容:ArrayList和Vector都会根据实际需要动态地调整容量,Vector扩容每次会增加1倍,ArrayList只会增加50%

生成随机数的三种方法

第一种:new Random()

第一种需要借助java.util.Random类来产生一个随机数发生器,也是最常用的一种,构造函数有两个,Random()和Random(long seed)。第一个就是以当前时间为默认种子,第二个是以指定的种子值进行。产生之后,借助不同的语句产生不同类型的数。
种子就是产生随机数的第一次使用值,机制是通过一个函数,将这个种子的值转化为随机数空间中的某一个点上,并且产生的随机数均匀的散布在空间中。以后产生的随机数都与前一个随机数有关。以代码为例。

public static void main(String[] args) {
  Random r = new Random(1);
  for (int i=0 ; i<5 ;  i++) {
    int ran1 = r.nextInt(100);
    System.out.println(ran1);
  }
}

在我的编译器下产生的五个数均为85,88,47,13,54,如果采用Random r = new Random(),产生的随机数就不同,这就是确定种子导致的结果。

第二种:Math.random()

而第二种方法返回的数值是[0.0,1.0)的double型数值,由于double类数的精度很高,可以在一定程度下看做随机数,借助(int)来进行类型转换就可以得到整数随机数了,代码如下。

public static void main(String[] args) {    
  int max=100,min=1;
  int ran2 = (int) (Math.random()*(max-min)+min); 
  System.out.println(ran2);
}

第三种:currentTimeMillis()

至于第三种方法虽然不常用,但是也是一种思路。方法返回从1970年1月1日0时0分0秒(这与UNIX系统有关)到现在的一个long型的毫秒数,取模之后即可得到所需范围内的随机数。

public static void main(String[] args){    
  int max=100,min=1;
  long randomNum = System.currentTimeMillis();  
  int ran3 = (int) (randomNum%(max-min)+min);  
  System.out.println(ran3);
}

Redis面试题

Redis支持的数据类型

  1. String字符串
  2. Hash(哈希)
  3. List(列表)
  4. Set(集合)
  5. zset(sorted set:有序集合)

缓存概述

缓存的作用是减少服务器对数据库的访问频率,从而提高数据库的稳定性。
访问流程如下:


Redis缓存1
Redis缓存2
Redis缓存3

代码逻辑

public Goods searchArticleById(Long goodsId){
  Object object = redisTemplate.opsForValue().get(String.valueOf(goodsId));
  if(object != null){// 缓存查询到了结果
    return (Goods)object;
  }
  // 开始查询数据库
  Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
  if(goods!=null){
    // 将结果保存到缓存中
    redisTemplate.opsForValue().set(String.valueOf(goodsId),goods,60,TimeUnit.MINUTES);;
  }
  return goods;
}

多线程常见面试题

并发和并行有什么区别

  1. 并行:之两个或多个事件在同一时刻发生,即同时做不同的事。例如垃圾回收时,多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
  2. 并发:指两个或多个时间在同一时间间隔内发生,即交替做不同事的能力,多线程是一种并发的能力。例如垃圾回收时,用户线程与垃圾线程同时执行(但不一定是并行,可能会交替执行),用户程序在继续执行,而垃圾收集程序运行于另一个CPU上

创建线程有哪几种方式

  1. 继承Thread类(真正意义上的线程类),时Runnable接口的实现。
  2. 实现Runnable接口,并重写里面的run()方法。
  3. 使用Executor框架创建线程池。Executor框架是juc里提供的线程池的实现。

线程的run()和srart()有什么区别

  1. start()方法用于启动线程,run()方法用于执行线程的运行时的代码
  2. run()方法可以重复调用,而start()只能调用一次。
  3. 第二次调用start()必然会抛出运行时异常

Spring面试题

@Mapper和@Repository注解的区别

  1. 使用@mapper后,不需要在spring配置中设置扫描地址,通过mapper.xml里面的namespace属性对应相关的mapper类,spring将动态的生成Bean后注入到ServiceImpl中。
  2. @repository则需要在Spring中配置扫描包地址,然后生成dao层的bean,之后被注入到ServiceImpl中

相关文章

网友评论

    本文标题:Java面试题总结

    本文链接:https://www.haomeiwen.com/subject/zcpwjltx.html