3

一次惨痛的阿里技术面

就在昨天,有幸接到了阿里的面试通知,本来我以为自己的简历应该不会的到面试的机会了,然而机会却这么来了,我却没有做好准备,被面试官大大一通血虐。因此,我想写点东西纪念一下这次的经历,也当一次教训了。其实面试官大大问的问题我也都听说过,却知其然不知其所以然。在这里就整理一下了。

1. JAVA中的容器用过那些?

  本人不才,用过的也就ArrayList、LinkedList、HaseSet、HashMap这几个。然后面试官大大就问了,ArrayList和LinkedList的区别是啥呀,我心想不就是数组和链表的区别吗,自己还手写过这玩意,就简单说了一说,发现还真的不知道说啥,特此整理一下。
  ArrayList和LinkedList的区别大致来源于内部的实现:
  前者是基于可变长数组的,数组的特性就是连续存储的,可以方便的根据下标去查询数据,根据下标去修改数据,而如果插入数据的话,插入到中间的话,这条数据之后的数据都需要后移,因此效率比较低,而且数组增长的时候,需要创建新的一个数组,并将数据拷贝一份,也会影响性能。
  后者是基于双向链表的,链表的特性就是不连续的,根据下标去查询的话,需要移动链表的指针,必然会导致效率的降低,而数据的插入却方便了很多,只需要修改那条数据的指针即可实现数据的插入。
  除了这一个,还问了HashSet和HashTable的区别(ps:what?什么是HashTable,没见过呀,当时就没答上来),后面查了一些东西才知道,HashTable就是和HashMap类似的东西,而且这玩意几乎是面试必考的东西(ps:后悔没有好好准备了),这里就记录下HashSet、HashMap以及HashTable的区别。
  * HashSet:set的实现类,内部使用HashMap存放数据,数据不允许重复,这玩意就是他添加元素的实现啦

public boolean add(Object o) {
    return map.put(o, PRESENT)==null;
}

  * HashMap:map的一个实现类,内部的方法在默认情况下是非同步的。HashMap可以视为数组和链表的结合体,而他的内部可以分为三部分:key的Set,value的Collection,Entry的Set,HashMap的存储就是根据key的hash值找到元素的位置,统一位置的数据按链表的形式存储,新加入的在链头,后加入的在链尾。
  * HashTable:继承自Dictionary,同样实现了Map的接口,HaseTable的方法是同步的,而且HashTable中的key和value都不允许null值。在HashMap中可以出现一个唯一的null主键,因此HashMap中get()返回空时不代表不存在,需要使用containsKey()方法判断。HashMap和HashTable都使用了iterator,同时HashTable也使用了Enumeration的方式。HashTable中直接使用了对象的hashcode,HashMap重新计算了hash值。

Java中集合的整理

是否有序 是否可重复 线程安全性
Vector 安全(同步集合类)
List 不安全
CopyOnWriteArrayList 读写分离,并发集合,数据最终一致,没有实时一致性
AbstractSet 不安全
HashSet 不安全
TreeSet 是(二叉树) 不安全
CopyOnWriteHashSet 读写分离,并发集合,数据最终一致,没有实时一致性
AbstractMap 使用key-value来映射和存储数据,Key必须惟一,value可以重复 不安全
HashMap 同上 不安全
TreeMap 是(二叉树) 同上 不安全
HashTable 同上 安全(同步集合类)
ConcurrentHashMap 同上 并发集合,采用可重入锁

2.JAVA中的ThreadPool的最大和最小进程数怎么确定的?

当时遇到这个问题直接蒙圈了,这东西的我一般最大值设置为cpu线程数+1,还真的没研究过到底怎么设置的,说白了就是只会拿来用,没有深入了解他的机制,所以面试完了,还是回来查查资料记录下吧。

  图片描述

简单来说就是cpu核心数cpu利用率(1+等待时间/计算时间)。因此,如果是IO密集型的任务,就分配多一点咯,至于多少吗,可以自己在服务器上测下,如果懒得测,直接取极端情况,cpu利用率100%,等待时间和计算时间一致,也就是直接取到2Ncpu左右。如果是运算密集型的话,可以直接取等待时间为0,也就是Ncpu。其实这只是比较懒的做法,尽量还是在服务器上测试下更好。

3.JAVA中的gc机制是怎么样的?

当听到这个问题的时候,感觉自己还是太年轻呀,没有深入的去了解这些东西,只是简单的看过,仅此而已。后悔自己没有好好的研究这些了,所以只是简单的回答当对象用不到的时候,由虚拟机自己负责回收。那么问题来了,对象什么时候用不到,怎么判断用不到了呢。
这里只是做些简单的记录,等有时间的时候在深入的去研究吧,毕竟大三狗,考研党。
gc的方法:引用计数算法、根搜索算法、标记/清除算法、复制算法、标记/整理算法

4.JAVA中的内存管理,堆和栈的区别?

这一块我只知道一些简单的知识,内存中的栈就是存放基本类型的变量和对象的引用变量,堆用来存放由new创建的对象和数组。深入的知识只能查资料咯。
  Java把内存分成两种,一种叫做栈内存,一种叫做堆内存
在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。
  堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。
  引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!


zorpan
41 声望14 粉丝

记笔记