集合常用类简介

 根据b站韩顺平教育韩顺平教育java教学视频学习的学习笔记。个人学习理解,如有疏漏,敬请改正。

目录

集合的优点

集合框架体系图

 Collection

 List接口和常用方法

ArrayList

 Vector

LinkedList

List集合的选择

Set接口和常用方法

HashSet

LinkedHashSet

Map接口和常用方法

Map接口实现类的特点(很实用 JDK8)

HashMap

HashTable

Properties

集合选型规则

TreeSet与TreeMap

Collections工具类

集合的优点

  1. 可以动态保存任意多个对象,使用比较方便
  2. 提供了一系列方便的操作对象的方法:add、remove、set、get等
  3. 使用集合添加,删除新元素的代码更加简洁

集合框架体系图

只对于常用的实现类

单列集合(集合里存放的是单个元素)

 双列集合(集合里存放的是键值对)

 Collection

1、Collection实现子类可以存放多个元素,每个元素可以是Object

2、有些Collection的实现类,可以存放重复的元素,有些不可以

3、有些Collection的实现类,有些是有序的(List),有些不是有序(Set)

4、Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的

     //单列集合Collection接口方法演示,以ArrayList 演示
        List list = new ArrayList();
        //add()添加元素,可以是任意对象
        list.add(123);//底层是add(new Integer(123));
        list.add("hello");
        list.add(12.23);
        list.add(true);
        System.out.println("list" + list);
        //remove()删除元素
        list.remove(0);//以下标的方式删除元素
        list.remove(12.23);//直接指定删除元素
        System.out.println("list" + list);
        //addAll() 添加多个元素,参数是Collection对象
        ArrayList list1 = new ArrayList();
        list1.add("红楼梦");
        list1.add("水浒");
        list.addAll(list1);
        System.out.println("list1"+ list);
        //removeAll() 删除多个元素
        list.removeAll(list1);
        System.out.println("list" + list);
        //contains() 查找元素是否查找,
        System.out.println(list.contains("hello"));//T
        //containsAll()查找多个元素是否存在
        System.out.println(list.containsAll(list1));//F
        //isEmpty()判断是否为空,返回布尔类型
        System.out.println(list.isEmpty());//F
        //size 返回集合内的元素个数
        System.out.println(list.size());//2
        //clear 清空
        list.clear();
        System.out.println("list" + list);

Collection接口遍历元素的方式

1、使用Iterator(迭代器)

  • Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
  • 所有实现了Collection接口的集合类都有一个iterator()方法,用于返回一个实现了Iterator接口的类对象,即可以返回一个迭代器
  • Iterator仅用于遍历集合,Iterator本身并不存放对象

迭代器方法

HasNext():判断是否还有下一个元素,用在while循环的判断

next():按个返回集合里的元素

在调用iterator.next()方法之前必须要调用iterator.hasNext()进行判断是否还有下一个元素,否则会报错

   //使用迭代器遍历Collection集合
        Collection list = new ArrayList();
        list.add(new Book("红楼梦","曹雪芹",198));
        list.add(new Book("三国演义","罗贯中",188));
        list.add(new Book("水浒传","施耐庵",178));
        System.out.println(list);
        //得到list对应的迭代器
        Iterator iterator = list.iterator();
        //可以使用快捷键itit(Ctrl+j),快速搭建while循环遍历集合
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);
        }
        //当遍历完成以后,迭代器指向最后的元素,这时再使用iterator.next();就会报错,所以要重置迭代器
        iterator = list.iterator();

2、使用增强for循环

  • 增强for循环,可以代替iterator迭代器,特点:增强for就是简化版的iterator,本质一样。只能用于遍历集合或数组

基本语法

for(元素类型 元素名:集合名或数组名){
访问元素

}

   for (Object book : list){
            System.out.println("book = " + book);
        }

        int[] it = {1,2,3,4};
        for(int in : it){
            System.out.println("in=" + in);
        }

 List接口和常用方法

List接口是Collection接口的子接口

  • List集合类中元素有序(添加顺序和取出顺序一致)、且可重复
  • List集合类中的每个元素都有其对应的顺序索引,即支持索引
  • List接口的实现类有很多,可咱API中查看,常用的有ArrayList、LinkedList和Vector

