强引用 、软引用、 弱引用、虚引用?
一般面试官会这样问:你知道Java中对象的引用类型有哪几种吗?分别讲讲这几种之间的区别?
强引用:只要强引用还存在,垃圾收集器永远不会回收被引用的对象;
软引用:描述一些还有用但是并非必需的对象,将要发生内存溢出之前,会被列进回收范围之中进行第二次回收,如果在此次回收中还是没有足够的内存,就会抛出内存溢出异常(SoftReference);
弱引用:只能存活到下一次垃圾回收之前,当垃圾收集器回收时,无论当前内存是否足够,被弱引用关联的对象都会被回收掉;
虚引用:最弱的一个引用类型,完全不会影响其生存时间,可以理解为没有引用一样,但是又有点区别,区别在于,弱引用关联的对象在被收集器回收的时候能收到一个系统回收通知;
浅拷贝和深拷贝的区别?
浅拷贝:源对象和副本对象是同一个对象,源对象(副本对象)引用计数器+1,只是拷贝了源对象的引用;
深拷贝:源对象和副本对象是不同的两个对象,源对象引用计数不变,副本对象计数器为1,相当于重新开辟一块内存生成一个新的对象;
Java中的值传递和引用传递?
值传递是指对象被值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象;
引用传递,意味着传递的并不是实际的对象,而是对象的引用;
Java中覆盖和重载的理解?
覆盖(Override)是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问权限不能比父类的小;
重载(Overload)表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同;
那么构成重载的条件有哪些?
参数类型不同、参数个数不同、参数顺序不同;
函数的返回值不同可以构成重载吗?
不可以,Java中调用函数并不需要强制赋值,根据方法的返回值是无法来区分重载方法的;
HashMap和Hashtable的区别?
HashMap没有同步,是线程不安全的,Hashtable通过使用synchronized关键字来保证了线程安全;
HashMap允许null作为key,而Hashtable是不允许的;
List 和 Set 的区别?
List:可以允许重复的对象、可以插入多个null元素
- 有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的 顺序
- 常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适
Set:不允许重复对象、只允许一个 null 元素
- 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序
- Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器
HashSet 是如何保证不重复的?
在向hashSet中add()元素时,判断元素是否存在的依据,不仅仅是hash码值就能够确定的,同时还要结合equles方法:
-
如果hash码值不相同,说明是一个新元素,存
-
如果hash码值相同,且equles判断相等,说明元素已经存在,不存
-
如果hash码值相同,且equles判断不相等,说明元素不存在,存
ArrayList、LinkedList和HashMap默认空间是多少?什么时候会扩容?如何扩容?
ArrayList:默认大小为10;新增元素时发现容量不够就会去扩容,扩容后的大小= 原始大小+原始大小/2 + 1;
LinkedList:双向链表,没有默认大小也没有扩容机制;
HashMap:默认空间大小为16,扩容因子为0.75;当当前大小和当前容量 的比例超过了扩容因子,就会扩容,也就是说不会等到空间全部用完就会扩容,扩容后大小为1倍即32,但是HashMap的扩容机制不是很友好,它是在存入数据之后进行判断是否需要扩容,如果下次不会再有元素被存入,就会进行一次无效的扩容;
HashMap的底层原理了解吗?
JDK1.8之前HashMap底层结构是数组+链表实现的,当hash碰撞严重的时候就会导致个别位置链表长度过长,从而影响性能;所以JDK1.8开始HashMap底层结构改为数组+链表+红黑树实现,这样也能避免多线程下HashMap死锁的问题;
多线程会导致HashMap的Entry链表形成环形数据结构,一旦形成环,那么Entry的next节点永远不为空,Hash就会陷入死循环获取Entry的场景,从而发生HashMap死锁;
ConcurrentHashMap和Hashtable的区别?
ConcurrentHashMap和Hashtable虽然都是线程安全的,但是有一些区别,Hashtable每次执行同步都是锁住整个数据结构,而ConcurrentHashMap将Hash表分成16个段(segment),每次执行同步所影响的都是当前数据所在的段,不会导致整个hash全部锁住,这种锁的细粒度更小,效率更高;
那么你知道ConcurrentHashMap底层具体是怎么实现的吗?
ConcurrentHashMap包含了两个静态内部类HashEntry和Segment,一个用来封装映射表的键值对,另一个用来充当锁的角色,Segment是一种可重入的锁,每个Segment守护一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须先获得对应的Segment锁;
HashMap的长度为什么是2的幂次方?
HashMap是通过将Key的hash值与length-1进行&运算来实现Key的定位的,而2的幂次方可以减少hash冲突(碰撞)的次数,提高hashmap查询效率,源码如下:
// 返回key的坐标,通过hash值以length-1做&运算
static int indexFor(int h, int length) {
return h & (length-1);
}
当length=2时的幂次方时,length-1转化的二进制必定为1111...(2的n次方实际就是1后面n个0,2的n次方-1 实际就是n个1)这种形式,在于hash值做&运算时效率会非常快,同时运算后的结果也是随机分布的,越随机分布hash冲突就越少;
当length!=2时的幂次方时,length-1和hash值做&运算,就会出现尾数永远为0的情况,这样就会造成很多其他值永远不会被entry占用,增加了hash冲突的概率,也造成空间的浪费;
IO和NIO的区别?
IO面向流,NIO面向缓冲
IO阻塞,NIO非阻塞
IO无选择器,NIO有选择器(多路复用器)
两种都是同步的,异步的IO为AIO
什么是队列、栈、链表?
队列:双向管道,一边进另一边出,所以支持FIFO先进先出原则
栈:单向管道,那边进那边出,所以不支持FIFO,跟队列相反,先进后出原则
链表:是一种线性表,由一系列结点组成,结点可以在运行时动态生成。每个节点包含一个存储数据元素的数据域和一个指向下个节点的指针,通过指针形成链表,所以节点是可以空间上不连续的;