2021年应届生面试题(一文到底)

2021年最新面试题


前言

提示:面试题知识点不分先后排序


一、集合

1.集合的特点

  • 对象封装数据。集合用于存储对象
  • 对象的个数确定可以使用数组,个数不确定可以用集合
  • 集合可改变长度

2.常用的集合类有哪些?

Map接口和collection接口是所有集合框架的父接口:

  1. Comllection接口的子接口包括:Set接口和List接口
  2. Map接口实现类主要有:HashMap、Hashtable、ConcurrentHashMap
  3. Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
  4. List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
    在这里插入图片描述
    Collection集合主要有ListSet两大接口:
ListSet
有序无序
插入多个null允许一个null
元素索引元素唯一性
支持for循环,通过下标遍历,可迭代只能用迭代
查找元素效率高删除和插入效率高

Map是一个键值,对集合、存储键,值之间的映射。

keyvalue
无序,唯一值不要求有序,允许重复

Map没有继承Conllection接口, 从Map集合检查元素,只要给出键对象,就返回相应的值。

3.哪些集合类是线程安全的?

  • vector:线程安全但是效率低。
  • statck:堆栈类,先进后出。
  • hashtable:就比hashmap多了个线程安全。
  • enumeration:枚举,相当于迭代器。

4.Conllection接口

1.Iterator 和 ListIterator 有什么区别?

ltratorListterator
可以遍历Set和List集合只能遍历List
单向遍历双向遍历

2.ArrayList 和 LinkedList 的区别是什么?

相同点:都不保证线程安全

ArrayListLinkedList
动态数组双向链表
效率高效率低
不占内存更占内存

3.ArrayList 和 Vector 的区别是什么?

ArrayListVector
非线程安全线程安全
扩容+50%+1%
性能好性能不行

二、多线程

1.并发的三要素是什么?怎么保证多线程的运行安全问题?

并发三要素:原子性可见性有序性

出现线程安全问题的原因:

  • 线程切换带来的原子性问题
  • 缓存导致的可见性问题
  • 编译优化带来的有序性问题

2.并发和并行的区别?

  • 并发:多个任务在同一个cpu核上、按时间片轮流交替,从逻辑上是同时运行
  • 并行:多个处理器或多个核处理器同时处理多任务。是真正意义上的同时运行

3.什么是上下文切换?

当前任务在执行完cpu时间片切换到另一个任务之前会保存自己的状态、以方便下次再切换回这个任务时候,可以再加载这个任务的状态 “任务从保存到再加载的的过程就是一次上下文切换

4.什么是线程死锁?

线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态。
在这里插入图片描述
形成死锁的四个条件:互斥条件请求与保持条件不剥夺条件循环等待条件

如何避免死锁:破坏产生死锁的四个条件之一就可以了

5.创建线程有哪几种方式?

1.继承 Thread类

定义Thread类的子类,重写run方法。
创建自定义的线程子类对象。
调用子类实例start方法启动线程

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run()方法正在执行...");
    }
}

public class TheadTest {
    public static void main(String[] args) {
        MyThread myThread = new MyThread(); 	
        myThread.start();
        System.out.println(Thread.currentThread().getName() + " main()方法执行结束");
    }
}
//执行结果
main main()方法执行结束
Thread-0 run()方法正在执行...

2.实现Runnable接口

定义Runnable接口实现类,并重写run方法
创建MyRunnable实例myRunnable,以myRunnable作为target创建Thead对象,该Thread对象才是真正的线程对象
调用线程对象的start()方法

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run()方法执行中...");
    }
}

public class RunnableTest {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
        System.out.println(Thread.currentThread().getName() + " main()方法执行完成");
    }
}
//执行结果
main main()方法执行结束
Thread-0 run()方法正在执行...

3.实现Callable接口

创建实现Callable接口的类myCallable
以myCallable为参数创建FutureTask对象
将FutureTask作为参数创建Thread对象
调用线程对象的start()方法

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() {
        System.out.println(Thread.currentThread().getName() + " call()方法执行中...");
        //call()方法的返回值必须与接口泛型类型一致
        return 1;
    }
}

public class CallableTest {
    public static void main(String[] args) {
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable());
        Thread thread = new Thread(futureTask);
        thread.start();

        try {
            Thread.sleep(1000);
            System.out.println("返回结果 " + futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " main()方法执行完成");
    }
}

