阿里电面
1、HashMap的底层实现?
答:
· 底层实现:通过数组+链表实现的。底层是一个线性数组,数组元素是Entry静态内部类,Entry中存储的是key-value对,持有一个指向下一个元素的引用next,数组中的每一项是一个链表。底层数组长度默认为16,负载因子为0.75,所以元素最大容量是16*0.75=12,当超过这个阈值,则开始扩容,翻倍。
· 两次hash:第一次是hashCode值,第二次是根据hashCode值对数组长度取模得到索引位置。
· 存放规则:若通过hash出的索引处位置不为null,通过循环遍历链表,equals()方法查询比较链表中是否有相同对象,若无,则通过addEntry()方法放在该索引位置,并让新对象的next引用指向原对象;若相同,则覆盖原来的对象,并返回旧值。
· hash冲突解决:链表法是用来解决hash冲突问题,是单向链表,
2、Hibernate的一级缓存和二级缓存的区别:
答:
一级缓存:Session级别的缓存;二级缓存:SessionFactory级别的缓存;
概念:
· (1)一级缓存就是Session级别的缓存,是事务范围的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么hibernate直接从一级缓存中拿,而不会再去连数据库,取数据;
· (2)二级缓存就是SessionFactory级别的缓存,是进程范围或集群范围的缓存,就是查询的时候会把查询结果缓存到二级缓存中,如果同一个sessionFactory创建的某个session执行了相同的操作,hibernate就会从二级缓存中拿结果,而不会再去连接数据库;
· (3)Hibernate中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存由hibernate管理的,一般情况下无需进行干预;第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载。 Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存;
比较:
· (1)一级缓存不会出现并发问题,因为是每个事务单独享有一级缓存;二级缓存存在并发问题,是进程范围或集群范围,由于多个事务会同时访问二级缓存中相同数据。
· (2)一级缓存中对象永远不会过期,除非显式清空缓存或提供数据过期策略(缓存最大时长)来清除特定的对象;
二级缓存应用场景:
· 什么样的数据适合存放到第二级缓存中?
· 1) 很少被修改的数据
· 2) 不是很重要的数据,允许出现偶尔并发的数据
· 3) 不会被并发访问的数据
· 4) 参考数据,指的是供应用参考的常量数据,它的实例数目有限,它的实例会被许多其他类的实例引用,实例极少或者从来不会被修改。
·
· 不适合存放到第二级缓存的数据?
· 1) 经常被修改的数据
· 2) 财务数据,绝对不允许出现并发
· 3) 与其他应用共享的数据。
Hibernate的二级缓存
· Hibernate提供了两级缓存,第一级是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法比卸除。在第一级缓存中,持久化类的每个实例都具有唯一的OID。
· 第二级缓存是一个可插拔的的缓存插件,它是由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与Hibernate集成。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。
Hibernate的二级缓存策略的一般过程如下:
· 1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
· 2) 把获得的所有数据对象根据ID放入到第二级缓存中。
· 3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
· 4) 删除、更新、增加数据的时候,同时更新缓存。
· Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query缓存。
Hibernate的Query缓存策略的过程如下:
· 1) Hibernate首先根据这些信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。
· 2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。
· 3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。
3、什么情况触发Full GC?
最直接的是System.gc的调用。
· 1.老年代空间不足;
· 2.永久代的空间满;
· 3.CMS GC时出现promotion failed和concurrent mode failure;
· 4.统计得到的Minor GC晋升到老年代的平均大小大于老年代的剩余空间;
promotion failed:是指survivor space放不下对象,只能放入到老年代,而老年代也放不下,导致担保失败。
Concurrent Mode Failure:CMS收集器无法处理浮动垃圾,可能出现"Concurrent Mode Failure"失败(备选用Serial Old)而导致另一次Full GC的产生;
涉及到对象分配规则:
· 1.对象优先分配在Eden区(如果Eden区没有足够的内存,VM执行一次Minor GC);
· 2.大对象直接进入老年代(避免在Eden区和两个Survivor区之间发生大量的内存拷贝);
· 3.长期存活的对象进入老年代(VM为每个对象定义一个年龄计数器,若对象经过一次Minor GC,则对象进入Survivor区,之后每经过一次Minor GC,年龄加1,当到达阈值时,对象进入老年代);
· 4.动态判断对象的年龄(若Survivor区中相同年龄的所有对象的大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代);
· 5.空间分配担保(每次进行Minor GC时,JVM计算Survivor区移至老年代的对象的平均大小,若这个值大于老年代的剩余值大小,则VM查看HandlePromotionFailure设置值是否允许担保失败进行一次Full GC)
4、JVM内存参数设置
答:
· -Xmx (堆内存最大值)Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定;
· -Xms (堆内存初始值)Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值;
· -Xmn (堆年轻代大小)Java Heap Young区大小,不熟悉最好保留默认值;
· -Xss (栈内存大小)每个线程的Stack大小,不熟悉最好保留默认值;
5、***设计模式,实现及应用场景。
***模式:
定义:给某个对象创建一个***对象,由这个***对象控制对原对象的引用,而创建这个***对象可以在调用原对象时可以增加一些额外的操作。
分类:远程***、虚拟***、保护***、智能引用***
应用:Spring AOP中JDK动态***;
6、Mysql的分页查询怎么实现?
答:LIMIT [offset,] rows
SELECT * FROM table LIMIT offset, rows; #表示返回第offset+1行~rows行的数据。
通过LIMIT子句可以用来限制由SELECT语句返回过来的数据数量,有一个LIMIT rows或两个参数(LIMIT offset, rows),如果给出两个参数,则第一个参数指定返回的第一行在所有数据中的位置,从0开始(就是返回初始的位置,相对于0来说,需要加1),第二个参数指定最多返回的行数。
最基本的分页方式:SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT ...
一:分页需求:
客户端通过传递start(页码),limit(每页显示的条数)两个参数去分页查询数据库表中的数据,那我们知道MySql数据库提供了分页的函数limit m,n,但是该函数的用法和我们的需求不一样,所以就需要我们根据实际情况去改写适合我们自己的分页语句,具体的分析如下:
比如:
查询第1条到第10条的数据的sql是:select * from table limit 0,10; ->对应我们的需求就是查询第一页的数据:select * from table limit (1-1)*10,10;
查询第11条到第20条的数据的sql是:select * from table limit 10,20; ->对应我们的需求就是查询第二页的数据:select * from table limit (2-1)*10,10;
查询第21条到第30条的数据的sql是:select * from table limit 20,30; ->对应我们的需求就是查询第三页的数据:select * from table limit (3-1)*10,10;
1. select * from table LIMIT 5,10; #返回第6-15行数据
2. select * from table LIMIT 5; #返回前5行
3. select * from table LIMIT 0,5; #返回前5行
二:通过上面的分析,可以得出符合我们自己需求的分页sql格式是:select * from table limit (start-1)*limit,limit; 其中start是页码,limit是每页显示的条数。
select * from table limit (start - 1)* limit, limit
其中start是页码,limit是每页显示的条数。
7、什么是动态树?平衡二叉树(AVL)和红黑树
8、什么是数据库的左连接和右连接?
答:右连接:right join或right outer join,以右边的表为准进行联合查找;
左连接:left join 或 left outer join 以左边的表为准进行联合查找;
全连接:full join 或 full outer join
内连接:inner join 或join
交叉连接:cross join 不带where条件
9、观察者模式:
定义:定义对象间的一种一对多的依赖关系,发布——订阅模式,让多个观察者同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能自动更新自己。(Subject主题、ConcreteSubject具体主题、Observer抽象观察者、ConcreteObserver具体观察者)
应用:触发联动,Tomcat中控制组件生命周期的Lifecycle就是观察者模式,以及对Servlet实例的创建,Session的管理,如抽象主题Lifecycle接口,具体主题StandardServer,抽象观察者LifecycleListener,具体观察者ServerLifecycleListener。
10、实习是做什么的?有什么难点?
11、事务的四大特性和隔离级别的理解?
12、Spring中的IOC实现方式?
13、JVM用过哪些优化?