List接口方法

    //List方法实现
        //1、List集合类中元素有序、可重复
        List list = new ArrayList();
        list.add("zdz");
        list.add("Maddox");
        list.add("Jack");
        list.add("Tom");
        list.add("Maddox");
        System.out.println("list :"+ list);
        //2、add(int index,Object els)  可以在index位置插入一个元素
        list.add(1,"张无忌");
        System.out.println("list:" + list);
        //3、addAll(int index,Collection els) 可以在index位置后插入一个Collection集合
        List list1 =  new ArrayList();
        list1.add("zxs");
        list1.add("Ajax");
        list.addAll(1,list1);
        System.out.println("list :"+ list);
        //4、get(index) 获取index处的元素
        System.out.println("list3= "+ list.get(2));
        //5、indexOf(Object obj) 返回obj在集合中首次出现的位置
        System.out.println("Ajax's index = "+ list.indexOf("Ajax"));
        //lastIndexOf(Object obj)  返回obj在集合中最后一次出现的位置
        System.out.println("Maddox's index = "+ list.lastIndexOf("Maddox"));
        //Object remove(int index) 删除index处的元素并返回此元素
        Object list2 = list.remove(1);
        System.out.println("list :" + list);
        System.out.println("list2 = "+ list2);
        //Object set(int index, Collection els)  els替换index处的元素
        list.set(0,"dasb");
        System.out.println("list :" +list);
        //List subList(int startIndex,int endIndex) 返回从startIndex开始到endIndex之间的子集合
        //注意 startList <= subList < endList
        List list3 = list.subList(2,5);
        System.out.println("list3 :" + list3);

List的三种遍历方式(ArrayList、LinkedList、Vector)

  1. 使用iterator
  2. 使用增强for循环
  3. 使用普通for循环(使用get()方法获取下标)

ArrayList

  • ArrayList可以存放所有元素,包括Null(空元素),Null可以为多个
  • ArrayList是由数组来实现数据存储的
  • ArrayList基本等同于Vector,除了ArrayList是线程不安全(但执行效率高),在多线程情况下,不建议使用ArrayList。
  • ArrayList中维护了一个Object类型的数组elementData,当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第一次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍
  • 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍

 Vector

  • Vector底层也是一个对象数组:protected Object[] elementData;
  • Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized关键字。在开发中,需要线程同步时,考虑使用Vector
  • ArrayList中维护了一个Object类型的数组elementData,当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量默认为10,容量满后,直接两倍扩容,调用无参构造器的时候其实就是调用有参构造器,参数为10,所以两者一样

public Vector(){

       this(10);

}

  • 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则按照两倍扩容

LinkedList

1、LinkedList底层实现了双向链表和双端队列

LinkedList中维护了两个属性first和last分别指向首结点和尾结点

LinkedList的CRUD操作对应方法,add()、remove()、set()、get()。其中remove()默认删除第一个结点。

2、所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高

3、可以添加任意元素(元素可以重复),包括null

4、线程不安全,没有实现同步

 LinkedList的CRUD操作

 //LinkedList的CRUD操作
        //增加
        LinkedList list = new LinkedList();
        list.add(1);
        list.add("hello");
        list.add(999);
        System.out.println("list :"+ list);

        //删除
        list.remove();//删除链表第一个元素,其调用了 list.removeFirst()
        System.out.println("list :"+ list);
        list.remove(1);
        System.out.println("list :"+ list);
        list.add(2333);
        System.out.println("list :"+ list);
        list.add(12);
        System.out.println("list :"+ list);
        list.add(2,234);
        System.out.println("list :"+ list);

        //获取元素个数
        System.out.println("list的元素个数:"+ list.size());

        //改
        list.set(2,"你哈");
        System.out.println("list :"+ list);

        //查
        System.out.println(list.get(2));
        System.out.println(list.indexOf("hello"));

        //遍历
        System.out.println("=====迭代器遍历=====");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println("list :"+ next);
        }

        System.out.println("=====增强for遍历=====");
        for (Object e : list) {
            System.out.println("list :"+ e);
        }

        System.out.println("=====普通for遍历=====");
        for (int i = 0; i < list.size(); i++) {
            System.out.println("list :" + list.get(i));
        }

List集合的选择

在不考虑线程安全的情况下,使用ArrayList,否则Vector

1、如果改查的操作多,ArrayList

2、如果增删的操作多,选择LinkedList

3、一般来说,在程序中,大多数的操作都是查询,因此大部分情况下选择ArrayList

4、在一个项目中,根据业务灵活选择,也可能一个模块使用的是ArrayList,另外一个模块是LinkedList

Set接口和常用方法

和List接口一样,Set接口也是Collection的子接口,因此,常用方法和Collection接口一样

Set接口的实现类的对象(Set接口对象),不能存放重复的元素,可以添加null

Set接口的遍历方式

注意:取出的顺序虽然不是添加的顺序,但是每次取出时顺序都是一样的

迭代器

增强for循环

不能使用索引的方式来获取(Set里存放的是无序元素,取出时的顺序不会和添加的顺序一致)

HashSet

实现了Set接口

1、HashSet实际上是HashMap(底层)

