面试题目积累
ArrayList和LinkedList的区别
数据的更新和查找
ArrayList的所有数据是在同一个地址上,而LinkedList的每个数据都拥有自己的地址.所以在对数据进行查找的时候,由于LinkedList的每个数据地址不一样,get数据的时候ArrayList的速度会优于LinkedList,而更新数据的时候,虽然都是通过循环循环到指定节点修改数据,但LinkedList的查询速度已经是慢的,而且对于LinkedList而言,更新数据时不像ArrayList只需要找到对应下标更新就好,LinkedList需要修改指针,速率不言而喻数据的增加和删除
对于数据的增加元素,ArrayList是通过移动该元素之后的元素位置,其后元素位置全部+1,所以耗时较长,而LinkedList只需要将该元素前的后续指针指向该元素并将该元素的后续指针指向之后的元素即可。与增加相同,删除元素时ArrayList需要将被删除元素之后的元素位置-1,而LinkedList只需要将之后的元素前置指针指向前一元素,前一元素的指针指向后一元素即可。当然,事实上,若是单一元素的增删,尤其是在List末端增删一个元素,二者效率不相上下。
查看linux 服务进程号
ps -e|grep mysql
InnoDB与MyISAM的区别
MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持
MyISAM类型的表强调的是性能,其执行速度比 InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持以及外键等高级数据库功能
- InnoDB不支持FULLTEXT类型的索引,而MyISAM支持
- InnoDB 中不保存表的具体行数,也就是说,执行select count() from table时,InnoDB要扫描一遍整个表来计算有多少行,但- - 是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含 where条件时,两种表的操作是一样的
- 对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引
- DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,MyISAM里会重新建立表
- InnoDB支持行锁,MyISAM不支持。但InnoDB的行锁也不是绝对的,假如在执行一个SQL语句时MySQL不能确定要扫描的范围,- - -
- InnoDB- 表同样会锁全表,例如update table set num=1 where name like “%a%”
- MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少,能加载更多索引。而Innodb是索引和数据是紧密- 捆绑的,没有使用压缩从而会造成Innodb比MyISAM体积庞大不小
如何选择
MyISAM适合:
(1)做很多count 的计算;
(2)插入不频繁,查询非常频繁,如果执行大量的SELECT,MyISAM是更好的选择;
(3)没有事务。
InnoDB适合:
(1)可靠性要求比较高,或者要求事务;
(2)表更新和查询都相当的频繁,并且表锁定的机会比较大的情况指定数据引擎的创建;
(3)如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表;
(4)DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的 删除;
(5)LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
要注意,创建每个表格的代码是相同的,除了最后的 TYPE参数,这一参数用来指定数据引擎。
其他区别:
1、对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
2、DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
3、LOAD TABLE FROMMASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
4、 InnoDB存储引擎被完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。
5、对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引。
6、清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表。
Mybatis级连查询如何实现一对多
假设我要获取一个SysUser对象
public class SysUser { /** * 用户角色 */ private SysRole sysRole; // setter getter public SysRole getSysRole() { return sysRole; } public void setSysRole(SysRole sysRole) { this.sysRole = sysRole; } }
自动映射方式
<select id="selectSysUserAndSysRoleById" resultType="com.mybatis.xml.domain.SysUser"> SELECT u.id, u.user_name userName, u.user_password userPassword, u.user_email userEmail, u.user_info userInfo, u.create_time createTime, u.head_img headImg, r.id "sysRole.id", r.role_name "sysRole.roleName", r.enabled "sysRole.enabled", r.create_by "sysRole.createBy", r.create_time "sysRole.createTime" FROM sys_user u INNER JOIN sys_user_role ur ON u.id = ur.user_id INNER JOIN sys_role r ON ur.role_id = r.id WHERE u.id = #{id} </select>
使用resultMap配置一对一映射
<!-- 使用resultMap配置一对一映射 --> <resultMap id="userRoleMap" type="com.mybatis.xml.domain.SysUser"> <id column="id" property="id" /> <result property="userName" column="user_name" /> <result property="userPassword" column="user_password" /> <result property="userEmail" column="user_email" /> <result property="userInfo" column="user_info" /> <result property="headImg" column="head_img" jdbcType="BLOB" /> <result property="createTime" column="create_time" jdbcType="TIMESTAMP" /> <!-- sysRole相关的属性 --> <result property="sysRole.id" column="role_id"/> <result property="sysRole.roleName" column="role_name"/> <result property="sysRole.enabled" column="enabled"/> <result property="sysRole.createBy" column="create_by"/> <result property="sysRole.createTime" column="role_create_time" jdbcType="TIMESTAMP"/> </resultMap>
使用resultMap的asscociation或者 collection标签配置一对一映射
<resultMap id="classmap" type="com.jicheng.dto.TaskTestParams"> <id property="id" column="t_id" /> <result property="name" column="t_name" /> <result property="type" column="type" /> <!-- 一对多关联映射:collection --> <collection property="fileParams" ofType="com.jicheng.dto.FileTestParams"> <id property="id" column="s_id" /> <result property="name" column="s_name" /> </collection> </resultMap>
手动执行多次SQL
请求转发和重定向的区别
forward(转发):是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,因为这个跳转过程实在服务器实现的,并不是在客户端实现的所以客户端并不知道这个跳转动作,所以它的地址栏还是原来的地址.
redirect(重定向):
是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
转发是服务器行为,重定向是客户端行为。1、转发是在服务器端完成的,重定向是在客户端发生的;
2、转发的速度快,重定向速度慢;
3、转发是同一次请求,重定向是两次请求;
4、转发地址栏没有变化,重定向地址栏有变化;
5、转发必须是在同一台服务器下完成,重定向可以在不同的服务器下完成。
典型的应用场景:转发: 访问 Servlet 处理业务逻辑,然后 forward 到 jsp 显示处理结果,浏览器里 URL 不变
重定向: 提交表单,处理成功后 redirect 到另一个 jsp,防止表单重复提交,浏览器里 URL 变了
同步跟异步的区别
同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是出于阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。
异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。
Java实现同步的方式
使用synchronized
synchronized关键跟ReentrantLock一样,也支持可重入锁。但是它是一个关键字,是一种语法级别的同步方式,称为内置锁。
内置锁可以作用在方法上。它还可以作用到变量,静态方法上。
synchronized跟ReentrantLock相比,有几点局限性:
- 加锁的时候不能设置超时。ReentrantLock有提供tryLock方法,可以设置超时时间,如果超过了这个时间并且没有获取到锁,就会放弃,而synchronized却没有这种功能
- ReentrantLock可以使用多个Condition,而synchronized却只能有1个
- 不能中断一个试图获得锁的线程
- ReentrantLock可以选择公平锁和非公平锁
- ReentrantLock可以获得正在等待线程的个数,计数器等
ReentrantLock可重入锁
ReentrantLock可重入锁是jdk内置的一个锁对象。
可重入锁中可重入表示的意义在于对于同一个线程,可以继续调用加锁的方法,而不会被挂起。可重入锁内部维护一个计数器,对于同一个线程调用lock方法,计数器+1,调用unlock方法,计数器-1。
举个例子再次说明一下可重入的意思,在一个加锁方法execute中调用另外一个加锁方法anotherLock并不会被挂起,可以直接调用(调用execute方法时计数器+1,然后内部又调用了anotherLock方法,计数器+1,变成了2)
Condition条件对象
条件对象的意义在于对于一个已经获取锁的线程,如果还需要等待其他条件才能继续执行的情况下,才会使用Condition条件对象。
wait/notifyAll 方式
wait/notifyAll方式跟ReentrantLock/Condition方式的原理是一样的。
Java中每个对象都拥有一个内置锁,在内置锁中调用wait,notify方法相当于调用锁的Condition条件对象的await和signalAll方法。
ThreadLocal
ThreadLocal是一种把变量放到线程本地的方式来实现线程同步的。
比如SimpleDateFormat不是一个线程安全的类,可以使用ThreadLocal实现同步
Semaphore信号量
Semaphore信号量被用于控制特定资源在同一个时间被访问的个数。类似连接池的概念,保证资源可以被合理的使用。可以使用构造器初始化资源个数。
并发包下的工具类
CountDownLatch
CountDownLatch是一个计数器,它的构造方法中需要设置一个数值,用来设定计数的次数。每次调用countDown()方法之后,这个计数器都会减去1,CountDownLatch会一直阻塞着调用await()方法的线程,直到计数器的值变为0。
CyclicBarrier
CyclicBarrier阻塞调用的线程,直到条件满足时,阻塞的线程同时被打开。
调用await()方法的时候,这个线程就会被阻塞,当调用await()的线程数量到达屏障数的时候,主线程就会取消所有被阻塞线程的状态。
在CyclicBarrier的构造方法中,还可以设置一个barrierAction。
在所有的屏障都到达之后,会启动一个线程来运行这里面的代码。
AbstractQueuedSynchronizer
AQS是很多同步工具类的基础,比如ReentrentLock里的公平锁和非公平锁,Semaphore里的公平锁和非公平锁,CountDownLatch里的锁等他们的底层都是使用AbstractQueuedSynchronizer完成的。
jdk,jre,jvm的关系
- JDK 用于开发,JRE 用于运行java程序 ;如果只是运行Java程序,可以只安装JRE,无序安装JDK。
- JDk包含JRE,JDK 和 JRE 中都包含 JVM。
- JVM 是 java 编程语言的核心并且具有平***立性。
Object类有哪些方法?各有什么作用?
- finalize方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。 - equals方法
该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。 - hashCode方法
该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
如果不重写hashcode(),在HashSet中添加两个equals的对象,会将两个对象都加入进去。
- toString方法
该方法用得比较多,一般子类都有覆盖。 - wait方法
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
(1)其他线程调用了该对象的notify方法。
(2)其他线程调用了该对象的notifyAll方法。
(3)其他线程调用了interrupt中断该线程。
(4)时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
notify方法
该方法唤醒在该对象上等待的某个线程。notifyAll方法
该方法唤醒在该对象上等待的所有线程。clone方法
保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里讲参数改变,这是就需要在类中复写clone方法。
- getClass方法
final方法,获得运行时类型。
HashMap、ConcurrentHashMap、HashTable的区别
- HashMap线程不安全,key允许存在一个为null的值,
- Hashtable 线程安全,全表锁
- ConcurrentHashMap会基于并发的等级来划分整个Map来达到线程安全,它只会锁操作的那一段数据而不是整个Map都上锁,它不用做外的同步的情况下默认同时允许16个线程读和写这个Map容器,它划分了多个段(segments),要操作哪一段才上锁那段数据
谈谈对微服务的理解
将一个大型的系统,按照业务拆分成多个微服务,多个微服务之间互相不影响,独立部署,服务之间是解藕的,共同为系统服务。那么一起工作,微服务避免不了会有服务之间的通讯,还有服务通讯的格式,API网关,数据的去中心化,更好的去为系统去做服务。
spring boot如何解决跨域问题
- @CrossOrigin注解方式 Controller method CORS configuration
- 过滤器实现跨域 Filter based CORS support
- 全局CORS配置
转发跟重定向的区别
1、浏览器地址栏显示不同(表面区别):
无论进行多少次请求,如果使用请求转发来实现,浏览器地址栏中只显示第一次发送请求的地址;
如果使用重定向来实现,浏览器地址栏显示的是每次请求的新地址。这只是表面上看到的不同地方。
2、组件之间可否共享信息不同(本质区别)
从本质上讲,请求转发时,从发送第一次到最后一次请求的过程中,WEB容器只创建一次request和response对象,请求之间始终共享这两个对象,所以每个请求可以访问他之前请求中的参数和属性的值;
而重定向时,浏览器每发送一次请求,WEB容器都会重新创建新的request和response对象,所以请求之间不能共享信息,即不能在请求中访问到他之前请求中的参数和属性的值。
SpringMVC的流程
(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响应用户。
Aop,IOC,DI
IOC
IOC是指在程序开发过程中,对象实例的创建不再由调用者管理,而是由Spring容器创建,Spring容器会负责控制程序之间的关系,而不是由代码直接控制,因此,控制权由程序代码转移到了Spring容器,控制权发生了反转,即控制反转。
Spring IOC提供了两种IOC容器,分别是BeanFactory和ApplicationContext。
依赖注入(DI)
依赖注入和控制反转含义相同,他们是从两个角度描述同一个概念。
当某个对象实例需要另外一个对象实例时,传统的方法是由调用者创建被调用者的实例,比如使用new,而使用Spring框架后,被调用者的实例不再有调用者创建,而是交给了Spring容器,者称为控制反转。
Spring容器在创建被调用实例时,会自动将调用者需要的对象实例注入为调用者,这样,通过 Spring容器获得被调用者实例,成为依赖注入。
以来注入方法:
- 属性setter注入
- 构造构造器注入
- 静态工厂方式实例化
- 实例工厂实例化
AOP概述
- AOP和OOP类似,也是一种编程模式,Spring AOP是基于AOP编程模式的一个框架,它的使用有效减少了系统间的重复代码,达到了模块间解耦的作用。
- AOP的全程是"Aspect Oriented Programming",即面向切面编程,它将业务逻辑的各部分进行隔离,使开发人员在编写业务逻辑时可以专心核心业务,从而提高开发基础。
- AOP采取横向抽取机制,取代了传统的纵向继承体系,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。
- 目前最流行的AOP有Spring AOP和AspectJ
- Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类植入增强的代码。
- AspectJ是一个基于Java语言的AOP框架,从Spring2.0开始,Spring AOP引入了对AspectJ的支持。
AOP相关术语
名称 | 说明 |
---|---|
Joinpoint(连接点) | 指那些被拦截到的点,在Spring中,可以被动态代理拦截目标类的方法 |
Pointcut(切入点) | 指要对哪些Joinpoint进行拦截,即被拦截的连接点 |
Advice(通知) | 指拦截到Joinpoint之后要做的事情,即对切入点增强的内容 |
Target(目标) | 指代理的目标对象 |
Weaving(植入) | 指把增强代码应用到目标上,生成代理对象的过程 |
Proxy(代理) | 指生成的代理对象 |
Aspect(切面) | 切入点和通知的结合 |
spring boot启动流程
spring bean生命周期
什么时候用抽象什么时候用接口?
抽象类允许部分实现类,而接口不包含任何成员的实现。接口关心行为,抽象关心的是事物
- 提供通用的已实现功能,则使用抽象类
- 控件之间的联系关联性并不大,定义一些通用的功能,需要经常修改的,可以使用接口,创建一个接口就是在创建一个定义,接口定义发布后则永远不能更改。接口不变性,就是为了保护为使用接口而编写的现有系统。
实现共有的功能,再加以拓展。而接口,实现一些通用的功能,大家方法都一样,但是可能具体实现的逻辑是不一样的。就比如我一个模版证书,他们的样式都是一样的,但是有多个不同的模版,而每个模版有他们各自其他的特点,那么可以使用抽象类。那如果是那种关联性不大的,比如不同的模版他们的生成方式不一样,有各自实现的,那么可以使用接口