• java 集合hashmap hashset arraylist 详解以及常见面试题


       今天复习了一下自认为java 中很重要的一部分集合,这篇文章主要从底层源码进行分析这几种集合的区别与联系,他们的用法不多讲,用法不难;大多数东西我也是从各位大神的博客上或者书上扒下来的,小菜鸟在复习,写下来主要是一:是为了想留下点东西 二:我发现在写的过程中我可以学到很多东西;

    关于java 集合的内容之前在阿里电面的时候问到的我第二个问题就是关于HashTable 线程安全的问题,问题不难但是深度问起来还是挺难回答的。接下来我根据我自己复习的情况简单写一篇文章供大家学习,希望多多指教;

        这是一张Java集合的总框架图很清晰明了  图片来源(http://blog.sina.com.cn/s/blog_51721d970100a37a.html)

     迭代器:

         在讲集合之前我又不得不先看一眼迭代器   collection 和map  都属于迭代器模式的的一种;

         迭代器(iterator)模式    :迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而   又不需暴露该对象的内部细节

      在讲集合之前我又不得不先看一眼迭代器   collection 和map  都属于迭代器的一种;

    我先根据我自己的理解给大家简单的讲解一下    下边橙色的是实现类 也是我们最常使用的一种;草绿色的是抽象类上边蓝色的是接口;


    一:先讲map, Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个value。Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。  

     

           面试中常问的问题是HashMap 和HashTable 的区别与联系    在讲他们之前   HashCode 需要简单的了解一下   hashCode方法,这个方法我们平时通常是用不到的,它是为哈希家族的集合类框架(HashMap、HashSet、HashTable)提供服务,hashCode 的常规协定是:

          关于HashMap和HashTable  是面试中常问的java  经典问题;

          HashMap 几乎等同于HashTable  但是因为HashTable  使用同步锁   所以线程安全;   判断值得存在性如图1.1

      HashMap: 1.线程不安全(因为没有使用同步锁(synchronized)),

            2.允许value  为null  ,

            3.HashMap  底层是通过Entry[]  每次新建一个HashMap 就相当于新建一个Entry[];图1.2实现原理图

                         4.调用put方法是首先通过获取  key的Hashcode 来保证key 的唯一性

            5.get,put 方法都通过数组链表指针移动等方式 利用hashcode   实现;不详细讲   

      HashTable:线程安全(使用synchronized),不允许value  为 null;    其他的和HashMap  类似不多讲;

     

       

     

     

              

         

                     图1.1                                                                    图1.2

     


     

     

     

     

    二 :关于colletion Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。

        List  and  set  :

       1、List,Set都是继承自Collection接口

       2、List特点:元素有放入顺序,元素可重复 ,

          Set特点:元素无放入顺序,元素不可重复(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决    定的,其位置其实是固定的)

       3、List接口有三个实现类:LinkedList,ArrayList,Vector ,Set接口有两个实现类:HashSet(底层由HashMap实现),LinkedHashSet

       List:

     

          1. vector 是同步的所以线程安全  提供的方法和arraylist 类似不多讲

          2.关于ArrayList 和 Linkist 类(自认为是重点 )   多讲一点  线程不安全

            ArrayList 优点:  提供了可增长数组的实现;对查询的调用花费常数的时间;

            缺点:新项的插入和现有项的删除耗费时间较长  线程不安全

            而Linklist 与Array List 正好相反   它不容易做索引所以对于查询  耗费相对多一些但是对于add and  remove  方法开销缺很小;总而言之各有优缺点;(面试常    问

            其导致的原因就是   arraylist 底层用数组的形式实现的list  而 LinkList 底层用底层用双向循环链表 实现的List

     

        接下来就是set 方法了;

       set:

           HashSet  =>  1.hashset 底层是用hashmap  实现的(图 1—1 ) 

               2.hashset 的add方法实际上是将需要添加的对象看做底层维护的map的key值储存的,而map  的value值都是同一个值;(图 1—2)

                (讲到这大家应该明白为什么hashset中不能储存相同的值了,因为map中键值对的形式,键值不能相同,所以。。。。)

                               3.hashset的remove和clear实际上都是调用了map  的方法;更加充分说明了hashset底层以hashmap  为基础;(图 1—3)

                           图 1—1                                               图1—2                                                                      图1-3

     

         


     

     

     下面是关于集合的几种常见面试题  题目来自于百度经验

     

    1. 集合类特性(几个常用类的区别)

      ArrayList: 元素单个,效率高,多用于查询  Vector: 元素单个,线程安全,多用于查询  LinkedList: 元素单个,多用于插入和删除  HashMap: 元素成对,元素可为空  HashTable: 元素成对,线程安全,元素不可为空

      WeakHashMap: 是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收

    2. Iterator 是什么

      一些集合类提供了内容遍历的功能,通过java.util.Iterator接口。这些接口允许遍历对象的集合。依次操作每个元素对象。当使用Iterators时,在获得Iterator的时候包含一个集合快照。通常在遍历一个Iterator的时候不建议修改集合本省。

      Iterator与ListIterator有什么区别

      1. Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。  

      2. Iterator只能正向遍历集合,适用于获取移除元素。ListIerator继承Iterator,可以双向列表的遍历,同样支持元素的修改。比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。

    3. Collection 和 Collections的区别

      Collection是集合类的上级接口,继承与他的接口主要有Set 和List.

      Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作

      List、Map、Set三个接口,存取元素时,各有什么特点

      List  以特定次序来持有元素,可有重复元素;

      Set  无法拥有重复元素,内部排序(无序);

      Map 保存key-value值,value可多值。

      Java集合面试题:[1]集合面试题、Java集合
    4. HashMap和Hashtable的区别

      都属于Map接口的类,实现了将惟一键映射到特定的值上。   

      一.历史原因:

      Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现  

      二.同步性:

      Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的  

      三.值:

       HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。 

       Hashtable 类似于 HashMap,但是不允许 null 键和 null 值。

      四.效率:

      Hashtable 比 HashMap 慢,因为它是同步的。

      怎样使HashMap同步

      HashMap可以通过Map m = Collections.synchronizedMap(hashMap)来达到同步的效果。

    5. ArrayList和Vector的区别

      ArrayList与Vector主要从二方面来说.  

      一.同步性:

         Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的。

      二.操作:

          由于Vector支持多线程操作,所以在性能上就比不上ArrayList了。

      三.数据增长:

             ArrayList和Vector都有一个初始的容量大小,当存储进去它们里面的元素个数超出容量的时候,就需要增加ArrayList和Vector的存储空间,每次增加存储空间的时候不是只增加一个存储单元,是增加多个存储单元。

             Vector默认增加原来的一倍,ArrayList默认增加原来的0.5倍。

             Vector可以由我们自己来设置增长的大小,ArrayList没有提供相关的方法。

      LinkedList与ArrayList有什么区别

      两者都实现的是List接口,不同之处在于:

      (1)、ArrayList是基于动态数组实现的,LinkedList是基于链表的数据结构。

      (2)、get访问List内部任意元素时,ArrayList的性能要比LinkedList性能好。LinkedList中的get方法是要按照顺序从列表的一端开始检查,直到另一端

      (3)、对于新增和删除操作LinkedList要强于ArrayList,因为ArrayList要移动数据

      附加:

             LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。

             注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:

      List list = Collections.synchronizedList(new LinkedList(…));

    6. 数组(Array)和列表集合(ArrayList)有什么区别

      下面列出了Array和ArrayList的不同点: 

              Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。

              Array大小是固定的,ArrayList的大小是动态变化的。 

              ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()  等等。

             对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

      Enumeration接口和Iterator接口的区别有哪些

             Enumeration速度是Iterator的2倍,同时占用更少的内存。但是,Iterator远远比Enumeration安全,因为其他线程不能够修改正在被iterator遍历的集合里面的对象。同时,Iterator允许调用者删除底层集合里面的元素,这对Enumeration来说是不可能的。

    7. HashSet和TreeSet有什么区别 

      HashSet有以下特点:

      A. 无序(不能保证元素的排列顺序,顺序有可能发生变化)B. 不同步C. 允许空值(集合元素可以是null,可以放入多个null,但会自动覆盖)

      当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。

      TreeSet有以下特点:

      A. 有序

            1. TreeSet是由一个树形的结构来实现的(数据结构是二叉树),它里面元            素是有序的

            2.TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于           排序状 态,支持两种排序方式,自然排序和定制排序。其中自然排序为             默认的排序方式;定制排序,TreeSet中的对象元素需要实Comparable             接口

          TreeSet类中跟HashSet类一样也没有get()方法来获取列表中的元素,所以      也只能通过迭代器方法来获取

          二叉树:

                

      B. 不允许空值

            1. HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过            Set用的只是Map的key

            2. Map的key和Set都有一个共同的特性就是集合的唯一性.TreeMap更是              多 了一个有序性.

            3. TreeSet类中跟HashSet类一样也没有get()方法来获取列表中的元素,所            以也只能通过迭代器方法来获取

            4. HashSet是基于hash算法实现的,性能优于TreeSet,通常使用                        HashSet。在我们需要对其中元素排序的时候才使用TreeSet。

      Java集合面试题:[1]集合面试题、Java集合
    8. HashMap,LinkedMap,TreeMap的区别

      HashMap,LinkedHashMap,TreeMap都属于Map。

      LinkedHashMap是HashMap的子类。

      Map 主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复

      1.HashMap的内部结构是一个数组,线性顺序存储,二次结构使用线性的单链表。使用key的hashCode做二次hash之后,再截取小于数组长度的值为索引值。key可以为null,存在索引为0的位置上。由于使用了数组,所以有一个负载因子loadFactor的概念(临界阈值threshold)和resize。resize比较耗时,冲突时链式遍历查找也比较耗时,所以选定一个合适的初始容易比较重要。存取性能都较高。迭代遍历时一维使用数组,二维使用链表。

                HashMap            是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直              接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的            键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任             一 时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如             果需要同步,可以用 Collections的synchronizedMap方法使HashMap           具有同步的能力。

      2.LinkedHashMap是HashMap的子类。内部结构是一个数组,线性顺序存储,二次结构使用线性的单链表,但同时内部维护了一个双向循环链表,可以保持顺序。access-order=false默认为使用新增存储顺序,access-order=true则指定使用读取和访问顺序。removeEldestEntry=false(当指定为true时,就是实现LRU算法的缓存容器,当然要指定淘汰时的使用频率和容量上限,其实是一个最近最少使用-->最近使用access-order=true/最新存储access-order=false)。存取性能较HashMap差-些,但相差不大。header.after为尾方向,header.before为首方向。迭代遍历时entrySet().iterator()跟HashMap一样(有点困惑,为什么不按线性顺序进行迭代,只能重写entrySet(),keySet()和values()方法)。适用于有缓存设计需求的情况(需继承)。 3.TreeMap的内部结构是一棵红黑树(又叫排序数,是二叉树的一种),使用链式存储,可以指定比较器Comparator,key需实现Comparable接口。key不能为null。存结点性能稍差,因为需要调整树结构;取结点用的是链表遍历,但是属于有序比较,性能中等。迭代遍历时用的树的中序遍历,是一个有序序列。适用于有排序需求的情况。


      下面是我测试用的简单的代码  发给大家吧:

       /*ArrayList */
          public static void Array (){
              ArrayList<String> arrayList = new ArrayList();
              /*arrlist 添加的方法 */
              arrayList.add("你好");
              arrayList.add("我好");
              arrayList.add("他好");
              arrayList.add("大家好");
              arrayList.add("真的好");
              //查询size
              int size = arrayList.size();
              //查询特定的元素是否存在
              boolean has = arrayList.contains("a");
              //是否为空
              boolean isEmpty = arrayList.isEmpty();
              //根据下标删除特定的元素
              arrayList.remove(1);
              //根据内容删除特定元素
              arrayList.remove("a");
              //删除全部元素
              arrayList.removeAll(arrayList);
          }
          public static void Link (){
              LinkedList<String> linkedList = new LinkedList();
              /*linklist 添加的方法 */
              linkedList.add("你好");
              linkedList.add("我好");
              linkedList.add("他好");
              linkedList.add("大家好");
              linkedList.add("真的好");
              //查询size
              int size = linkedList.size();
              //查询特定的元素是否存在
              boolean has = linkedList.contains("a");
              //是否为空
              boolean isEmpty = linkedList.isEmpty();
              //根据下标删除特定的元素
              linkedList.remove(1);
              //根据内容删除特定元素
              linkedList.remove("a");
              //删除全部元素
              linkedList.removeAll(linkedList);
      
              /*  这是比arraylist 多提供的一些方法  不多解释一看就懂*/
              linkedList.getFirst();
              linkedList.getLast();
              linkedList.removeFirst();
              linkedList.removeLast();
          }
         /*Treeset  以及利用构造器进行数据排序*/
      
         public static  void tree(){
      
             TreeSet  treeSet = new TreeSet();
             treeSet.add("A");
             treeSet.add("B");
             treeSet.add("D");
             treeSet.add("C");
      
             for(Iterator iterator= treeSet.iterator();iterator.hasNext();){
      
                 System.out.println((String)iterator.next());
             }
         }
      
         /*HashSet */
          public static  void hash(){
      
              HashSet hashSet = new HashSet();
              hashSet.add("A");
              hashSet.add("B");
              hashSet.add("D");
              hashSet.add("C");
      
              /*利用迭代器的方法   排序输出*/
              for(Iterator iterator= hashSet.iterator();iterator.hasNext();){
                  System.out.println((String)iterator.next());
              }
          }
      
          /*Hash Map  */
      
          public static  void hashmap(){
      
              HashMap hashMap = new HashMap();
              hashMap.put("a","A");
              hashMap.put("b","A");
              hashMap.put("c","A");
              hashMap.put("d","A");
              hashMap.put("e",null);
              /*判断某个值得存在性*/
              hashMap.containsKey("a");
              hashMap.containsValue("A");
      
              System.out.println(hashMap.get("e"));
          }
          /*HashTable*/
          public static  void hashtable(){
      
              Hashtable hashtable = new Hashtable();
              hashtable.put("a","A");
              hashtable.put("b","A");
              hashtable.put("c","A");
              hashtable.put("d","A");
              /*判断某个值得存在性    */
              hashtable.containsKey("a");
              hashtable.containsValue("A");
              hashtable.contains("b");
      
              System.out.println(hashtable.get("e"));
      
      
          }
      
         public static void main(String[] atgs){
             tree();
             hashmap();
             hashtable();
         }

     

     

  • 相关阅读:
    简单粗暴的tensorflowRNN
    简单粗暴的tensorflow多层感知机(MLP)
    简单粗暴的tensorflow模型导出
    Tensorflow
    简单粗暴的tensorflowTensorBoard可视化
    linux deb文件安装
    numpy.squeeze()的用法
    pandas
    图像融合opencv中addWeighted()
    numpy线性代数
  • 原文地址:https://www.cnblogs.com/ykjava/p/6769995.html
Copyright © 2020-2023  润新知