IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Java面试题

    shendao发表于 2017-04-22 22:27:34
    love 0

    被alibaba从C++调剂到Java岗位,仍在面试中,然而对Java并不熟悉,基础很差,故整理而学习之。
    同时询问,简书又没TOC功能的替代?没有目录很艰难

    [TOC]

    线程安全

    • 线程安全

      当多个线程类并发操作某类的某个方法,在该方法的内部来修改这个类的某个成员变量的值,不会出错,我们就说,这个方法是线程安全的。

      某类的某个方法是否线程安全的关键是:

      1. 该方法是否修改该类的成员变量;
      2. 是否给该方法加锁(是否使用synchronized)
    • 线程不安全

      当多个线程类并发操作某类的某个方法,在该方法内部来修改这个类的某个成员变量的值,很容易发生错误,故我们说,这个方法是线程不安全的。如果要把这个方法变成线程安全的,则用synchronized关键词来修饰这个方法即可。

      TIPS:用synchronized关键字修饰方法,会导致加锁,虽然可能使该方法线程安全,但是会极大的降低该方法的执行效率,所以慎用该关键词。

    String StringBuffer StringBuilder

    • String是字符串常量,后两者是字符串变量。String不可变是因为在JDK中String类倍声明为一个final类。
    • StringBuffer是线程安全的,StringBuilder线程不安全。线程安全会带来额外的内存开销,所以StringBuffer效率低于StringBuilder

    Vector ArrayList LinkedList

    • Vector和ArrayList都是以类似数组的形式存储的,LinkedList则是以链表的形式进行存储的

    • Vector线程同步(安全),ArrayList和LinkedList线程不同步(不安全)

    • ArrayList扩容容器大小的50%,Vector为100%。ArrayList更省空间?

    • ArrayList 是线性表(数组)
      get() 直接读取第几个下标,复杂度 O(1)
      add(E) 添加元素,直接在后面添加,复杂度O(1)
      add(index, E) 添加元素,在第几个元素后面插入,后面的元素需要向后移动,复杂度O(n)
      remove() 删除元素,后面的元素需要逐个移动,复杂度O(n)

      LinkedList 是链表的操作
      get() 获取第几个元素,依次遍历,复杂度O(n)
      add(E) 添加到末尾,复杂度O(1)
      add(index, E) 添加第几个元素后,需要先查找到第几个元素,直接指针指向操作,复杂度O(n)
      remove() 删除元素,直接指针指向操作,复杂度O(1)

    HashTable,HashMap,TreeMap,WeakHashMap

    Java面试题
    img

    Map概括

    Map是“键值对”映射的抽象接口

    AbstractMap实现了Map中大部分函数接口,减少了“Map的实现类”的重复编码

    SortedMap有序的”键值对“映射接口

    NavigationMap继承自SortedMap,支持导航函数的接口

    HashMap是基于拉链法实现的散列表,一般用于单线程程序中。

    HashTable是基于拉链法实现的散列表,一般用于多线程。

    TreeMap是有序(默认升序)的散列表,通过红黑树实现,一般用于单线程中存储有序的映射

    WeakHashMap基于拉链法实现的散列表,一般用于单线程,相比HashMap,WeakHashMap中的键是”弱“键,当弱键被GC回收时,对应的键值也会从WeakHashMap中删除,而HashMap中的键是强键。

    HashMap与HashTable对比

    • 相同点

      • 都是存储键值对(key-value)的散列表,而且都是采用采用拉链法实现的。
      • 添加:首先根据key计算出哈希值,再计算出数组索引,然后根据索引找到Entry(单向链表),再遍历该单向链表,将key和链表中的每一个节点的key进行对比。若存在,则更新value,若不存在,将该节点插入到Entry链表的表头位置
      • 删除:首先根据key计算哈希值,再计算出数组索引,然后根据索引找到Entry遍历,找到节点删除。
    • 不同点

      • 继承和实现方式不同

        • HashMap继承于AbstractMap,实现了Map、CloneMap、Serializable接口

        • HashTable继承于Dictionary,实现了Map、Cloneable、Serializable接口

        • 两者定义代码

          public class HashMap<K,V>       extends AbstractMap<K,V>       implements Map<K,V>, Cloneable, Serializable {} public class Hashtable<K,V>     extends Dictionary<K,V>     implements Map<K,V>, Cloneable, Serializable {}
      • 线程安全性

        • HashMap的函数是非同步的,不是线程安全的。
        • HashTable的几乎所有函数都是同步的,是线程安全的。
      • 对null值的处理

        • HashMap的key和value都可以是null,当HashMap的key为null,HashMap会将其固定插入到table[0]—HashMap散列表的第一个位置。table[0]处只能容纳一个key为null的值,若多个key为null的值插入,则保留最后插入的value。
        • HashTable的key和value都不可以是null,会抛出NullPointerException
      • 支持的遍历种类

        • HashMap只支持Iterator(迭代器)遍历
        • Hash Table支持Iterator(迭代器)和Enumeration(枚举器)两种方式遍历
      • 通过Iterator迭代器便利时的遍历顺序

        • HashMap从前向后遍历数组;对数组具体某一项对应的链表,则从表头开始向后遍历。
        • HashTable从后向前遍历数组;对数组具体某一项对应的链表,则从表头开始向后遍历。
      • 容量的初始值和增加方式

        • HashMap默认初始大小为16,默认加载因子是0.75。增加时,每次将容量变为原始容量*2(保证为2^n)

          TIPS:为了提高效率,HashMap的容量是2的幂,即使指定初始容量不是2的幂,内部也会将其转换为2的幂。

          int capacity = 1; while (capacity < initialCapacity)       capacity <<= 1;//是不是非常interesting
        • HashTable默认初始大小为11,默认加载因子是0.75。增加时,每次扩容为原始容量*2+1(保证近似质数,分散效果好)

      • 添加key-value时采用的hash函数不同

        • HashMap采用自定义的哈希算法

             static int hash(int h) {           h ^= (h >>> 20) ^ (h >>> 12);           return h ^ (h >>> 7) ^ (h >>> 4);       }
        • Hash Table采用key的hashCode()方法,没有自定义的哈希函数

          int hash = key.hashCode();     int index = (hash & 0x7FFFFFFF) % tab.length;
      • 部分API不同

        • HashMap不支持contains(Object value)方法,没有重写toString()
        • HashTable支持contains(Object value)方法,重写toString()

    //TODO:深夜更新



沪ICP备19023445号-2号
友情链接