美文网首页
Java基础 - 集合

Java基础 - 集合

作者: ADMAS | 来源:发表于2019-04-15 17:13 被阅读0次

    集合

    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)  目的是将数组转成集合,得到的集合不允许删除,增加,只能查询

    相关文章

      网友评论

          本文标题:Java基础 - 集合

          本文链接:https://www.haomeiwen.com/subject/qizgiqtx.html