public HashSet(){

map = new HashMap<>();

}

  • 添加一个元素时,先得到hash值(HashCode方法)-会转成索引值
  • 找到存储数据表table,看这个索引位置是否已经存放有元素
  • 如果没有直接加入
  • 如果有,调用equals比较,如果相同就放弃添加,如果不同,则添加到最后
  • 在Java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

3、可以存放null值,即可以有一个空值

4、HashSet不保证元素是有序的,取决于hash后,再确定索引的结果(即不保证存放元素的顺序和取出顺序一致)

5、和Set一样不能有重复值(元素/对象)

LinkedHashSet

LinkedHashSet是HashSet的子类

LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表

LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表来维护元素的次序,这使得元素看起来是以插入顺序保存的

LinkedHashSet不允许添加重复元素

在LinkedHashSet中维护了一个hash表和双向链表,双向链表设置头结点和尾结点,每个结点有pre和next属性,这样就可以形成双向链表并保证在遍历LinkedHashSet时插入顺序和遍历顺序一致。

在添加一个元素时,先求hash值,再求索引,确定该元素在table的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加) 

Map接口和常用方法

Map接口实现类的特点(很实用 JDK8)

1、Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)

2、Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中

3、Map中的key不允许重复,原因和HashSet一样,当有重复的key出现的时候相当于与先出现的key对应的value替换原来key下面的value

4、Map中的value可以重复

5、Map的key可以为null但只能有一个为null,value也可以为null且可以有多个

6、常用String类作为Map的key

7、key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value

8、Map存放的一对k-v是放在一个Node中的,

常用方法

map.put(“no1”,”hello”);//添加map元素方法

map.get(key);//根据key来读取元素

remove:根据key删除映射关系

size:获取元素个数

isEmpty:判断个数是否为0

clear:清除

containsKey:查找键是否存在

Map六大遍历方式

4个使用到的方法

1、containsKey:查找键是否存在

2、keySet:获取所有的键

3、entrySet:获取所有关系k-v

4、values:获取所有的值

6种遍历方式

 Map map = new HashMap();
        map.put("Hello","World");
        map.put("罗贯中","三国演义");
        map.put("施耐庵","水浒");
        map.put(null,"老房子");
        map.put("Maddox",null);

        //第一组 keySet获取键
        Set set = map.keySet();
        System.out.println("====方式一  增强for循环-keySet======");
        for (Object key : set){
            System.out.println("NO1:"+ key + "-" + map.get(key));
        }

        System.out.println("====方式二  迭代器-keySet======");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object key =  iterator.next();
            System.out.println("NO2:"+ key + "-" + map.get(key));
        }

        //第二组 使用values获取所有的值 仅仅能够打印值
        Collection values = map.values();
        //这里可以使用所有的Collection遍历方法
        System.out.println("====方式三  增强for循环-values======");
        for (Object value : values){
            System.out.println("NO3:"+value);
        }

        System.out.println("====方式四  迭代器-values======");
        Iterator iterator1 = values.iterator();
        while (iterator1.hasNext()) {
            Object value =  iterator1.next();
            System.out.println("NO4:"+value);
        }

        //第三组 entrySet:获取所有关系k-v
        Set entrySet = map.entrySet();
        System.out.println("====方式五  增强for循环-entrySet======");
        for(Object entry : entrySet){
            Map.Entry m = (Map.Entry)entry;
            System.out.println("NO5:" + m.getKey() + "-" + m.getValue());
        }

        System.out.println("====方式六  迭代器-entrySet======");
        Iterator iterator2 = entrySet.iterator();
        while (iterator2.hasNext()) {
            Object entry =  iterator2.next();
            Map.Entry m = (Map.Entry)entry;
            System.out.println("N6:" + m.getKey() + "-" + m.getValue());
        }

HashMap

HashSet底层即使用了HashMap,两者之间底层逻辑基本相同

1.Map接口的常用实现类:HashMap、HashTable和Properties

2.HashMap是Map接口使用频率最高的实现类

3.HashMap是以key-val对的方式来存储数据

4.key不能重复,但是值val可以重复,允许使用null键和null值

5.如果添加相同的key则会覆盖原来的key-val,等同于修改

6.与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的

7.HashMap没有实现同步,一次是线程不安全的(方法没有做同步互斥的操作,没有synchronized)

扩容机制(和HashSet相同)

1.HashMap底层维护了Node类型的数组table,默认为null

2.当创建对象时将加载因子(loadfactor)初始化为0.75

3.当添加key-val时,通过key的哈希值得到在table的索引,然后判断该索引处是否有元素,如果没有元素直接添加;如果该索引处有元素,继续判断该元素的key是否和准备加入的key相等,如果相等则直接替换val;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够则需奥扩容

