Java面试指南一(1)

 

第二部分 CoreJava基础(1)

第04章 解读API

4.1 Object常用的方法

       解析:面试刚开始都很简单,但也容易给面试官留下印象,就像这个题,如果你有三年以上经验,回答的少于六个,那么估计你下面将很危险了。Object中的这些方法都很精典,务必记住。 

参考答案:object常用的方法有clone(),equals(),hashCode(),notify(),notifyAll(),

toString(),wait(),finalize()

 

 4.2 String与StringBuffer区别

  解析:这是一个很基础的题,String字符串的问题几乎很多面试官都喜欢问,因为在实际项目开发中用到的最多的变量就是String,所以读者要重点对待,熟练掌握。 

参考答案:StringStringBufferjava中都是用来进行字符串操作的。

String是一个很特别的类,它被final修饰,意味着String类不能被继承使用,一旦声明是一个不可变的类。

StringBuffer是一个长度可变的,通过追加的方式扩充,并且是线程安全;尤其在迭代循环中对字符串的操作,性能一般优于String。但线程安全意味着开销加大,性能下降,所以在线程安全的情况下一般用StringBuilder来代替StringBuffer使用,StringBuilder的速度要优于StringBuffer

 

拓展:javaAPI中哪些类是final的?String"+"号操作性能是不是一定慢?

4.3  Vector,ArrayList, LinkedList的区别

       解析:这里主要考察集合类的熟练程度,考察深度可深可浅;浅的主要是考察使用,深点可能考察底层的数据结构,算法实现等,感兴趣的朋友可以深究一下。

 

参考答案:

 1VectorArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。

 2Vector线程同步,ArrayListLinkedList线程不同步;后两者一般用在线程安全的地方,也可以通过Collections.synchronizedList(……);实现线程同步。

 3LinkedList适合指定位置插入、删除操作,不适合查找;ArrayListVector适合查找,不适合指定位置的插入、删除操作。

 4ArrayList在元素填满容器时会自动扩充容器大小的50%,而Vector则是100%,因此ArrayList更节省空间。

 5LinkedList 还实现了 Queue 接口,该接口比List提供了更多的方法,包括 offer(),peek(),poll(),多与一些线程池一起使用.

 补充:以上都实现了序列化接口,这点在对象远程传输时很重要;而Vector,ArrayList实现了AccessRandom接口,这是一个标记接口,此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。

 注意: 默认情况下ArrayList的初始容量非常小,所以如果可以预估数据量的话,分配一个较大的初始值属于最佳实践,这样可以减少调整大小的开销。

 

拓展:线性列表和双链表的数据结构实现?

4.4  HashTable, HashMap,ConcurrentHashMap区别

       解析:这里还有一个TreeMap没有列出,TreeMap能够把它保存的记录根据Key键排序,所以Key值不能为空,默认是按升序排序,也可以写自己的比较器(TreeMap排序是根据红黑树实现的,有兴趣的可以研究一下它的算法实现)。而ConcurrentHashMap是从jdk1.5新增的,是HashMap的一种线程安全的实现类,经常在多线程的环境中使用,由于底层的实现使用的是局部锁技术,在线程安全的前提下比HashTable的性能要好,推荐使用(ConcurrentHashMap局部锁技术实际上就是把Map分成了NSegmentputget的时候,都是现根据key.hashCode()算出放到哪个Segment中,而这里的每个segment都相当于一个小的HashTable,有兴趣的朋友可以读一下源代码),此题经常在中高级职位面试中问到,所以请慎重对待。

 参考答案:

 1HashTable线程同步,key,value值均不允许为空;HashMap非线程同步,key,value均可为空,HashTable因为线程安全的额外开销会造成性能下降,而HashMap由于线程不安全,在多线程的情况下,一般要加锁,或者使用Collections.synchronizedMap()来创建线程安全的对象。

2HashTable继承的父类是Dictionary,而HashMap继承的父类是AbstractMap

,而且又都实现了Map接口,所以Map接口中提供的方法,他们都可以使用;HashTable的遍历是通过Enumeration,而HashMap通常使用Iterator实现。

 3HashTable有一个contains(Object value)的方法,其功能和HashMapcontainsValue(Object value)一样,而HashMap提供的更加细致还有一个取Key值的方法为containsKey(Object key)

 4、哈希值的使用不同,HashTable直接使用对象的hashCode,代码是这样的:         

 int hash = key.hashCode();

 int index = (hash & 0x7FFFFFFF) % tab.length;

HashMap重新计算hash值,而且用与代替求模:

 int hash = hash(k);   int i = indexFor(hash, table.length);

