面经资料来源:http://www.nowcoder.com/discuss/3836
阿里实习 Java研发 一面
加载一个类的过程:加载->链接(验证,准备,解析)->初始化
双亲委派模式的方法:向上不断查看是否加载了类(findLoadedClass()),向下尝试加载类(loadClass()),自定义类加载器需要回调(findClass())。
具体请参考Blog Java类装载过程与类装载器
在JDK1.7及以前,HashMap中维护着Entry,Entry中维护着key,value以及hash和next指针,而整个HashMap实际就是一个Entry数组
当向 HashMap 中 put 一对键值时,它会根据 key的 hashCode 值计算出一个位置, 该位置就是此对象准备往数组中存放的位置。
如果该位置没有对象存在,就将此对象直接放进数组当中;如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找(为了判断是否是否值相同,map不允许<key,value>键值对重复), 如果此链上有对象的话,再去使用 equals方法进行比较,如果对此链上的每个对象的 equals 方法比较为 false,则将该对象放到数组当中,然后将数组中该位置以前存在的那个对象链接到此对象的后面。
get方法类似,通过key取hash找到数组的某个位置,然后遍历这个数组上的每个Entry,直到key值equals则返回。
如果Hash碰撞严重,那么JDK1.7中的实现性能就很差,因为每次插入都要遍历完整条链去查看key值是否重复,每次get也要遍历整个链,在JDK1.8中,由于链表的查找复杂度为O(n),而红黑树的查找复杂度为O(logn),JDK1.8中采用链表/红黑树的方式实现HashMap,达到某个阀值时,链表转成了红黑树。
具体请参考 JDK7与JDK8中HashMap的实现
HashMap不是线程安全的,ConcurrentHashMap是线程安全的,HashMap内部维护着一个Entry数组,而ConcurrentHashMap内部有一个Segment段,它将大的HashMap切分成若干个段(小的HashMap),然后让数据在每一段上Hash,这样多个线程在不同段上的Hash操作一定是线程安全的,所以只需要同步同一个段上的线程就可以了,这样实现了锁的分离,大大增加了并发量。ConcurrentHashMap的实现中还使用了不变模式final和volatile来保障线程安全
具体请参考 ConcurrentHashMap原理分析
传统的进程间通信的方式有大致如下几种:
(1) 管道(PIPE)
(2) 命名管道(FIFO)
(3) 信号量(Semphore)
(4) 消息队列(MessageQueue)
(5) 共享内存(SharedMemory)
(6) Socket
Java如何支持进程间通信。我们把Java进程理解为JVM进程。很明显,传统的这些大部分技术是无法被我们的应用程序利用了(这些进程间通信都是靠系统调用来实现的)。但是Java也有很多方法可以进行进程间通信的。
除了上面提到的Socket之外,当然首选的IPC可以使用Rmi,或者Corba也可以。另外Java nio的MappedByteBuffer也可以通过内存映射文件来实现进程间通信(共享内存)。
虚拟机将所管理的内存分为以下几个部分:
具体请查看 Java内存区域
JVM通过可达性(可触及性)分析算法标记出哪些对象是垃圾对象,然后将垃圾对象进行回收,在新生代中采用复制算法,在老年代中采用标记清理或标记压缩算法。新生代存储了新new出的对象,老年代存储了大的对象和多次GC后仍然存在的老年对象,持久代存储了类信息,常量(JDK7中String常量池被移到堆中),静态变量(JDK7中被移到了Java堆),类方法
具体请查看 JVM 垃圾回收机制 , Java内存区域
总体来说就是,全局中的引用(例如常量或者静态属性)与执行上下文(例如栈帧中的本地变量表)。
具体请查看 JVM 垃圾回收机制快排的基本思想是:
1.先从数列中取出一个数作为基准数(pivot)。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
平均复杂度O(NlogN),最差O(N^2),最好O(NlogN)具体请查看 排序总结(不断更新)
二叉平衡树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
AVL树的插入和删除,主要是依靠左旋和右旋来达到平衡状态。
红黑树的插入,插入节点是红色,通过一系列选择和着色使其成为红黑树。
步骤为:
所以红黑树的插入需要最多两次旋转,删除需要最多三次旋转
具体请查看 红黑树
给定一个单链表,只给出头指针h:
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?
解法:
1、对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
2、对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。
3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。
4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度
1. http://www.importnew.com/7010.html
2. http://www.cnblogs.com/flyingwind/archive/2012/10/24/2737204.html