尚硅谷JavaSE入门笔记 - P516 ~ P561

集合

目录

前言

本文为B站Java教学视频BV1Kb411W75N的相关笔记,主要用于个人记录与分享,如有错误欢迎留言指出。
本章笔记涵盖视频内容P516~P561

1. 集合框架概述

  • 定义:集合,数组都是对多个数据进行存储操作的结构,简称Java容器;此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储
  • 数组在储存多个数据方面的缺点:
    • 一旦初始化以后,其长度就不可修改
    • 数组中提供的方法非常有限,对于添加,删除,插入数据等操作非常不便,同时效率不高
    • 对于获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
    • 数组存储数据的特点:有序,可重复。对于无序,不可重复的需求,不能满足
  • 集合框架:
    • Collection接口:单列集合,用来存储单个单个的对象
      • List接口:存储有序的,可重复的数据(ArrayList,LinkedList,Vector)
      • Set接口:储存无序的,不可重复的数据(HashSet,LinkedHashSet,TreeSet)
    • Map接口:双列集合,用来存储一对(key - value)的数据(HashMap,LinkedHashMap,Hashtable,Properties)

2. Collection接口

2.1 常用方法

  • add(Object e):将元素e添加到集合coll中
  • size():获取添加的元素的个数
  • addAll(Collection coll):将coll集合中的元素添加到当前的集合中
  • clear():清空集合元素
  • isEmpty():判断当前集合是否为空
  • contains(Object obj):判断当前集合中是否包含obj
  • containsAll(Collection coll):判断形参coll中的所有元素是否都存在于当前集合中
  • remove(Object obj):从当前集合中移除obj元素
  • removeAll(Collection coll):从当前集合中移除coll中包含的所有元素
  • retainAll(Collection coll):获取当前集合和coll集合的交集,并返回给当前集合
  • equals(Object obj):当当前集合和形参集合的元素都相同时,返回true
  • hashCode():返回当前对象的哈希值
  • toArray():转化集合为数组
  • literator():返回Iterator接口的实例,用于遍历集合元素。
public void test(){
    Collection coll = new ArrayList();	//以collection接口下的ArrayList类型为例
    
    //1. add(Object e):将元素e添加到集合coll中
    coll.add("AA");
    coll.add(123);	//自动装箱
    coll.add(new Date());
    coll.add(new Person("Jerry",20));	//自定义类型
    
    //2. size():获取添加的元素的个数
    System.out.println(coll.size());//4
    
    //3. addAll(Collection coll1):将coll1集合中的元素添加到当前的集合中
    Collection coll1 = new ArrayList();
    coll1.add(456);
    coll1.add("CC");
    coll.addAll(coll1);
    System.out.println(coll.size());//6
    
    //4. clear():清空集合元素
    coll.clear();	//清空的是集合内部元素,而不是集合本身
    
    //5. isEmpty():判断当前集合是否为空
    System.out.println(coll.isEmpty());	//true
    
    coll.add("AA");
    coll.add(123);	//自动装箱
    coll.add(new Date());
    coll.add(new Person("Jerry",20));
    
    //6. contains(Object obj):判断当前集合中是否包含obj
    System.out.println(coll.contains(123));//true
/*
该方法在判断时会调用obj类内的equals(),若该子类重写了equals则比较内部元素,此处返回true;若该子类未重写equals则比较地址值,此处返回false;同理,如果参数是一个类名(地址值),则无论有没有重写都会返回false
*/
    System.out.println(coll.contains(new Person("Jerry",20)));
    
    //7. containsAll(Collection coll1):判断形参coll1中的所有元素是否都存在于当前集合中
    //Arrays.asList的作用是将数组转化为list,一般用于初始化简化代码,省去add的部分
    Collection coll2 = Arrays.asList(123,456);
    System.out.println(coll.containsAll(coll2));
    
    //8. remove(Object obj):从当前集合中移除obj元素
    coll.remove(123);
    //和contain一样remove需要用到equals()方法,自定义类需要重写
    coll.remove(new Person("Jerry",20));
    
    //9. removeAll(Collection coll1):差集,从当前集合中移除coll1中包含的所有元素
    Collection coll3 = Arrays.asList(123,456);
    coll.removeAll(coll3);
    
    //10. retainAll(Collection coll1):交集,获取当前集合和coll1集合的交集,并返回给当前集合
    Collection coll4 = Arrays.asList(123,456,789);
    coll.retainAll(coll4);
    
    //11. equals(Object obj):当当前集合和形参集合的元素都相同时,返回true
    //若形参本身有序,则比较在乎顺序;若形参本身无序,则比较不在乎顺序(ArrayList是有序的)
    Collection coll5 = Arrays.asList(123,456);
    System.out.println(coll.equals(coll5));
    
    //12. hashCode():返回当前对象的哈希值
    System.out.println(coll.hashCode());
    
    //13. 集合 → 数组:toArray()
    Object[] arr = coll.toArray();	//由于集合内部类型可能不一,所以用Object类数组接收较好
    for(int i = 0;i < arr.length;i++){
        System.out.println(arr[i]);
    }
    //13.1 数组 → 集合
    List<String> list = Arrays.asList(new String[]{"AA","BB","CC"});
    System.out.println(list);	//[AA,BB,CC]
    	//注意:这种方法对于基本数据类型可能会出错
    	List arr1 = Arrays.asList(new int[]{123,456});
    	System.out.println(arr1);//会直接报地址值,因为集合将整个数组都看成一个元素
    	//解决方法:
    	//方式一:
    	List arr2 = Arrays.asList(123,456);//直接添加
    	//方式二:
    	List arr3 = Arrays.asList(new Integer[]{123,456});//使用包装类
    	
    //14. literator():返回Iterator接口的实例,用于遍历集合元素。
    //(见下)
}