//执行结果
Thread-0 call()方法执行中...
返回结果 1
main main()方法执行完成

4.使用Executors工具类(线程池)

主要有newFixedThreadPool,newCachedThreadPool,newSingleThreadExecutor,newScheduledThreadPool,后续详细介绍这四种线程池

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run()方法执行中...");
    }
}

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run()方法执行中...");
    }
}

//执行结果
线程任务开始执行
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...

6.run()和start()有什么区别?

run()方法会当成一个main线程的普通方法执行。
start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容,这是真正的多线程工作。

7.线程的生命周期和五种基本状态?

在这里插入图片描述

五种基本状态:新建可运行运行阻塞死亡

8.sleep()和wait()的区别?

两者相同点:可以暂停线程的执行

sieep()wait()
是Thread静态方法是Object类的方法
释放CPU不释放锁释放CPU和锁
用于暂停执行用于线程间交互/通信
自动苏醒。或者使用wait()超时后线程自动苏醒不会自动苏醒,要调用对象上notify()或notifyAll()

9.sleep()和yield()的区别?

两者相同点:可以暂停线程的执行

sieep()yield()
低优先级运行机会更高优先级运行机会
转入阻塞状态转入就绪状态
抛出异常没有声明任何异常

三、Spring

在这里插入图片描述

1.Spring框架核心?

Ioc容器AOP模块

  • IOC容器管理POJO对象以及它们之间的解耦关系
  • AOP以动态非侵入的方式增强服务

2.Spring用到了哪些设计模式?

  • 工厂模式:用来创建对象的实例
  • 单例模式:Bean默认为单例模式
  • 代理模式:面向切面功能AOP用到了JDK动态代理CGLIB字节码生成技术
  • 模板方法:解决代码重复问题
  • 观察者模式:定义对象键一种 一对多依赖关系

3.Spring控制反转(IOC)

1.IOC有什么作用?

  • 依赖注入(管理对象)
  • 解耦
  • 代理托管类的产生过程

2.IOC实现机制?

实现原理:工厂模式+反射机制

interface Fruit {
   public abstract void eat();
 }

class Apple implements Fruit {
    public void eat(){
        System.out.println("Apple");
    }
}

class Orange implements Fruit {
    public void eat(){
        System.out.println("Orange");
    }
}

