Java基础 - 集合

集合

1.集合体系

集合1.png

Collection(集合的根接口) --> Iterable(接口)

Collection

  • List接口

    有序 (记录元素的添加顺序) 可以重复

    • AbstractList(抽象类)

      • ArrayList [数组结构]

      • Vector [数组结构]

        • Stack
      • LinkedList[链表结构]

  • Queue接口

    • Deque接口
      • LinkList[链表结构]
  • Set接口

    无序 (不记录元素的添加顺序) 不能重复

    • AbstractSet抽象类
      • TreeSet[红黑树结构]

      • HashSet[哈希表结构]

        • LinkHashSet[链表+哈希表]
    • SortedSet接口

Map接口

  • AbstractMap抽象类

    • HashMap
    • TreeMap
  • HashTable

    • Properties

在集合的接口规范中,我们不难发现,包含的是对数据的CRUD

添加: add()  addAll()

查询: contains(Object o)

删除: remove(Object o)

注意: 集合只能存储对象!

2.List

特点:

有序 (记录元素的添加顺序) 可以重复

查询:get()方法, 根据索引查  indexOf()方法,查询对象的索引

修改:set()方法

2.1 Vector

Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable

  • 基于数组结构
  • 实现可增长的对象数组,使用整数索引进行访问,大小可以根据需要增大或者缩小
  • 无参构造默认内部数组长度为10.

  • 线程安全,不效率

  • 是Java1.0就有了,属于老古董

2.2 Stack

Stack<E> extends Vector<E>

表示后进先出, 继承于Vector类,Vector类的方法在Stack中都能使用

Stack() 创建一个空堆栈

push() 把一个对象压进堆栈

peek() 查看栈顶的对象

pop() 移除堆栈顶部的对象, 并返回该对象

empty() 堆栈是否为空

search() 在栈中查找对象, 并确定到栈顶的距离
  • 线程安全,不效率

2.2 ArrayList

ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable

  • 基于数组结构

  • 使用上大致是跟Vector一致的,允许所有元素(包括null)

  • 默认无参构造创建对象时没有长度,在需要存储元素的时候才进行扩容

      add() 添加一个元素
    
      addAll() 添加另一个集合中的所有元素
    
  • ArrayList 不是线程安全的, 效率高

2.3 LinkedList

LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable

  • 允许所有元素(包括null)

  • 底层基于链表、双向队列数据结构集合

  • List接口的链表实现,支持List的通用方法

  • 为首尾元素的操作提供了特定的方法, 允许作为堆栈,队列,双向队列

      offerFirst() 添加头元素
      offerLast()  添加尾元素
    
      pollFirst() 移除头元素
      pollLast()  移除尾元素
    
      peekFirst() 查看头元素
      peekLast()  查看尾元素
    
  • 线程不安全,处理首尾元素效率高

2.4 集合的迭代

所谓迭代,就是访问集合中的每一个元素

  • for循环

    使用for循环访问数组中的元素,依赖的是数组的索引

  • Iterator

    • 不是所有集合都可以使用

    • 面向对象的做法,把迭代集合的操作封装成一个对象

        Iterator it = list.iterator();
        while(it.hasNext()){
            Object obj = it.next();//取出下一个元素
        }
      
    • 常用方法

        hasNext() 是否有下一个元素,
        判断当前索引是否等于集合长度,不等则返回true,表示还有元素可以迭代.
        
        next() 先返回当前索引的元素,然后索引+1
      
        remove() 删除元素
      
    • 在迭代的过程中只能使用迭代器操作源集合的元素

  • ListIterator

    • Iterator的子接口,并且功能更加的强大

    • 包含了CRUD的方法

        ListIterator it = list.listIterator();
        //从头到尾迭代
        while(it.hasNext()){
            it.next();//获取下一元素
            it.set("111");//替换和删除原理是一样的,必须先next()移位
        }
        it.add("222");//往集合里添加元素
        //从尾到头迭代
        while(it.hasPrevious){
            it.previous();//取出上一元素
        }
      
    • 只有List集合中才有

  • foreach

    • 语法糖,底层是Iterator

        for(Object obj : list){
            ....
        }
      
    • 只要实现了Iterable接口就可以用foreach迭代

迭代集合总学了3种方式:在迭代的过程中如果要操作集合,建议使用迭代器,仅仅是要访问元素就使用foreach会简单一些

2.5 泛型

  • 类型的不确定,但是使用逻辑一样

  • 集合使用泛型和没有使用泛型的区别

    • 没有泛型

        取出集合中的元素对象,要调用到元素对象子类特有的方法,必须强转(不安全)
      
        到处都是警告
      
    • 使用泛型

        使用的时候限定了只能存储对应的类型,其他的类型不能存储进来
      
        使用里面的对象时不需要强转
      
        如果要存储多种类型的数据,建议分开存储
      
        没有警告
      
  • 泛型只是语法糖,当取出并使用集合里的对象时,底层是编译器帮我们强转,有编译器来强转保证安全

  • 泛型的作用域

    • 声明在类上,在整个类中有效

        class test<E>{
            ...
        }
      
    • 声明在方法上,只在当前的方法中有效

         /** 
         * 这才是一个真正的泛型方法。
         * 首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T
         * 这个T可以出现在这个泛型方法的任意位置.
         */
        public <T> T showKeyName(Generic<T> container){
            System.out.println("container key :" + container.getKey());
            //当然这个例子举的不太合适,只是为了说明泛型方法的特性。
            T test = container.getKey();
            return test;
        }
      
        * 泛型的数量也可以为任意多个 
         如:public <T,K> K showKeyName(Generic<T> container){
             ...
             }
      
  • 问号的使用

    泛型中使用问号的3种情况:

      1.?:未知类型
    
      2.? super BaseClass:必须是BaseClass类型的父类或者BaseClass类型
    
      3.? extends BaseClass:必须是BaseClass类型的子类或者BaseClass类型
    

