面试

## 概念 ### ==自我介绍== - 我叫***,大学所学的专业就是(java)计算机软件开发,拥有不错的Java基础,以及编程规范;一般开源的框架 Hibernate、mybatis、Spring ,SpringCloud以及一些缓存,中间件和 mysql,都在项目中经常使用。个人性格比较开朗,也经常看一些网上的教程自学。 如果有幸能加入贵公司,我有信心,也有能力做好这份工作,以上是我的个人基本情况。 ### ==并发 并行 串行== ![image.png](https://cos.easydoc.net/31477061/files/kx62q75f.png) ### ==session 和 cookie 有什么区别?== Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中; Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。 ---------------------------------------------- ## java基础 ### ==final== - final 修饰的类叫最终类,该类不能被继承。 final 修饰的方法不能被重写。 final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。 - Java中的String类就是一个final类 类的private方法会隐式地被指定为final方法。 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。 很多时候会容易把static和final关键字混淆,static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变 ### ==static== - 在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。” - 方便在没有创建对象的情况下来进行调用(方法/变量)。 - 静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。 - static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。 ### ==String、StringBuffer、StringBuilder的区别== - String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象 而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。 - StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的 而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer - 所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。 ### ==String 类的常用方法都有那些== indexOf():返回指定字符的索引。 charAt():返回指定索引处的字符。 replace():字符串替换。 trim():去除字符串两端空白。 split():分割字符串,返回一个分割后的字符串数组。 getBytes():返回字符串的 byte 类型数组。 length():返回字符串长度。 toLowerCase():将字符串转成小写字母。 toUpperCase():将字符串转成大写字符。 substring():截取字符串。 equals():字符串比较。 ### ==Java中有几种类型的流== 1.字节流和字符流 2.字节流继承inputStream和OutputStream 3.字符流继承自InputSteamReader和OutputStreamWriter ### ==流:字节流和字符流哪个好?== 大多数情况下使用字节流会更好,因为字节流是字符流的包装,而大多数时候 IO 操作都是直接操作磁盘文件,所以这些流在传输时都是以字节的方式进行的(图片,视频,音频等都是按字节存储的) 如果对于操作需要通过 IO 在内存中频繁处理字符串的情况使用字符流会好些,因为字符流具备缓冲区,提高了性能 ### ==list -set -map 及其实现类== - List 有顺序,可以有重复对象 - LinkedList 基于链表实现,链表内存是散列的,增删快,查找慢; - ArrayList 基于数组实现,非线程安全,效率高,增删慢,查找快; - Vector 基于数组实现,线程安全,效率低,增删慢,查找慢; - Set 集合中的对象无序,并且没有重复对象 - HashSet 底层是由 Hash Map 实现,不允许集合中有重复的值,使用该方式时需要重写 equals()和 hash Code()方法; - LinkedHashSet 继承于 HashSet,同时又基于 LinkedHashMap 来进行实现,底层使用的是 LinkedHashMap - Map 中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对象可以重复; - HashMap 基于 hash 表的 Map 接口实现,非线程安全,高效,支持 null 值和 null - HashTable 线程安全,低效,不支持 null 值和 null 键; - LinkedHashMap 是 HashMap 的一个子类,保存了记录的插入顺序; - TreeMap,能够把它保存的记录根据键排序,默认是键值的升序排序 {SortMap 接口 } ---------------------------------------------- ## spring ### ==Spring Springmvc 中的各种常用注解== @Controller,@Service、@Repository, @Autowired, @Resource,@RequestMapping,@RequestParam @ResponseBody @Required @Configuration ,@Bean,@Import ### ==ioc aop== > IOC - IoC(Inversion of Control)是指容器控制程序对象之间的关系 - 控制权由应用代码中转到了外部容器,控制权的转移是所谓反转 - 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系 - IoC还有另外一个名字——“依赖注入(Dependency Injection) - 所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。 - 依赖注入的思想是通过反射机制实现的 - IoC的优点:降低了组件之间的耦合,降低了业务对象之间替换的复杂性,使之能够灵活的管理对象。 - 依赖注入的三种方式 - 构造方法注入 - Setter注入 - 基于注解的注入 @Autowired > AOP - AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充 - AOP 要达到的效果是,保证开发者不修改源代码的前提下,去为系统中的业务组件添加某种通用功能。 - ![image.png](https://cos.easydoc.net/31477061/files/kmd8obh8.png) ### ==@Autowired @Resource== - @Autowired 自动按照类型注入 类型不唯一时,他会把属性名作为bean的id在容器中查找 - @Resource 使用属性name指定bean的id - @Resources按名字,是JDK的,@Autowired按类型,是Spring的。 @Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。 @Resource注解和@Autowired一样,也可以标注在字段或属性的setter方法上,但它默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。 ### ==Spring框架中都用了哪些设计模式== - 工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。 - 代理设计模式 : Spring AOP 功能的实现。 - 单例设计模式 : Spring 中的 Bean 默认都是单例的。 - 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。 - 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。 - 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。 - 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。 ### ==SpringMVC请求处理流程== (1)用户发送请求至前端控制器DispatcherServlet; (2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handler; (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响应用户。 > 总结 : - 用户向服务器发送请求 - DispathcerServlet接收请求找到具体的controller并执行 - controller执行完成返回ModelAndView - 前端控制器调用视图解析器解析ModelAndView返回具体的view - 渲染页面,响应给用户。 ### ==Spring-bean的循环依赖以及解决方式== - 什么是循环依赖? ![image.png](https://cos.easydoc.net/31477061/files/km5r69vh.png) - Spring 是如何解决的 其实很简单、在 Spring 获取单例流程(一) 中我们曾提及过三级缓存 > 这三级缓存分别指: singletonFactories : 单例对象工厂的cache earlySingletonObjects :提前暴光的单例对象的Cache singletonObjects:单例对象的cache Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取 如果获取到了则: 从singletonFactories中移除,并放入earlySingletonObjects中。 其实也就是从三级缓存移动到了二级缓存。 ---------------------------------------------- ## SpringBoot ### ==SpringBoot有哪些优点== 1、快速构建项目。 2、对主流开发框架的无配置集成。 3、项目可独立运行,无须外部依赖Servlet容器。 4、提供运行时的应用监控。 5、极大的提高了开发、部署效率。 6、与微服务的天然集成 ### ==SpringBoot的自动配置原理== Spring Boot的启动类上有一个@SpringBootApplication注解 @SpringBootApplication是一个复合注解或派生注解, 在@SpringBootApplication中有一个注解@EnableAutoConfiguration,开启自动配置。通过Import注解导入AutoConfigurationImportSelector。在这个类中加载/META-INF/spring.factories文件的信息,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能。 ---------------------------------------------- ## mysql数据库 - MyBatis ### ==数据库索引有哪几种类型?== - 主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。 - 唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。 - 普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。 - 全文索引:是目前搜索引擎使用的一种关键技术。 > 索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。索引的原理很简单,就是把无序的数据变成有序的查询 ![图片.png](https://cos.easydoc.net/31477061/files/kn1aphwt.png) ### ==索引的优点-缺点== - 优点 - 可以快速读取数据提高查询速度; - 可以保证数据记录的唯一性; - 可以加速表与表的连接 - 可以显著的减少查询中分组和排序的时间。 - 缺点 - 创建索引和维护索引需要时间,而且数据量越大时间越长 - 创建索引需要占据磁盘的空间,如果有大量的索引,可能比数据文件还要大。 - 当对表中的数据进行增加,修改,删除的时候,索引也要同时进行维护,降低了数据的维护速度 ### ==mysql 数据结构-及其他数据结构== - B+树 ==mysql采用的数据结构== - B+树相比B树,新增叶子节点与非叶子节点关系,叶子节点中包含了key和value,非叶子节点中只是包含了key,不包含value。 - b+树在b树的基础上增加了叶子节点,将所有的节点数据按一定的顺序使用链表连接, 从而范围查询效率非常高。 - Hash算法 - 哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。 - 也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 - 优点:查找可以直接根据key访问 - 缺点: 不能进行范围查找(因为底层数据结构是散列的,无法进行比较大小) - 二叉树算法 - 如何二叉树是将首次插入的作为根节点,将后面的值与根节点比较,小的在左边,大的在右边。 - 如果首次插入的根节点是最小的,就会造成查询效率变低,所以需要引入平衡二叉树。 - 平衡二叉树算法 - 优点:平衡二叉树算法基本与二叉树查询相同,效率比较高 - 缺点:插入操作需要旋转,支持范围查询(回旋效率低),且如果树的高度越高,查询IO的次数越多 - B树 - B树概括来说是一个节点可以拥有多于2个子节点的二叉查找树。与自平衡二叉查找树不同,B-树为系统最优化大块数据的读和写操作。B-tree算法减少定位记录时所经历的中间过程,从而加快存取速度。普遍运用在数据库和文件系统。 - 因为B树一个节点可以对应多个元素 ,是在平衡二叉树结构中减少了树的高度,所以B树数据结构相比平衡二叉树数据结构实现减少磁盘IO的操作,范围查询效率依然不高。 ### ==mysql性能优化调优== - 可以在建表的时候,为了获取更好的性能,将表中的字段长度设的尽可能的小。 - 尽可能的把字段设置成NOT NULL,这样在执行查询的时候,数据库不用去比较NULL值。 - 对于部分的文本字段,例如“性别”或者“民族”,我们就可以用enum(int)来定义 - 索引应建立在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。 - like语句操作like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。 - 不使用<>操作 id<>3可使用id>3 or id<3来代替。 ### ==SQL语句优化== - Where子句中:where表之间的连接必须写在其他Where条件之前,那些可以过滤掉最大数量记录的条件必须写在Where子句的末尾.HAVING最后。 - 避免在索引列上使用计算 - 避免在索引列上使用IS NULL和IS NOT NULL - 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。 - 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描 - 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描 - 把*改为前端所需要的字段名 - 模糊查询比如‘%xxx%’,因此该查询必然走全表扫描,除非必要,否则不要在关键词前加%。 - 用EXISTS替代IN、用NOT EXISTS替代NOT IN。 ### ==MyBatis 中 ${}和 #{}== - #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号 - $将传入的数据直接显示生成在sql中 - #方式能够很大程度防止sql注入 - $方式无法防止Sql注入。 - $方式一般用于传入数据库对象,例如传入表名. - 一般能用#的就别用$. ---------------------------------------------- ## redis ### ==redis数据结构== ![图片.png](https://cos.easydoc.net/31477061/files/kmkhi6qt.png) ---------------------------------------------- ## 线程 ### ==线程的创建方式有几种== 继承Thread类 实现Runnable接口、 实现Callable接口通过FutureTask包装器来创建Thread线程、 使用ExecutorService、Callable、Future实现有返回结果的多线程。 其中前两种方式线程执行完后都没有返回值,后两种是带返回值的。 ### ==sleep()和wait()有什么区别== - sleep 是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep 不会释放对象锁。 - wait 是Object 类的方法,对此对象调用wait 方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify 方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 - 相同点: - 这两个方法都能使线程进入阻塞状 - 不同点: - sleep()方法是Thread类中的静态方法;而wait()方法是Object类中的方法; sleep()方法可以在任何地方调用;而wait()方法只能在同步代码块或同步方法中使用(即使用synchronized关键字修饰的); 这两个方法都在同步代码块或同步方法中使用时,sleep()方法sleep 不会释放对象锁;而wait()方法则会释放对象锁; ### ==yield join== - yield进入等待就绪状态,和其他线程 重新抢cup运行资格。 - join等待该线程执行完毕后在执行。 ![image.png](https://cos.easydoc.net/31477061/files/kwu89sp3.png) ![image.png](https://cos.easydoc.net/31477061/files/kwu83w9c.png) ### ==sleep wait 区别== ![image.png](https://cos.easydoc.net/31477061/files/kwu7pn8q) ---------------------------------------------- ## 线程池 ### ==为什么用线程池== ![image.png](https://cos.easydoc.net/31477061/files/kx639f0y.png) ---------------------------------------------- ## 事务 ### ==Spring什么情况下事务会失效== - 事务只能应用于 public 方法。 - 当绕过代理对象, 直接调用添加事务管理的方法时, 事务管理将无法生效。在Service中添加@Transactional注解,好处是减少代码。 - 当在方法中使用try捕捉异常的时候 ---------------------------------------------- ## 异常Exception ### ==异常体系 Exception Error== ![image.png](https://cos.easydoc.net/31477061/files/kwu7hc87.png) ### ==常见异常== 1. java.lang.nullpointerexception 程序遇上了空指针,简单地说就是调用了未经初始化的对象或者是不存在的对象 2. java.lang.arithmeticexception 数学运算异常&quot;,比如程序中出现了除以零这样的运算就会出这样的异常 3. java.lang.arrayindexoutofboundsexception 异常的解释是&quot;数组下标越界&quot 4. 类型强制转换异常:ClassCastException 5. 文件未找到异常:FileNotFoundException 6. 字符串转换为数字异常:NumberFormatException 7. 操作数据库异常:SQLException 8. 输入输出异常:IOException 9. 方法未找到异常:NoSuchMethodException 10. java.lang.ClassFormatError类格式错误 ---------------------------------------------- ## HTTP TCP BIO、NIO、AIO ### ==简述 tcp 和 udp的区别?== - TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。 - TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。 - Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。 - UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。 - 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。 - TCP对系统资源要求较多,UDP对系统资源要求较少。 ### ==BIO、NIO、AIO 有什么区别== - BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。 - NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。 - AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。 ### ==三次握手的概念== - 总结 建立连接时,发送状态1,进入等待 服务器收到1,同时自己也发送一个状态2 客户端收到服务器的状态2,向服务器发送确认状态3 发送完毕,客户端和服务器(TCP 连接成功)状态,完成三次握手。客户端与服务器开始传送数据 - 第一次握手:建立连接时,客户端发送syn 包(syn=j)到服务器,并进入SYN_SENT 状态, 等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。 第二次握手:服务器收到syn 包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN 包(syn=k),即SYN+ACK 包,此时服务器进入SYN_RECV 状态; 第三次握手:客户端收到服务器的SYN+ACK 包,向服务器发送确认包ACK(ack=k+1),此包 发送完毕,客户端和服务器进入ESTABLISHED(TCP 连接成功)状态,完成三次握手。 完成三次握手,客户端与服务器开始传送数据 ### ==get 和 post 请求有哪些区别?== - GET参数通过URL传递,POST放在Request body中。 - GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。 - GET请求在URL中传送的参数是有长度限制的,而POST么有。 - GET请求只能进行url编码,而POST支持多种编码方式。 - GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。 - GET在浏览器回退时是无害的,而POST会再次提交请求。 - GET产生的URL地址可以被Bookmark,而POST不可以。 - GET请求会被浏览器主动cache,而POST不会,除非手动设置。 - 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。 ------------------------------------------------ ## jdk新特性 ### ==jdk1.8新特性== ![image.png](https://cos.easydoc.net/31477061/files/kxh5zw9g.png)