class Factory {
    public static Fruit getInstance(String ClassName) {
        Fruit f=null;
        try {
            f=(Fruit)Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}

class Client {
    public static void main(String[] a) {
        Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple");
        if(f!=null){
            f.eat();
        }
    }
}

3.IOC支持哪些功能?

对IOC来说,重要的是容器。容器管理Bean生命周期。控制Bean依赖注入

  • 依赖注入
  • 依赖检查
  • 自动装配
  • 支持集合
  • 初始化和销毁方法
  • 回调某些方法(需要实现接口。)

4.Spring面向切面(AOP)

1.SpringAOP原理

AOP原理:不去动原来的代码,而是基于原来代码产生代理对象,通过代理的方法去包装,就完成对以前方法的增强

AOP底层原理就是动态代理的实现

2.代理机制有几种

  • JDK动态代理
  • CGLIB字节码代理

3.几大通知的执行顺序

  1. 前置通知:在目标方法被调用之前调用通知功能;
  2. 后置通知:在目标方法完成之后调用通知,
  3. 返回通知:成功执行之后调用通知,
  4. 异常通知:抛出异常后调用通知,
  5. 环绕通知:通知包裹了被通知的方法,

5.Spring注解

1.@Component, @Controller, @Repository, @Service 有何区别?

@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。

@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。

@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。

@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。

2.Autowired 注解有什么作用?

@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在

3.@Qualifier 注解有什么作用?

使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean 来消除歧义。

4.@RequestMapping 注解有什么用?

类级别:映射请求的 URL
方法级别:映射 URL 以及 HTTP 请求方法

6.Spring 事物管理?

编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。

声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。

四、Spring MVC

1.MVC核心组件

  1. 前端控制器
  2. 处理器映射器
  3. 处理器
  4. 视图解析器
  5. 视图

2.描述Spring MVC的工作流程?

在这里插入图片描述

(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。

3.Spring MVC常用的注解有哪些?

@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。

@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。

@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。

@Controller 用于标记在一个类上,使用它标记的类就是一个Spring MVC Controller 对象

请求路径上有个id的变量值,可以通过@PathVariable来获取

@RequestParam用来获得静态的URL请求入参 spring注解时action里用到。

4.如何解决POST请求中文乱码问题

在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;

五、SpringBoost

1.核心注解是哪个?主要由哪几个注解组成的?

启动类注解@SpringBootApplication 。也是SpringBoot的核心注解,包含了以下三个注解:
@SpringBootConfiguration : 组合 @Configguration注解 实现配置文件的功能
@ComponentScan: Spring组件扫描

2.核心配置文件是什么?

spring boot 核心的两个配置文件:

  • bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext加载的,比 applicaton 优先加载,配置在应用程序上下文的引导阶段生效。一般来说我们在 Spring Cloud Config 或者 Nacos 中会用到它。且 boostrap 里面的属性不能被覆盖;
  • application (. yml 或者 . properties): 由ApplicatonContext 加载,用于 spring boot 项目的自动化配置。

六、MyBatis

1.#{}和${}的区别?

#{}${}
是占位符,预编译处理是拼接符,没有预编译处理
是以字符串传入,将sql中的#{}替换?号是原值传入,替换成变量的值
有效防止sql注入不能防止sql注入
自动加上单引号不会加上单引号
替换是在DBMS中替换DBMS外

七、Redis分布式集群

在这里插入图片描述

1.Redis 可以存储键和五种不同类型的值之间的映射。

  • 字符串
  • 列表
  • 集合
  • 散列表
  • 有序集合

2.Redis有哪些优缺点

优点:

  • 读写性能优异
  • 支持俩种持久化:AOF 和 RDB
  • 支持事物
  • 数据结构丰富
  • 支持主从复制

缺点:

  • 数据库容量受到物理内存的限制
  • 不具备自动容错和恢复功能
  • 主机宕机未及时同步到从机
  • 较难支持在线扩容

3.Redis为什么这么快

  • 基于内存操作
  • 数据结构简单
  • 采用单线程
  • 使用多路I/O 复用

4.缓存异常

1.缓存雪崩

某一时刻发生大规模缓存失效,所有请求发送到数据库,数据库承受大量请求崩掉

解决方案

  1. 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  2. 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
  3. 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

2.缓存穿透

查询缓存和数据库不存在的数据,所有请求发送到数据库上,数据库承受大量请求崩掉

解决方案

  1. 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  2. 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
  3. 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap拦截掉,从而避免了对底层存储系统的查询压力

3.缓存击穿

大量请求查询一个key,key失效,导致大量请求打到数据库

解决方案

  1. 设置热点数据永远不过期。
  2. 加互斥锁,互斥锁

4.缓存预热

系统上线后,将相关的缓存数据直接加载到缓存系统。

解决方案

  1. 直接写个缓存刷新页面,上线时手工操作一下;
  2. 数据量不大,可以在项目启动的时候自动进行加载;
  3. 定时刷新缓存;

5.事物

1.什么是事物?

Redis中,单条命令是原子性执行的。事物不保证原子性、且没有回滚
Redis的事务总是具有ACID中的一致性隔离性

2.Redis事物三个阶段?

  1. 事物开始MULTI
  2. 命令入队
  3. 事物执行EXEC

6.哨兵

在这里插入图片描述
哨兵的核心知识

  1. 哨兵至少需要 3 个实例,来保证自己的健壮性。
  2. 哨兵 + redis 主从的部署架构,是不保证数据零丢失的,只能保证 redis集群的高可用性。
  3. 对于哨兵 + redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练。

八、Mysql和Oracle的区别

区别:MysqlOracle
事物:在存储引擎的行级锁支持事物完全支持事物
逻辑备份:需要锁定数据,才能一致不锁定数据,备份数据一致
提交方式:默认自动提交需要手动提交
数据持久性:更新数据会丢失在线日志恢复客户提交数据
性能诊断:慢查询日志各种成熟诊断工具
一致性:已读提交隔离可序列化隔离
并发性:使用表级锁,事物引擎的表行级锁依赖表索引行级锁,对并发支持较高

九、单体式架构和分布式架构有什么区别?

单体式架构

优点缺点
开发,测试简单启动慢,代码冲突
扩容简单性能有限

分布式架构:业务复杂提高效率

  • 7
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千筹问战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值