class Person{
    String name;
    int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

2.2 Iterator迭代器

  • 定义:Iterator对象称为迭代器,主要用于遍历Collection集合的元素。Iterator仅用于遍历集合,其本身并不提供承装对象的能力。集合对象每次调用iterator()方法都将得到一个全新的迭代器对象。

  • Iterator常用方法

//hasNext():判断是否还有下一个元素
//next():指针下移,并将下移后集合位置上的元素返回
Iterator iterator = coll.iterator;
while(iterator.hasNext()){
    System.out.println(iterator.next());
}
//remove():删除当前集合位置上的元素
//与集合的remove方法不同,Iterator通过遍历迭代器对象的方法删除集合的元素
//如果还未调用next()或在上次调用next方法之后已经调用了remove方法,再调用remove都会报错
Iterator iter = coll.iterator;	//回到起点
while(iter.hasNext()){
    Object obj = iter.next();
    if(obj.equals("Tom")){
        iter.remove();
    }
}
  • foreach (增强for循环)
//for(数组元素的类型 局部变量 : 数组对象)
//遍历集合
for(Object obj : coll){
    System.out.println(obj);
}
//遍历数组
for(int i : arr){
    System.out.println(i);
}

/*
foreach只能用于遍历!不能完全取代for!
如果使用foreach赋值,有可能会出现赋值后值没有改变的情况(比如String类型)
*/

2.3 List接口

  • 定义:List集合类中元素有序且可重复,集合中的每个元素都有对应的顺序索引,因此常用List替代数组。List接口的实现类常用的有:ArrayList,LinkedList和Vector

  • List接口下常用实现类的异同

    • 相同点
      • 三个类都实现了List接口,都可以存储有序的,可重复的数据
    • 不同点
      • ArrayList:作为List接口的主要实现类;线程不安全,效率高;底层使用Object[] elementData存储数据
      • LinkedList:对于频繁的插入,删除操作,使用LinkedList的效率比ArrayList高;底层使用双向链表存储
      • Vector:作为List接口的古老实现类;线程安全,效率低;底层使用Object[] elementData存储数据
  • List接口中的常用方法

    • void add(int index, Object ele):在index位置插入ele元素
    • boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
    • Object get(int index):获取指定index位置的元素
    • int indexOf(Object obj):返回obj在集合中首次出现的位置
    • int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
    • Object remove(int index):移除指定index位置的元素,并返回此元素
      • 此处相当于List重载了Collection中的remove方法,当remove参数为一个int型的时候,编译器会自动使用List中的方法,删除指定索引的数,而不是调用equals遍历数组删除指定值的数。如果要调用Collection中的方法,可以使用remove(Integer x)的方法
    • Object set(int index, Object ele):设置指定index位置的元素为ele
    • List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合

2.4 Set接口

