Java学习笔记05(集合框架)

集合

集合概述

由于数组的灵活性不够,Java提供一些特殊的集合类,可以存储任意类型的对象,并且长度可以变化。

分为单列集合Collection和多列集合Map;

Collection

Collection:单列集合的根接口,用来储存符合某些要求的元素。

​ List集合主要存储有序可重复的元素。

​ Set集合主要存储无序不可重复的元素。

​ ArrayList 实现类;

​ List 子接口: LinkedList 实现类;

​ Vector 实现类;

​ Collection 接口:

​ HashSet 实现类; --> 子类 LinkedHashSet;

​ Set 子接口:

​ TreeSet 实现类;

Map

Map:双列集合的根接口,用来存储 具有 键(key)和 值(value)映射关系的元素;

​ Hashtable 实现类; --> 子类 Prorerties

Map 接口: HashMap 实现类; --> 子类 LinkedHashMap

​ TreeMap 实现类;

List接口

List接口 继承 Collection接口,实现了List接口的对象成为List集合。

List集合中允许出现重复的元素,元素以线性方式进行存储,可以通过索引的方式访问元素。

List集合中的元素有序,即 元素的存入顺序和取出顺序一致。

ArrayList集合

ArrayList集合是List接口的一个实现类, 可以看作是一个长度可变得数组,它的内部的数组存储结构是数组;

在对集合进行某位置的删除和增加操作时会创建一个新的数组,不适合大量的增删操作,但是方便利用索引取出某元素,方便遍历和查找元素。

ArrayList的大部分方法都是从 Collection 和 List 接口中继承过来的;

一些方法举例:

  ArrayList list = new ArrayList();   
        list.add("str1");				//向 list集合中增加元素
        list.add("str2");
        System.out.println(list.size());   //  .size()  集合的大小
        System.out.println(list.get(1));  //   .get(index)  取出 索引为index的元素

ArrayList 好似 线性表;

LinkedList集合

LinkedList集合是List接口的一个实现类,好似数据接口中的链表,方便增删元素;

该集合 内部 有 两个 Node 类型 的 fist 和 last 属性 维护 一个双向循环链表;

LinkedList的方法除了从Collection 和 List接口中继承过来的 还有 一些专门处理增删查改的一些方法;

一些方法的举例:

 LinkedList link = new LinkedList();
 link.add("1");           //向集合中添加元素
 link.add("2");
 link.offer("offer");   //向集合尾部增加元素;
 link.push("push");    //向集合头部增加元素;
 System.out.println(link);
 Object obj = link.getFirst(); //得到第一个元素
 link.removeFirst();         //删除集合中的第一个元素
 link.pollLast();              //删除集合中的最后一个元素
 System.out.println(link);
 link.add(1,"center");   //在  索引为 1 的位置上 添加 center 元素;
 System.out.println(link);

Collection集合遍历

Iterator遍历集合

Iterator接口是java集合框架中的一员, Collection 和 Map 主要用来存储元素,而 Iterator 主要用来 遍历 Collection集合中的元素;所以 Iterator对象也叫迭代器;

通过下面例子 介绍 Iteractor迭代器的使用:

     LinkedList link = new LinkedList();
        link.add("1");           //向集合中添加元素
        link.add("2");
        Iterator iterator = link.iterator();  //通过 Collection集合中的iterator()方法获取Iterator对象
        while (iterator.hasNext()){            //  .hasNext()判断是否有下一个元素
            System.out.println(iterator.next());  // .next()获取下一个元素;
        }

foreach遍历集合

从JDK5开始提供了foreach循环。 用于遍历数组或者集合中的元素; 就是增强 for 循环;

语法如下:

for( 容器中元素类型 临时变量 : 容器变量) {

​ 执行语句;

}

foreach循环注意点: 在循环中不能够改变 集合或数组元素的值,只能对其进行访问;

JDK8 中的 forEach 遍历集合

list.forEach(obj -> System.out.println(obj)); // list 集合;

Set接口

Set 和 List 接口类似,方法和 Collection中的方法基本一致, 只是比 Collection 接口更加严格;

与 List 不同的是,Set接口中的元素无序, 并且以某种规则保证存入的元素不重复;

