个人总结
难度中等,Java的基础部分有点忘了,还有那个token的实现流程也有点给忘了,项目问的比较少,还是要注重Java基础部分的复习。
1.jdk8和jdk7有什么区别呢?
- jdk8的新特性主要就是流式编程和lambda,区别上主要就是源码的优化,我比较了解的就是hashMap的底层优化。
- 在jdk7时,hashMap解决hash冲突主要就是通过拉链法来解决的,也就是通过链表来解决的,缺点很明显,在hash冲突多的时候就会出现斜树的问题,事件复杂度为O(N),在jdk8之后就是使用链表+红黑树来解决hash冲突的问题。在链表的长度大于等于8且hash数组的容量大于等于64的时候将链表转换为红黑树,将时间复杂度控制在O(logN)。
- 还有一个就是在jdk7的时候hashMap进行扩容的时候会存在死锁的问题。在进行链表插入的时候使用头插法。因为在扩容的时候涉及到数组数据的移动赋值,当两个线程同时进行移动赋值的时候,链表就会出现闭环的问题,在jdk8之后就使用尾插法来解决这个死锁的问题。
2.你刚刚说到hashMap扩容死锁的问题,解释一下闭环是怎么现成的呢?
我就举个例子,现在我们有两个现线程都要去进行移动赋值,当前链表中有数据A和B,有两个指针分别指向当前节点及下一个节点。线程一先进行赋值的操作,因为头插法的实现,导致B指向A,在线程2进行头插法的时候就会出现死循环,最终导致死锁的问题。
3.==和equals的区别?
equals是String中实现判断相等的方法,==主要就是去判断实例的引用地址是否相同,而equals主要就是判断两个实例中数据的值是否相等,无效考虑地址的问题。在执行速度上==的速度会快很多,因为只需要判断引用地址即可。
4. 重写和重载的方法有什么区别?
- 作用域方面,重写方法主要就是发生在子类去继承接口时,而重构方法主要发生在同一个类中。
- 在格式方面,重写方法必须保证方法的返回类型,形参,返回类型相同,但是当抽象方法的被final或者static修饰的时候不能别重写。而重构方法只需要保证方法的名字相同。
*5.接口和抽象类有什么区别?
- 在方法的编写方面,接口中只能编写抽象的方法,而在抽象接口中既可以编写抽象方法也可以编写普通的方法。
- 在类的继承和实现方面,接口可以同时继承多个接口,抽象方法只能继承一个类但是可以同时实现多个就接口。
- 在类定义变量的方面,抽象类可以定义普通的变量,接口只能定义的静态变量,在接口的抽象方法中,如果该抽象方法被final或static修饰的话就不能被实现。
*6.final关键值的作用?
- 当final修饰类的时候,该类从创建到销毁的整个过程变量的值都不会发生改变。
- 当final修饰形参的时候,该形参的引用在方法中执行的整个过程中都不会发生改变。
- 当final修饰方法的时候,在该类被继承或者接口被实现的时候都不能被重写。
- 当final修饰类的时候,说明该类不能被继承。
7.set和List有什么区别?
- 从结构方面,set存储无序不重复的集合,List存储有序的集合。
- 从实现类方面,set主要的实现类就是HashSet,而List主要的实现类就是ArrayList和LinkedLIst。
- HashSet的底层结构主要就是HashMap,基于hash表+链表+红黑树实现的,在扩容的时候会扩容为原来的2倍,而ArrayList的底层使用动态数组实现的,在扩容的时候扩容为原来的1.5倍。
8.有了解过线程周期吗?
在线程线程刚刚创建的时候就是新建状态。在线程执行任务的时候就是可执行状态,当线程获取锁失败的时候就是堵塞状态,在线程调用wait方法就是等待状态,当线程调用sleep方法的时候就是计时等待状态,在线程进行销毁的时候就是终止状态。
9.什么是死锁有了解过吗?
最常见的死锁就是线程间获取锁的死锁问题,现在有两个线程和两个锁A,B,线程一获取到A锁,线程二获取到B锁,两者都需要获取对方的锁,但是呢,双方都没有进行先进行解锁导致相互等待,最终导致死锁问题的发生,当然像我前面说的hashMap在jdk7之前也存在扩容死锁的问题。
10.单例和多例有了解过吗?
单例模式最典型的实现就是ioc容器,在每次回去容器中实例类的时候,这个类默认就是一个单例,也就是该类是同一个类。当然ioc也可以通过scope设置为多例模式,也就是在每次获取实例类的时候会新建一个类返回。
11.反射有了解过吗?
- 我们可以通过反射获取类的实例,并且可以越过有效范围的限制,破坏了封装性。可以通过反射获取类的所有方法及属性,还可以回去注解的所有属性。
- 获取反射的主要方法就是:1.类.class。2. 类实例.getclass方法。3.class.getName方法4.保证类.TYPE属性5.classLoader.loadClass方法。
12.spring有哪些常用的注解?
spring主要的思想就是ioc和aop, ioc中的注解主要就是@Bean,@AutoWried,@Qualify,@Component。aop的主要注解就是@Aspect。@Before,@After,@Around等通知方式。
13.RestController和Controller的区别?
RestContrller的底层实现就是通过@Controller和@ReponseBody。
*14.Spring的核心配置文件是什么?
主要的配置文件就是applicationContext.xml,主要就是用来配置数据库连接,ampper的映射,spring容器的配置等等。
15.ORM框架有了解过吗?
我主要使用的ORM框架就是mybatis,JPA之前做项目的时候也有使用过。主要激素通过mapper.xml文件编写SQL语句来访问数据库,目前我的项目中主要使用的就是mybatis-plus编写Dao层。
16.你刚刚说到Mybatis,那你对mybatis的执行流程有了解过吗?
- 读取mybatis-config.xml的配置文件。
- 创建sqlSession工厂,也就是创建会话工厂。
- 通过工厂创建sqlSession,sqlSession中包含访问数据库的读写方法。
- 在SqlSession中Excutor负责执行操作数据库的接口。
- 在Excutor中有个属性叫做MapperStatement负责将从数据库到java的类型转化及从java到数据库的类型转换。最终操作数据库。
*17.Mysql有哪些引擎?
主要的就是三个存储引擎,Myisam,Innodb,Memory。
- Myisam只支持表级锁,索引的的底层采用B+树结构,不支持事务。存储的结构以.sdi存储表结构,.myi存储索引,.myd存储数据。
- Innodb目前mysql默认的存储引擎,索引的底层结构使用B+树结构,支持表级锁和行级锁,支持事务的处理,存储结构以.idb结尾的文件存储数据,索引,表结构。
- Memory存储引擎底层就是使用当前内存来进行存储,存储的结构以.sdi存储表的结构。
18.索引的作用是什么?
我们可以把索引理解成目录,通过目录我们就可以快速的定位数据的位置,索引也是如此。主要的作用就是加快我们的查询速度。
19.索引有哪些类型?
唯一索引:在表中只能唯一存在。主键索引:也就是主键最带的索引。全文索引。
我比较了解的索引就是聚簇索引和非聚簇索引。二者索引都是使用B+树为底层结构的。区别就是聚簇索引在叶子节点上存储的数据是一整条的数据,而非聚簇索引在叶子节点上主要存储的主键id,以此如果使用到非聚簇索引进行查询的时候,会使用主键id到聚簇索引中查询出现回表的操作。
20.为了加快sql的查询速度,索引添加到哪比较合适?
- 我们需要保证字段数据的唯一性,不建议对名字,岁数这种字段添加索引,一般推荐对id这种唯一的字段添加索引。当要对长字符串数据或Text数据添加索引的时候可以使用全文索引。
- 也并不是说添加越多索引查询就越快,在进行写操作的时候我们也需要花费时间成本来维护索引。
- 在添加索引的时候我们需要避免索引失效的问题,实现覆盖索引的效果,避免回表的发生。
- 在进行对大数据的分页查询的时候我们可以使用 子查询+覆盖索引来优化速度。(先通过范围查询除id主键的集合,通过id集合作为子查询条件查询对应的所有数据)
21.git有哪些常用的指令?
最常用的就是克隆:git clone ,拉取最新的代码:git pull,将当前的代码添加到缓存中:git add *
将代码进行提交:git commit "注释", 将代码进行推送:git push。
22.git分支管理,如何将别人的远程推送的代码合并到自己的上面?
主要就是通过git pull将远程的代码同步到本地,用户进行手动处理冲突的位置。
23.项目中登录流程校验是怎么实现的呢?
我做的项目中,主要有两种实现方式:通过gateway的全局拦截器进行校验和双token三认证的实现方式。那个我给您介绍一下两种方案的实现流程,您看行吗?
在实习项目中,主要就是基于springSecurity+jwt实现的,请求进入gateway的全局拦截器中,拦截器会去解析token,在解析成功后将userid存放到请求头中,将请求路由到对应的微服务模块中,这里有一个细节就是,我们会在每个微服务中编写一个公共的全局拦截器会将请求头中的userId存储到threadLocal共远程调用的时候使用。(jwt主要就是三个部分 头部,参数体,签名,签名通过头部 + 参数体使用Base64生成对应的签名)
在我的物流微服务项目中就是基于双token三认证实现的校验 ,token分为长token和短token,短token用来进行进行校验长token用来生成新的短token和长token,且会将其存储到redis中,长token只能使用一次。三校验分别是:校验短token是否有效为第一校验,如果无效就校验长token是否有效这就是第二次校验,有效的话就会去redis中判断长token是否被使用过这个是第三次校验。最终生成新的长短token。(token的生成主要就是通过自定义的私钥生成的)
public static String createToken(String subject)
{
return Jwts.builder()
.setSubject(subject)
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
*23.token是由哪个包实现的呢?
我项目中的token主要都是使用jwt生成的,就是jwt包,使用的步骤就是建立一个根据类自定义个生成token的方法,通过对应的参数,加密算法,密钥就可以生成对应的token,在token进行解析的时候提供密钥和token就可以获得对应的参数。
//token生成方法
String tokrn = Jwts.builder()
.setSubject(subject)
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
//token解析方法
Object body = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();