面经问题选之Java SE基础部分

来源:互联网 发布:新西兰生活 知乎 编辑:程序博客网 时间:2024/05/24 05:11

准备把看到的一篇面经涉及的问题全都过一遍,内容比较多,深入讲不现实,过一个大概,至少知道是怎么一回事。


Q1:Java的四种引用,强弱软虚,用到的场景

1)强引用(StrongReference) :

最常用的引用,JVM宁愿抛出OutOfMemoryError,也不会让垃圾回收器回收被强引用引用的对象。

2)软引用(SoftReference):

只有在内存不足的时候,才会被垃圾回收器回收。且垃圾回收器会优先回收长时间没有使用的软可及对象(可及性见下)。用于实现内存敏感的高速缓存。

3)弱引用(WeakReference):

一旦发现立即被回收,比软引用的生命周期更短。不过由于垃圾回收线程的优先级很低,因此不一定会很快发现弱可及对象。

4)虚引用(PlantomReference):

有等同于没有的引用,必须与引用队列ReferenceQueue联合使用,主要用途是结合ReferenceQueue,用来跟踪持有某个虚引用的对象是否已近被回收。


补充:

可及性:

同一个对象可能持有多种引用,或者是通过某条或多条引用链来到达,单条路径取最弱引用作为该路径的代表引用,然后多条路径的比较中,取最强的代表引用作为该对象的可及性。

ReferenceQueue的作用:

1) 提供一个失去引用对象的引用的清除机制,防止大量失去引用对象的Reference对象造成的内存泄露

2) 可以跟踪我们所关心的对象是否将被回收( 如果该对象的弱/软/虚 引用出现在了队列中)

深入学习链接:http://zhangjunhd.blog.51cto.com/113473/53092/


Q2: ArrayList、LinkedList、Vector的区别

List接口,元素有序,允许重复内容
|----ArrayList : 底层采用数组实现,异步,数据增长为原来的50%.

|----Vector : 底层同样采用数组实现,同步的,数据增长为原来的一倍。

|        |--派生--Stack

|----LinkedList: 底层采用双向链表实现,异步


对比:

ArrayList是异步的,所以当我们不要求线程安全的时候,为了省去保证线程安全的开销,使用ArrayList比使用Vector高效。

ArrayList与Vector 底层都是使用数组实现的,因此访问任意元素效率高,但是增加和删除的效率低(增删都会导致元素的移动),相比下LinkedList,底层采用双向链表实现,访问慢,但是增加删除快。

实际上,《Practical Java》中推荐的是尽量使用数组而不是集合,对于要求高效率的程序更是如此,尽量避免同步,额外的方法调用,数据增长造成额外空间重新分配的开销。


Q3::HashMap与ConcurrentHashMap的区别

HashMap不是线程安全的这是众所周知的,而ConcurrentHashMap则是线程安全的。

ConcurrentHashMap在实现同步上,并不是在所有方法上加sychronized(不然就变成HashTable了),而是引入了分段锁的概念。将一个Map的内容,拆分存储在多个SegMent中,根据hashCode来决定存储到或在哪个SegMent中读取,只有当多个线程读取 / 写入的部分属于同一个SegMent的时候,该SegMent才会被阻塞,其余情况分属不同SegMent的读写不会导致阻塞,在提供了线程安全的前提下,效率更高。

深入学习链接:http://blog.csdn.net/xuefeng0707/article/details/40834595


Q4:TreeMap、HashMap、LinkedHashMap的区别

Map接口: 除了LinkedHashMap之外,元素无序(指的是遍历出来的顺序与插入顺序无关), 不允许重复键,允许重复内容。

|

|---HashMap : 异步,底层实现为数组+链表,允许null作为键值,数据增长条件为0.75的数组容量被占用,容量翻倍,hashCode计算为二次hash,取得更好的散列

|          |          值

|          |

|          |---派生--LinkedHashMap:  保证有序, 遍历起来一般比HashMap慢,但是当HashMap中实际数据量非常少而容量非常大时,LinkedHashMap遍历起来就会比

|                                                 HashMap快

|

|---HashTable: 同步,底层同HashMap,不允许null作为键值,且实现了Dictionary抽象类,数据增长条件同样为0.75的容量被占用,容量翻倍并+1,hashCode计算

|                    为直接对数组长度取模                     

|     

|---TreeMap: 异步,不允许空键,底层为红黑树,遍历取出的是排序后的结果

补充:HashMap解决冲突的办法为链表法。

深入学习链接:

http://xiaolu123456.iteye.com/blog/1485349

http://blog.sina.com.cn/s/blog_7cf112e00100rk88.html


Q5:Interface与abstract类的区别。

1) 接口的数据成员必须为public static final, 而抽象类可以有普通的成员变量

2) 接口中所有的方法必须为抽象方法,而抽象类可以拥有非抽象的普通方法

3) 接口的抽象方法只能定义为public类型且默认为public,在实现的时候,只能定义为public或友好的。而抽象类的抽象方法可以定义为public或protected。

4) 一个类只能继承一个抽象类,却可以实现多个接口

5) 个人理解,设计理念上,抽象类定义的是"is-a"的关系,接口定义的是"behave like"的关系( 接口这样描述自己:“对于实现我的所有类,看起来都应该象我现在这个样子”。 ---<<Thinking in Java>>)

补充:

1.即便一个类不包含任何抽象方法,我们仍然可以将这个类声明为abstract类,如果我们想要禁止这个类的所有实例,这种方法非常有效。(出自<<Thinking in Java>>)。

2.抽象类在设计模式中的应用:

模版方法模式:定义一个操作中的算法的骨架,而将步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。

实例:

假设某个项
目的所有Servlet类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的Servlet 都继承这个抽象基类,在抽象基类的service 方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码

深入学习链接:http://blog.163.com/wuqiwei_2010/blog/static/1625507782011215114150967/


Q6:

http://zhh9106.iteye.com/blog/2151791



Q10:foreach与正常for循环效率对比

foreach的效率比正常for循环略低,但是遍历数组的话,效率几乎没区别。foreach在遍历不同的容器时,其编译方式不同。当我们需要遍历数组以外的容器的时候,最好还是使用普通for循环。


补充:

1)  foreach并不是关键字

2) 关于网上流传的很多foreach只取值,无法对遍历对象做修改的说法,我觉得是不准确的,确切的说法应该是使用foreach无法增删或覆盖集合的元素,但是还是可以对集合的元素的属性做修改,这个其实还是看对句柄的理解。

import java.util.*;class Apple{     public int var;}public class See{    public Apple[] ap = new Apple[2];    public static void main(String[] args) {        See ts = new See();        /*Innitialization*/        ts.ap[0] = new Apple();        ts.ap[1] = new Apple();        ts.ap[0].var = 10086;        ts.ap[1].var = 11111;                /*use foreach to change the properties of the entry */        for(Apple x : ts.ap)            x.var = 233;          for(int i=0; i<2; i++){          System.out.println(ts.ap[i].var);        }        /*try to use foreach to change the entry*/        for(Apple x : ts.ap)            x = new Apple();                /*If the entries were replaced, the out put should be 0*/        for(int i=0; i<2; i++){          System.out.println(ts.ap[i].var);          /*however the out put is 233*/        }    }}

深入学习链接:http://bbs.csdn.net/topics/340188487

1 0
原创粉丝点击