记录java的基础面试的每一个瞬间

记录java的基础面试的每一个瞬间:

一、String、StringBuffer、StringBuilder的区别:

1:首先String的底层是一个被final修饰的字符数组,所以它是不可变的字符序列,拼接字符串的效率低,而StringBuffer、StringBuilder是可变的字符序列,

   拼接字符串的效率较高。

2:如果强行使String的内容发生变化,那么将会产生一个新的字符串对象,而StringBuffer、StringBuilder是在其后追加内容。

3:StringBuffer起源于jdk1.0,而StringBuilder起源于jdk1.5。

4:StringBuffer 是线程安全的,相对来说效率较低,而stringBuilder是线程不安全的,相对来说是线程不安全的。

二、请解释overload 与 override的区别:

1.overlode:意为方法的重载,而override意为方法的重写

2.overlode:方法名相同,参数列表一定不同,与返回值的类型无关,

  而override分为:基本数据类型以及void、引用数据类型、以及抛出的异常

  a:基本数据类型以及void,返回值的类型与被重写的返回值的类型保持一致。

  b:引用数据类型,返回值的类型小于等于被重写的返回值的类型。

  c:抛出的异常类型小于等于被重写的异常类型。

  d:修饰符的类型大于等于被重写的修饰的类型。

三、请解释final、finally、finalize的区别:

  a:final可以修饰外部类,成员属性、成员方法,被final修饰的类不可以继承;被final修饰的属性不可以修改,即是常量;被final修饰的方法不可以被重写。

    b:finally用于try{}catch(){}finally{}代码块儿中,放在finally中的代码一定会被执行,一般用于释放资源等操作。

    c:finalize它是object中的方法,用来jvm的通知jvm的垃圾回收机制,对其进行回收。

四、ArrayList、linkList、Vector的区别:

    ArrayList:

         a:底层是动态的数组。

         b:ArrayList是jdk1.2有的,较vectory晚了一些,是线程不安全的,同时也就意味着效率较高些。

         c:当new ArrayList对象时,会调用一个默认的 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};即是会创建一个空的数组常量,

           当其第一次添加元素的时候,会初始化为10,后期会扩容到原来的1.5倍。

         d:ArrayList只支持foreach 和迭代器遍历集合。

    vectory:

        a:底层是动态的数组。

        b:vectory是jdk1.0就有的,较Arraylist早了一些,是线程安全的,当然线程安全就意味着效率相对来说低些。

      c:vectory初始化的长度为10,可以自定义扩容,也可以按2倍扩容。

        d:除了支持foreach和迭代器遍历数组外还支持旧版的迭代器Enumration

  

  linkList:

             a:底层是双向列表,jdk1.6之后也是双端序列。

         b:它的子类是stack,特点:先进后出。

 五、hashmap 和hashtable的区别,以及hashmap的底层是什么?

  hashtable:

              a:它是jdk1.0就有的,底层是基于哈希表,它是线程安全的,效率相对来说较低。

              b:不允许存储null键和null值。

    hashmap:

           a:它是jdk1.2才有的,底层是基于哈希表的,它是线程不安全的,效率相对来说是比较高的。

                       b:允许存储null值和null键。     

hashmap的底层的实现(jdk1.6):

      hashmap的底层是动态的数组加上链表,首先数组会先初始化长度为16的数组,这个数组的元素的类型是Entry类型的数组,当存储一对映射的关系时,取出key,计算它对应的hashcode值,用这个hashcode值与数组的长度做运算,得到index[index的范围是0,table.length - 1],先判断table[index]是否为空,如果为空,那么就将映射关系封装成Entry的对象,存储到table[index],如果table[index]不为空,那么就要用key与table[index]中的所有映射关系的key进行equals比较,如果返回的结果为true,此时说明该key已经存在,那么就用新的key对应的value来替换旧的key对应的value,如果table[index]下面的映射关系的key与新添加的映射关系的key进行equals比较返回的值为false,说明要添加的key在原来的映射关系中不存在,那么就将新的key对应的映射关系封装进Entry对象中,连接到table[index]的下面的链表head部,此时注意添加映射关系时,如果table[index]不为空,并且size已经到达临界值,即阈值(阈值 = table.length * 0.75)时,数组table就会扩容,扩容到原来的2倍,如果一旦扩容的话,所有的映射关系要用hashCode值来计算存储位置。

hashmap的底层的实现(jdk1.8):
  hashmap的底层是动态的数组加上链表/红黑树,首先也是先创建长度为16的数组,这个数组的类型是Node类型,当存储映射关系时,取出key的值,并计算它对应是hashcode值,用这个hashcode值与数组做运算,可以的出index[index的范围是0 - table.length - 1],然后判断table[index]的值是否为空,如果为空,那么就将映射关系封装成Node类型的对象,存储到table[index]中,如果table[index]不为空的话,那么就要用key与table下面的映射关系的key进行equals比较,如果返回的结果是 true,说明此key已经存在,那么就用新的key对应的value去覆盖返回为true的key对应的value的值。

如果返回的结果是false的话,那么就要分情况了:

a:如果table[index]的下面是一个红黑树,那么新的映射关系的对象封装到TreeNode对象上,然后连接在叶子的节点上。

b:如果table[index]的下面不是一个红黑树,而链表的长度没有超过8个,那么新的映射关系封装成Node类型,连接到链表的尾部。

c:如果table[index]的下面不是一个红黑树,而链表的长度超过了8个,此时还要判断table的长度有没有超过64,如果没有的话,那么需要先扩容,然后先把map中的所有的映射关系重新调整位置,然后在根据hash值与数组做运算,然后重复上面的操作。

d:如果table[index]的下面不是一个红黑树,而链表的长度超过了8个,而此时table数组的长度超过了64,那么把table[index]下面的链表变成一个红黑树,然后新的映射关系封装为TreeNode,连接到叶子结点上。

e:当size达到临界值值,table数组就会扩容,扩容到原来的2倍,一旦扩容,所有的映射关系就需要重新用hashcode值来计算存储的位置。

 

      

猜你喜欢

转载自www.cnblogs.com/donghaibin/p/9180250.html