3.Set

特点:

无序不重复,不包含重复元素,最多包含一个null元素

3.1 HashSet

HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable

  • 哈希表数据结构

  • 无序,不能重复

  • 无参构造创建一个HashMap,默认初始容量为16

  • add() 方法添加对象,需要判断两个点

    • 1.调用需添加对象的的hashCode()方法,对比set中已存在对象的hash是否相等

    • 2.调用添加对象的equals()方法,与set中已存在对象进行比较

    • 只有以上两点都返回true时,set才会添加新对象.

  • HashCode集合判断是否重复的关键就在于 Object的hashCode和equals方法

  • 线程不安全

3.2 LinkedHashSet

LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable

  • 基于链表和哈希表的结构

  • 使用链表来记录对象添加的顺序,使用哈希表来判定元素的唯一

  • 底层是创建了一个初始容量为16的LinkedHashMap

  • 没有自己的特定方法,使用上和set接口一致

3.3 TreeSet

TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable

  • 底层是红黑树数据结构,将集合中的对象进行比较,重复的则不添加

  • 基于TreeMap实现

  • 默认无参构造是基于自然顺序排序(从小到大), 自定义的对象添加到TreeSet里面,需要实现Comparable接口

    • 当前对象实现Comparable接口的compareTo(A a)方法,返回值1表示比指定对象a大,0 表示相等, -1 表示比指定对象a小.

    • compareTo()方法是自然比较方法

  • 如果不想按自然顺序排序,TreeSet构造器还可以传入Comparator进行自定义排序,比如从大到小

      public TreeSet(Comparator<? super E> comparator) {
           throw new RuntimeException("Stub!");
       }
    

    Comparator

      int compare(T var1, T var2);
      var1 > var2 返回1
      var1 == var2 返回0
      var < var2 返回-1
      以上返回值会使集合按照从小到大排序
    
  • 分析TreeSet中的TreeMap可以发现,优先使用Comparator的compare()进行排序,如果没有Comparator,则使用对象的compareTo()方法进行排序

4.Map

表示映射关系,以键值对key-value形式存在

  • 特点:

    • key无序不重复,value可重复

    • 一个key只能映射一个值

    • Map是存储了多个键值对 Map.Entry<k,v> 的集合

  • 常用方法

      put(k,v) 添加元素
    
      get(k) 返回指定key的值
    
      keySet() 以set集合返回所有的key
    
      values() 以Collection的形式返回所有的值
    
      size() 获得键值对的个数
    
      entrySet() 返回Entry<k,V>的set集合
          HashMap<String,Object> map = new HashMap<>();
          Set<Map.Entry<String, Object>> entries = map.entrySet();
          for (Map.Entry<String, Object> entry : entries){
              String key = entry.getKey(); //键
              Object value = entry.getValue(); //值
          }
    

4.1 HashMap

  • 基于哈希表的Map接口的实现类

  • 非同步,允许使用null键和null值,除此之外,与HashTable类大致相同

4.1 TreeMap

  • 作为key的元素,需要实现hashCode()和equals()之外,还需要实现Comparable接口,重写compareTo()方法,compareTo()方法需要正确返回整数,负数以及0

  • treeMap 与 hashMap不同,hashMap需要根据equals方法来判断key是否相等,而treeMap是根据

compareTo() == 0 判断是否相等.

4.2 Map和set的关系

  • Set底层是用Map数据结构,xxxSet底层就用xxxMap数据结构,如HashSet --> HashMap

  • Set集合不会重复的关键:

    Set集合的元素是底层Map用key来保存,用一个常量作为value,
    所有的key都映射到这个常量,满足键值对的要求,

    key的不重复特性保证了Set的元素是不重复的

5.集合相关类

5.1 Collections

  • 集合的工具类
  • 常用方法:

    shuffle() 打乱集合中元素的顺序

    sort() 对集合中的元素进行排序

    synchronizedCollection(Collection<T> c):返回线程安全(同步)的collection

    synchronizedMap(Map<k,v> m):返回线程安全(同步)Map

  • 使用线程安全的集合需要注意的地方:

    进行迭代的时候,迭代的代码必须同步

       List<String> list = new ArrayList<>();
      Collection<String> collection = Collections.synchronizedCollection(list);
      synchronized (collection){
          //迭代需要进行同步
          Iterator<String> iterator = collection.iterator();
          while (iterator.hasNext()){
                  iterator.next();
          }
      }
    

5.2 Arrays

Arrays.asList(T... t)  目的是将数组转成集合,得到的集合不允许删除,增加,只能查询
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容

  • 四、集合框架 1:String类:字符串(重点) (1)多个字符组成的一个序列,叫字符串。生活中很多数据的描述都采...
    佘大将军阅读 747评论 0 2
  • 集合类简介 为什么出现集合类?面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就要对对象进...
    阿敏其人阅读 1,416评论 0 7
  • 自定义泛型 1.1、泛型的定义介绍 在集合中,不管是接口还是类,它们在定义的时候类或接口名的后面都使用<标识符>,...
    Villain丶Cc阅读 8,739评论 0 7
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,373评论 0 4
  • Java集合类可用于存储数量不等的对象,并可以实现常用的数据结构如栈,队列等,Java集合还可以用于保存具有映射关...
    小徐andorid阅读 1,936评论 0 13