  • 定义:Set接口是Collection的子接口,但其没有提供额外的方法;Set集合类中元素无序且不可重复,如果尝试把两个相同的元素加入同一个Set集合中则操作失败;Set判断两个对象是否相同使用的是equals()
  • Set接口下常用实的现类
    • HashSet:Set接口的主要实现类;线程不安全;可以储存null值
    • LinkedHashSet:HashSet的子类,在添加数据的同时,每个数据还维护了两个引用(指针),记录此数据的前一个和后一个数据,遍历其内部数据时,可以按照添加的顺序遍历。对于频繁的遍历操作,LinkedHashSet效率高于HashSet
    • TreeSet:可以按照添加对象的指定属性进行排序
  • Set中无序性与不可重复性的理解
    • 无序性:不等于随机性。储存的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定
    • 不可重复性:包整添加的元素按照equals()判断时,不能返回true,即:相同的元素只能添加一次。但是判断重复的方式涉及到哈希表底层原理,具体请看HashSet的元素添加过程
2.4.1 HashSet/HashLinkedSet
  • HashSet中元素的添加过程

    向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置,判断数组此位置上是否已经有元素

    • 若此位置上没有其它元素,则元素a添加成功

    • 若此位置上有其它元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值

      • 若hash值不相同,则元素a添加成功
      • 若hash值相同,则需要调用元素a所在类的equals()方法
        • 若equals()返回false,元素a添加成功
        • 若euqals()返回true,元素a添加失败

    jdk7中处理重复数组位置元素的方法是头插法添加链表

    jdk8中处理重复数组位置元素的方法是尾插法添加链表

2.4.2 TreeSet
  • 向TreeSet中添加的数据,要求是相同类的对象
  • TreeSet有两种排序方式:自然排序(实现Comparable接口)和定制排序(Comparator)
    • 自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,而不是equals()
    • 定制排序中,比较两个对象是否相同的标准为:compare()返回0,而不是equals()

3. Map接口

3.1 常用方法

  • Object put(Object key, Object value):将指定key-value添加到(或修改)当前map对象中

  • void putAll(Map m):将m中的所有key-value对存放到当前map中

  • Object remove(Object key):移除指定key的key-value对,并返回value

  • void clear():清空当前map中的所有数据

  • Object get(Object key):获取指定key对应的value

  • boolean containsKey(Object key):是否包含指定的key

  • boolean containsValue(Object value):是否包含指定的value

  • int size():返回map中key-value对的个数

  • boolean isEmpty():判断当前map是否为空

  • boolean equals(Object obj):判断当前map和参数对象obj是否相等

  • 元视图操作的方法(遍历方法)

    public void test(){
        Map map = new HashMap();
        map.put("AA",123);
        map.put(45,1234);
        map.put("BB",56);
        
        //遍历所有的key集:keySet()
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println();
        
        //遍历所有的value集:values()
        Collection values = map.values();
        for(Object obj : values){
            System.out.println(obj);	//因为value的类型不确定,所以用obj
        }
        System.out.println();
        
        //遍历所有的key-value
        //方式一:entrySet()
        Set entrySet = map.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while(iterator1.hasNext()){
            Object obj = iterator1.next();//返回的set里面只有Entry一种类型,可以向下转型
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + "-" + entry.getValue());
        }
        
        //方式二:
        Set keySet = map.keySet();
        Iterator iterator2 = keySet.iterator();
        while(iterator2.hasNext()){
            Object key = iterator2.next();
            Object value = map.get(key);
            System.out.println(key + "-" + value);
        }
    }
    

3.2 Map的实现类的结构

  • Map:双列数据,存储key-value对的数据
    • HashMap:作为Map的主要实现类;线程不安全,效率高;可以存储值为null的key和value
      • LinkedHashMap:在原有的HashMap基础上,添加了一对指针,指向前一个和后一个元素,保证在遍历map元素时,可以按照添加的顺序实现遍历;对于频繁的遍历操作,此类执行效率高于HashMap
    • TreeMap:按照添加的key-value对进行排序,实现排序遍历;考虑key的自然排序或定制排序
    • Hashtable:作为古老的实现类;线程安全,效率低;不能存储值为null的key和value
      • Properties:常用来处理配置文件;key和value都是String类型