Set接口的两个实现类:HsahSet (根据对象的哈希值来确定元素在集合中的存储位置) 和 TreeSet ( 以二叉树的方式存储数据 )

HashSet集合

Set 接口的一个实现类,所存储的元素不可重复,且无序;

为什么 HashSet 中的 元素 不会重复?

答:当向 HashSet 集合中 添加 一个元素时,首先会 调用 该元素的 hashCode() 方法获取该元素的 哈希值。,通过 哈希值 来确定元素的存储位置,如果该存储位置上为空,就直接存入。如果不为空就 调用该 元素的 equal() 方法 与 该位置上的值进行比较,若为false就存入,若为true 就将该元素舍去;

因此,由于在判断存入的元素是否 重复时 需要用到 hashCode() 和 equal()方法 ,所以需要 在存入对象是,在此对象属于的类中 重写 Object类中的 hashCode()和 equal() 方法;

TreeSet集合

内部采用平衡二叉树的存储结构; 具有排序功能;

平衡二叉树:任意两个节点的左右子树的深度差的绝对值不超过1,也叫自平衡二叉查找树;

任意结点的左子树上的每个节点的值都比该节点小,右子树上的每个节点的值比该节点大;

TreeSet也不会存储重复的元素,他在继承Set接口的基础上有一些特有的方法;

TreeSet类中的方法举例:

TreeSet ts = new TreeSet();
        ts.first();              //获取首元素
        ts.last();               //获取尾元素
        ts.lower(10);         //获取集合中小于       10 的 最大元素 ,没有返回 null;
        ts.floor(10);         //获取集合中小于或等于 10 的 最大元素 ,没有返回 null;
        ts.higher(10);       //获取集合中大于       10 的 最小元素 ,没有返回 null;
        ts.ceiling(10);       //获取集合中大于或等于   10 的 最小元素 ,没有返回 null;
        ts.pollFirst();         //删除第一个元素并返回;
        ts.pollLast() ;        //删除最后一个元素并返回;

为什么TreeSet中的元素会自动排序?

不论向TreeSet集合中添加的元素的顺序如何,这些元素都能够自动排序; 这是因为添加过程中 都会对集合中的元素进行比较。比较时会调用compareTo()方法,该方法在Comparable接口中定义的。

因此,要想对集合中的元素进行排序,就必须实现Comparable接口和compareTo()方法,在Java中的大部分类都实现了Comparable接口,并且实现了 compareTo()方法,如 Integer,,Double,String类;

也可以向 TreeSet 集合中 存入 自定义的 数据类型。 自定义的类型没有实现 comparable接口, 因此无法进行排序操作; Java提供两种排序规则解决这个问题。

  1. 自然排序‘

    TreeSet 集合中存储的对象所属的类必须实现 Compearable 接口,并重写 compareTo()方法;

  2. 定制排序

    可以 通过实现 Comparator接口 自定义一个 比较器类;

    在实例化 TreeSet 时,将 比较器的对象 作为 构造方法 的 参数;

Map接口

Map接口是一种双列集合,每一个元素都有 一个键对象 Key 和一个 值对象 Value; Key 和 Value 之间存在一种一对一的映射关系; 两个对象的数据类型可以任意,Key不能重复,这样就可以通过 Key 来找到唯一的Value;

HashMap集合

HashMap是Map接口的一个实体类,底层由哈希表构成,实际上就是一个 数组+链表 的组合体 。集合的主体部分是一个 Entry数组,用来存储键和值 Entry<E,V>; 数组的长度成为HashMap的容量capacity;每一个 数组 中又 可以存有一个链表,一般称数组为水平的,链表是竖直的;每个竖直部分成为一个桶bucket;引入链表是为了解决 哈希冲突;

其结构约如下:

// 竖着的 链表 bucket 桶

Entry<K,V> Entry<K,V> Entry<K,V> Entry<K,V> Entry<K,V> Entry<K,V> //横向的数组 ↓ ↓ ↓ ↓ Entry<K,V> Entry<K,V> Entry<K,V> Entry<K,V> ↓ ↓ Entry<K,V> Entry<K,V>

