美文网首页面试
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