3.2.1 HashMap/LinkedHashMap
  • HashMap中元素的添加过程

    HashMap map = new HashMap(),在实例化后,底层创建了长度是16的一维数组Entry[] table

    map.put(key1,value1),开始添加元素

    首先,调用key1所在类的hashCode()计算key1的哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置

    • 如果此位置上的数据为空,此时key1-value1添加成功

    • 如果此位置上的数据不为空,意味着此位置上已存在数据,比较key1和已经存在数据的哈希值

      • 如果key1的哈希值与已存在的数据的哈希值都不相同,此时key1-value1添加成功
      • 如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较,调用key1所在类的equals(key2)比较
        • 如果equals()返回false:此时key1-value1添加成功
        • 如果equals()返回true:使用value1替换value2

    jdk8相较jdk7在底层实现方面的不同:

    • new HashMap()时,底层没有创建一个长度为16的数组,首次调用put()方法时才会创建

    • jdk7底层结构只有数组+链表,jdk8中底层结构:数组+链表+红黑树

      当数组的某一个索引位置上的元素以链表形式村的数据个数 > 8且当前数组的长度 > 64时,此时此索引位置上的所有数据改用红黑树储存

3.2.2 TreeMap
  • 向TreeMap中添加key-value,要求key必须是由同一个类创建的对象
  • 大多数设置都和TreeSet一致,具体参见TreeSet

3.3 Properties接口

  • 定义:Properties是专门用于对properties文件进行操作的接口

    ​ (properties文件可在New → Resource Bundle 内创建)

    //假设Properties文件内已定义name=Tom,password=abc123
    //其中name,password就是key;Tome,abc123就是value,他们都是String类型
    public class Test{
        public static void main(String[] args) {
            //Properties常用来处理配置文件,key和value都是String类型
            Properties pros = new Properties();
    
            FileInputStream fis = null;
            try {
                fis = new FileInputStream("testing.properties");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            try {
                pros.load(fis);	//加载流对应的文件
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            String name = pros.getProperty("name");	//获取key对应的value
            String password = pros.getProperty("password");
    
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    //testing.properties文件(放在工程文件根目录下)
    name=Tom
    password=abc123
    

4.Collections工具类

  • 定义:Collections是一个操作Set,List,Map等集合的工具类

  • 常用工具类

    • reverse(List):反转List中元素的顺序
    • shuffle(List):对List集合元素进行随机排序
    • sort(List):根据元素的自然顺序对指定List集合元素按升序排序
    • sort(List, Comparator):根据指定的Comparator的定制顺序对List集合元素进行排序
    • swap(List ,int int):将指定List集合中的i处元素和j处元素进行交换
    • Object max(Collection):根据元素的自然排序,返回给定集合中的最大元素
    • Object max(Collection, Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
    • Object min(Collection):根据元素的自然排序,返回给定集合中的最小元素
    • Object min(Collection, Comparator):根据Comparator指定的顺序,返回给定集合中的最小元素
    • int frequency(Collection, Object):返回指定集合中指定元素的出现次数
    • void copy(List dest, List src):将src中的内容复制到dest中
    • boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List中的元素
    //对于void copy(List dest, List src)有特别需要关注的地方
    //被拷贝的List与目标List要求大小一致
    List list = new ArrayList();
    list.add(123);
    list.add(0);
    list.add(65);
    list.add(-99);
    
    //以下写法会直接报异常IndexOutOfBoundsException
    List dest = new ArrayList();	//新建的List没有大小
    List dest1 = new ArrayList(list.size());	//内部没有元素,实际dest.size()还是0
    Collections.copy(dest,list);
    
    //正确写法
    List dest2 = Arrays.asList(new Object[list.size()]); //内部被list.size()个null填满了
    Collections.copy(dest,list);
    
  • Collections类还提供了多个synchronizedXxx()方法,该方法可以将指定集合包装成线程同步的集合

上一篇:c++ 自定义inserter


下一篇:java基础复习03