向 HashMap 添加元素时,先调用 添加元素的 key对象 的 hash(k) 方法,找到要存储的桶位置(在数组中的位置),然后判断该位置上是否为空,若为空,则直接添加元素;若不为空,则在链表中挨个比较 是否 集合中的元素 的键值 equal(k);若相等,则将 新值替换旧值 ,并返回原来的旧值;若不相同,则在链表的头部添加 一个新的节点插入新添加的元素;

HashMap 一些方法举例:

 Map map = new HashMap();    // 多态的应用 , map 只能调用 Map接口中存在的方法
      					   // 由于 HashMap类必须重写Map中的方法,所以map调用的方法都是HashMap中重写后的方法;
        map.put(1, "d");              // 向 Map 中存储数据
        map.containsKey(1);   //是否存在 Key==1 的 元素,存在返回true,否则返回 false;
        map.get(1);           //获得指定 k对象 的 值;
        map.keySet();         //以 Set集合的形式 得到key的集合并返回;
        map.values();         //以 Collection 集合的形式 得到 Value的集合并返回
        map.replace(1,"e");   //将 key=1 的 值 替换为 “e”;
        map.remove(1);   //删除 key=1 的 键值对元素;

当添加元素Key的值 已经存在时,则会会新的value值替换旧的Value值;

Map集合遍历

Map集合的遍历和Collection集合的遍历基本相同。

Iterator遍历jMap集合

将Map集合转换为 Iterator接口对象,有两种方式:keySet()方法 和 entrySet()方法;

  1. keySet()方法

    先将 Map集合中的 键 存到 Set集合中,然后生成 Iterator接口对象;
    代码举例:

		Map map = new HashMap();
	    Set set = map.keySet();        // 将 键key 存入 set 集合;
        Iterator it = set.iterator();  // 生成set 集合的 迭代器;(一个键值迭代器)
        while (it.hasNext()){
            Object key = it.next();
            Object value = map.get(key);  //得到 key 对应的 value;
            System.out.println(key + "=" + value);
        }
  1. entrySet()方法。

    该方法是将 Map中的 键值对 作为 一个整体返回 到 Set集合中, 然后 生成 Set集合的 迭代器。 Entry 是 Map接口内部类,可以通过Entry 类型的元素 取出Map 中元素的 键 和 值(通过 getKey()方法 和 getValue() 方法);

    代码举例:

    		Map map = new HashMap();
     	    Set set = map.entrySet();      // entrySet 将键值对作为整体 返回给set
            Iterator it = set.iterator();
            while (it.hasNext()) {
                Map.Entry entry = (Map.Entry) it.next();  //Map.Entry  entry类型
                Object key = entry.getKey();
                Object value = entry.getValue();
                System.out.println(key + "=" + value);
            }
    

    forEach遍历Map集合

    map.forEach((key, value) ->System.out.println(key+"="+value));
    

注意点:HashMap 集合 不能保证存入和取出的元素的顺序;若想要 存入和取出的顺序相同,Java提供一个 LinkedHashMap集合,它是HashMap的子类。和LinkedList 类似,用双向链表维护内部元素的关系;

TreeMap集合

存放键值之间的映射,不允许键重复;与HashMap集合的区别:TreeMap中的元素都是按照顺序排列的,内部存储结构是二叉树;

该集合 和 TreeSet集合 类似, 存储过程中都需要 进行元素比较,实现Comparable接口。也可以实现自己的比较器Comparator

Properties集合

Map中的另一个实现类HashTable实现类,与HashMap类似,主要区别在于 HashTable 是线程安全的,但是其效率不如HashMap,现在基本已经被HashMap代替;但 Properties类 是 HashTable的一个子类,该类经常用来存储应用的配置项;

泛型

泛型就是 规定 存入集合的数据类型;使用方法就是 在集合类型名后面加一个<参数化类型>,里面放入要存入的数据类型;

使用举例代码如下:

  ArrayList<String> list = new ArrayList<>();   //  <Srting> 只能往集合中传入 String 类型 的元素        list.add("String");        list.add(1);          // 报错 , 因为 list集合 的泛型 为字符串;

为什么使用泛型?
答:因为可以向集合中存入任意类型的对象元素,当存入一个对象元素,在取出时,集合会忘记 该对象的数据类型,于是会将元素编译成Object 类型;若在取出时进行强制类型转化,容易出现错误(因为不同类型之间可能不能强制转化);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值