4.第一次添加,需要扩容table容量为16,临界值(threshold)为12(16*0.75)

5.以后再扩容,则需要扩容table容量为原来的2倍(32),临界值为原来的2倍,即(32*0.75=24),以此类推

6.在Java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

HashTable

存放的元素是键值对:k-v

键和值都不能为null

使用方法基本上和HashMap一样

是线程安全的

HashTable扩容(源码)

Properties

  1. Properties类继承自HashTable类并且实现了Map接口,也是使用一种键值对的形式来保存数据,所以也不能有null值
  2. 使用特点和HashTable类似
  3. Properties还可以用于从xxx.properties文件中加载数据到Properties类对象并进行读取和修改

说明:xxx.properties文件通常为配置文件,这个知识点在IO流举例

集合选型规则

在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行选择

1、先判断存储的类型(一组对象[单列]或一组键值对[双列])

2、一组对象:Collection接口

允许重复:List

    增删多:LinkedList[底层维护了一个双向链表]

    改查多:ArrayList[底层维护Object类型的可变数组]

不允许重复:Set

    无序:HashSet[底层是HashMap,维护了一个哈希表即[数组+链表+红黑树]

    排序:TreeSet

    插入和取出顺序一致:LinkedHashSet,维护数组+双向链表

3、一组键值对:Map

    键无序:HashMap数组+链表+红黑树]

    键排序:TreeMap

    键插入和取出顺序一致:LinkedHashMap

    读取文件:Properties

TreeSet与TreeMap

TreeSet

当我们使用无参构造器,创建TreeSet时,仍然是无序的

使用TreeSet提供的一个构造器,可以传入一个比较器

 

 TreeMap

当我们使用无参构造器,创建TreeMap时,仍然是无序的

 

Collections工具类

Collections是一个操作Set、List和Map等集合的工具类

Collections提供了一些列静态的方法对集合元素进行排序、查询和修改等操作

排序操作(均为static方法)

reserve(List):反转List中元素的顺序

shuffle(List):对List集合元素进行随机排序

sort(List):根据元素的自然顺序对指定List集合元素按升序排序

sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序

swap(List,int i,int j):将指定List集合中的i处元素和j处元素进行交换

查找、替换

Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素

Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素

Object min(Collection):和max相同

Object min(Collection,Comparator):和max相同 int frequency(Collection,Object):返回指定集合中指定元素的出现次数

void copy(List dest,List src):将src中的内容复制到dest中

boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的所有旧值

      /*
        Collections工具类
        Collections是一个操作Set、List和Map等集合的工具类
        Collections提供了一些列静态的方法对集合元素进行排序、查询和修改等操作
      */
        List list = new ArrayList();
        list.add("Hello");
        list.add("World");
        list.add("Fine");
        list.add("wowo");
        list.add("surprise");
        /*
        排序操作(均为static方法)
        reserve(List):反转List中元素的顺序
        */
        Collections.reverse(list);
        System.out.println("list - reverse+ " + list);
        /*
        shuffle(List):对List集合元素进行随机排序
        */
        Collections.shuffle(list);
        System.out.println("list - shuffle + " + list);
//        sort(List):根据元素的自然顺序对指定List集合元素按升序排序
        Collections.sort(list);
        System.out.println("list - sort + " + list);;
//        sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
        Collections.sort(list, new Comparator() {
            @Override
            public  int compare(Object o1,Object o2){
                return (((String)o1).length() - ((String)o2).length());
            }
        });
        System.out.println("list - sort - com + " + list);
//        swap(List,int i,int j):将指定List集合中的i处元素和j处元素进行交换
        Collections.swap(list,2,3);
        System.out.println("list - swap + " + list);
//        查找、替换
//        Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
        System.out.println("Max = " + Collections.max(list));
//        Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
        System.out.println("MaxOfLength = " + Collections.max(list, new Comparator() {
            @Override
            public int compare(Object o1,Object o2){
                return (((String)o1).length() - ((String)o2).length());
            }
        }));
//        Object min(Collection):和max相同
//        Object min(Collection,Comparator):和max相同 int frequency(Collection,Object):返回指定集合中指定元素的出现次数
//        void copy(List dest,List src):将src中的内容复制到dest中
        List dest = new ArrayList();
        //为了完成一个完整的拷贝,需要先给dest赋值,使其和list大小相同,否则会有下标越界的错误
        for (int i = 0;i < list.size();i++){
            dest.add(" ");
        }
        Collections.copy(dest,list);
        System.out.println("dest  = " + dest);
//        boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的指定旧值
        Collections.replaceAll(list,"wowo","tom");
        System.out.println("list + replaceAll = " + list);

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值