static int hash(Object x) {  int h = x.hashCode();

  h += ~(h << 9); 

  h ^= (h >>> 14);  

  h += (h << 4);

  h ^= (h >>> 10);  

  return h;}

static int indexFor(int h, int length) {return h & (length-1);} //网络提供,面试时不追问,可以不说出具体的实现代码。

 5ConcurrentHashMapHashMap线程安全的实现,并且逐渐取代Hashtable的使用,因为Hashtable锁的机制是对整个对象加锁,而ConcurrentHashMap使用的是局部锁技术,实际上就是把Map分成了NSegmentputget的时候,都是现根据key.hashCode()算出放到哪个Segment中,而这里的每个segment都相当于一个小的Hashtable,性能将高于HashTable

 

 4.5  Equals()和HashCode()作用

       解析:这个问题每个面试求职者或许都被问到过,属于常见题型,但也是比较难回答的面试题之一;包括很多面试官本身也有时候并不能解释得很清楚,如果要回答好这个小问题,首先要了解这两个方法的实现原理(在第I版中不会太深入讨论)。在《Effective java》中有这样一句话:在每个覆盖了equals方法的类中,也必须覆盖hashCode方法,如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常动作,这样的集合包括HashMap,Hashtable,HashSet。这里列出一下equals重写的规则:

1 自反性:对任意引用值Xx.equals(x)的返回值一定为true.

2 对称性:对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;

3 传递性:如果x.equals(y)=true, y.equals(z)=true,x.equals(z)=true

4 一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变

5 非空性:任何非空的引用值Xx.equals(null)的返回值一定为false

 

 

参考答案:这两个方法都是Object类的方法,equals通过用来判断两个对象是否相等。HashCode就是一个散列码,用来在散列存储结构中确定对象的存储地址。HashMapHashSet,他们在将对象存储时,需要确定它们的地址,而HashCode就是做这个用的。在默认情况下,由Object类定义的hashCode方法会针对不同的对象返回不同的整数,这一般是通过将该对象的内部地址转换成一个整数来实现的。

javaequalshashCode之间有一种契约关系:

1. 如果两个对象相等的话,它们的hashcode必须相等。

2. 但如果两个对象的hashcode相等的话,这两个对象不一定相等。

由于java.lang.Object的规范,如果两个对象根据equals()方法是相等的,那么这两个对象中的每一个对象调用hashCode方法都必须生成相同的整数结果。(下面作为解释内容可以不必回答,理解使用)

举例说,在HashSet中,通过被存入对象的hashCode()来确定对象在HashSet中的存储地址,通过equals()来确定存入的对象是否重复,hashCode()equals()都需要重新定义,因为hashCode()默认是由对象在内存中的存储地址计算返回一个整数得到,而equals()默认是比较对象的引用,如果不同时重写他们的话,那么同一个类产生的两个完全相同的对象就都可以存入Set,因为他们是通过equals()来确定的,这就是HashSet失去了意义。面试时简单的说,HashSet的存储是先比较HashCode,如果HashCode相同再比较equals,这样做的目的是提交储存效率。所以换句方式问,如果用对象来做为Key值的话,要满足什么条件呢?答要重写equalsHashCode方法。

4.6  Sleep()和Wait()区别

       解析:多线程可以说是java面试中的重点难点之一,也是最能筛选面试者的分水领,这个只是属于最基本的考点,尽可能的回答周全,面试的朋友可以对多线程这块多花点时间。

 

参考答案:

 1wait()Object类的方法,在每个类中都可以被调用;而sleep()是线程类

Thread中的一个静态方法,无论New成多少对象,它都属于调用的类的。

 2sleep方法在同步对象中调用时,会持有对象锁,其它线程必须等待其执行结束,如果时间不到只能调用interrupt()强行打断;在sleep时间结束后重新参与cpu时间抢夺,不一定会立刻被执行。

  3wait()方法在同步中调用时,会让出对象锁。通常与notify,notifyAll一起使用。

4.7  IO与NIO的区别

  解析:这是现在面试中常被问到的一个问题,尤其做后台开发的职位;NIO是从jdk1.4就引入了,但是如果没有实际开发中使用过,不是很容易说的很清楚,这里从概念的层面介绍一下,希望有兴趣的朋友能更深层次的研究一下。

参考答案:IO是早期的输入输出流,而NIO全名是New IOIO的基础上新增了许多新的特性。提供的新特性包括:非阻塞I/O,字符转换,缓冲以及通道。

 1IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。

 2Java IO的各种流是阻塞的。这意味着,当一个线程调用read() write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。虽然是非阻塞的,但也会遇到一个问题就是服务器对最大连接的支持,但在线用户连接数大于系统支持数时,NIO的默认实现是并不管是否还有足够的可用连接数,而是直接打开连接。在netty框架中经常会看到一个open too many files异常就是由此引起的,所以要灵活使用,合适配置。

3Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来选择通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

 扩展:NettyNIO实现的一个经典框架,好多职位中都要求熟悉netty,大家有时间可以研究一下。

4.8  Synchronized和Lock区别和用法

       解析:这里相对于上面的waitsleep的区别来说,难度明显增加,也是常见的面试题。

参考答案:

首先他们都是用来实现线程的同步操作的,synchronizedjdk1.2以来一直存在,而且Lockjdk1.5的新增;具体区别如下:

 1LockJDK1.5才出现的,而在jdk1.5及之前的synchronized存在很大的性能问题,尤其在资源竞争激烈的条件下,性能下降十多倍,而此时的Lock还基本能维持常态。(synchronizedjdk1.5后的版本,作了很大的性能优化)

 2、使用synchronized时对象一定会被阻塞,其它线程必须等待锁释放后才能执行,在高并发的情况下,很容易降低性能,而且控制不当还容易造成死锁,所以要合适的利用Synchronized,并且尽可能的精确到最小的业务逻辑块。而Lock提供了更细致的操作,其常用的实现类有读写锁,这里以ReentrantLock 为例,它拥有Synchronized相同的并发性和内存语义,此外还多了锁投票,定时锁等候和中断锁等候等很多详细的方法操作。 ReentrantLock获取锁定与三种方式:a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回falsec)tryLock(long timeout,TimeUnit unit),如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回falsed) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断。

 3synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中。

 补充:

A.无论synchronized关键字加在方法上还是对象上,他取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。 B.每个对象只有一个锁(lock)和之相关联。

C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。synchronized可以加在方法上,也可以加在对象上,通常理解为,只有持有了锁才可以进行对应代码块的执行。

java.util.concurrent.locks包下面提供了一些锁的实现,有读写锁,公平锁等。

synchronized替换成lock的实现可以提升性能:

1. 大部分应用场景是读写互斥,写和写互斥,读和读不互斥。而synchronized则是都互斥。

可以利用读写锁来优化性能,读锁锁住读的代码块,写锁锁住写的代码块。

2. 要确保你在理解原来利用到synchronized的代码逻辑,避免一概而论地把synchronized替换成锁。

PS:被synchronized修饰的方法所在的对象,其它线程可以访问该对象的非synchronized修饰的方法,不能访问synchronized的任何方法。

  说明:里面有一部分看网上总结的比较好,就直接拿过来使用了,当然面试时也不是说必须要把上面的点回答完,最重要要通过自己的理解表达出来。

 

 4.9  Final、Finally、Finalize的区别

       解析:这是一个很老很老就存在的面试题,但还是经常被问到,越简单的题在面式中越不允许答错。

 

参考答案:

FinalJava中一个特别的关键字(修饰符),final修饰的类不能被继承,final修饰的变量不能被修改(是常量),final修饰的方法不能被重写,所以使用final要考虑清楚使用场景。

FinallyJava异常处理try{}catch(..){}finally{}中的一部分,finally语句块中的语句一定会被执行到(Down机除外),通常用于进行资源的关闭操作,如数据连接关闭等。

FinalizeObject类中的一个方法,finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的,设计的初终是可以进行一些资源的关闭,但这个方法很少被重写,因为垃圾回收器执行时并不一定会调用,比如抛异常时,而且垃圾回收本身就是随意的,不可控制的。

4.10  OverLoad与Override的区别

       解析:这里其实是考的是Java面向对象的三(四,如果算上抽象就是四大特征)大特征,封装、继承、多态、(抽象)中的多态,属于基础类型常考题之一。

 

 参考答案:overloadoverride是多态的两种表现形式;

 overload重载规则是同名不同参,方法名相同,参数类型、个数、顺序至少有一个不相同(与返回值、参数名、抛出的异常都没有关系);

 overload可以发生在父类、同类、子类中。override重写的规则是方法名、参数、返回值相同,发生在父子类之间,而且子类不能抛出比父类更多的异常,被重写的方法一定不能定义成final

 

4.11  Collection与Collections的区别

  参考答案:Collection是一个集合的超级接口,它定义了一些集合常用的操作方法,如add,size,remove,clear等,我们经常用到的List(可重复集合),Set(不可重复集合)接口就是它的子接口。

 Collections此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。它包含在 collection 上操作的多态算法,即包装器,包装器返回由指定 collection 支持的新 collection,以及少数其他内容。如果为此类的方法所提供的 collection 或类对象为 null,则这些方法都将抛出NullPointerException。常用到的方法如copy,sort,reverse,replaceall等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值