Java SE08_集合笔记

集合

1 什么是集合

1.1 概念

概念:对象的容器,实现了对多个对象常用的操作,可实现数组的功能。

1.2 和数组的区别

  1. 数组长度固定,集合长度不固定
  2. 数组可以存储基本类型和引用类型,集合只能存储引用类型

1.3 位置

java.util.*


2 Collection体系集合

image-20220524173609046

  • List接口的特点:有序、有下标、元素可重复
  • Set接口的特点:无序、无下标、元素不能重复

2.1 Collection父接口

定义: Collection collection = new ArrayList();

位置:import java.util.Collection; import java.util.ArrayList;

特点:代表一组任意类型的对象,无序、无下标、不能重复。

2.2 常用方法

  1. 添加元素 collection.add();

  2. 删除元素

    collection.remove();

    collection.clear();

  3. 遍历元素(重点)

    1. 使用增强for(因为无下标)

      for(Object object : collection){ }

    2. 使用迭代器

      //haNext(); 有没有下一个元素
      //next(); 获取下一个元素
      //remove(); 删除当前元素
      Iterator it = collection.iterator();
      while(it.hasNext()){
        String object = (String)it.next(); //强转
        // 可以使用it.remove(); 进行移除元素
        // collection.remove(); 不能用collection其他方法 会报并发修改异常
      }
      
  4. 判断 collection.contains(); collection.isEmpty();

代码演示:

	public static void main(String[] args) {
        //Collection接口的使用
        Collection collection = new ArrayList();
        //1.添加元素:add()
        collection.add("苹果");
        collection.add("西瓜");
        collection.add("榴莲");
        System.out.println(collection.size());//3
        //可直接打印,=collection.toString()
        System.out.println(collection);//[苹果, 西瓜, 榴莲]

        //2.删除元素:remove(),clear()
//        collection.remove("榴莲");
        //清空之后的元素为0
//        collection.clear();
//        System.out.println(collection.size());//2

        //3.遍历元素【重点】
        //3.1 使用增强for
        for (Object o : collection) {
            System.out.print(o+" ");//苹果 西瓜 榴莲
        }
        System.out.println();

        //3.2 使用迭代器(专门用来遍历遍历集合的一种方式)
        //hasnext();有没有下一个元素
        //next();获取下一个元素
        //remove();删除当前元素
        Iterator it = collection.iterator();
        //迭代过程中不允许collection的删除方法,但是可以使用迭代器自己的remove()方法
        while(it.hasNext()){
            System.out.print(it.next().toString());
//            it.remove();
        }
        System.out.println();

        //4.判断是否存在:contains(),isEmpty()
        boolean flag1 = collection.contains("西瓜");
        boolean flag2 = collection.contains("香蕉");
        boolean flag3 = collection.isEmpty();
        System.out.println(flag1);//true
        System.out.println(flag2);//false
        System.out.println(flag3);//false
    }

2.3 List子接口

定义: List list = new ArrayList<>();

位置:import java.util.List; import java.util.ArrayList;

特点:有序、有下标、元素可重复

常用方法:

  1. 添加元素 list.add( ); 会对基本类型进行自动装箱

  2. 删除元素 可以用索引 list.remove(0)

    当删除数字与索引矛盾时 对数字强转

    list.remove((Object) 10)list.remove(new Integer(10))

  3. 遍历

    1. 使用for遍历

      for(int i = 0; i < lise.size(); i++){
        sout(list.get(i)); 
      }
      
    2. 使用增强for

      for(Object list: collection){ }

    3. 使用迭代器

      Iterator it = collection.iterator();
      while(it.hasNext()){
        String object = (String)it.next(); //强转
        // 可以使用it.remove(); 进行移除元素
        // collection.remove(); 不能用collection其他方法 会报并发修改异常
      }
      
    4. 使用列表迭代器 (注意和迭代器区别)

      ListIterator lit = list.listIterator();
      while(lit.hasNext()){
        System.out.println(lit.nextIndex() + ":" + lit.next()); //从前往后遍历
      }
      
      while(lit.hasPrevious()){
        System.out.println(lit.previousIndex() + ":" + lit.previous()); //从后往前遍历
      }
      
  4. 获取 list.indexOf( );

  5. 返回子集合 sublist(x, y); 左闭右开

    List subList = list.subList(1, 3); 返回索引 1、2

代码演示:

	public static void main(String[] args) {
        //List子接口的使用,特点:1有序有下标,2可以重复
        //先创建List集合对象
        List list = new ArrayList<>();
        //1.添加元素 add()
        list.add("苹果");
        list.add("小米");
        list.add(0,"华为");
        System.out.println("元素个数:" + list.size());//元素个数:3
        System.out.println(list.toString());//[华为, 苹果, 小米]

        //2.删除元素 remove() clear()
//        list.remove("苹果");
//        list.remove(0);
//        System.out.println(list.toString());//[苹果, 小米]

        //3.遍历
        //3.1使用for遍历
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i)+" ");//华为 苹果 小米
        }
        System.out.println();
        //3.2使用增强for
        for (Object o : list) {
            System.out.print(o+" ");//华为 苹果 小米
        }
        System.out.println();
        //3.3使用迭代器 只有3个方法
        Iterator it = list.iterator();
        while(it.hasNext()){
            System.out.print(it.next()+" ");//华为 苹果 小米
        }
        System.out.println();
        //3.4使用列表迭代器 和iterator的区别,它可以向前或向后遍历,添加,删除,修改元素
        ListIterator lit = list.listIterator();
        //从前往后
        while(lit.hasNext()){
            System.out.print(lit.nextIndex()+":"+lit.next()+" ");//0:华为 1:苹果 2:小米
        }
        System.out.println();
        //从后往前
        while(lit.hasPrevious()){
            System.out.print(lit.previousIndex()+":"+lit.previous()+" ");//2:小米 1:苹果 0:华为
        }
        System.out.println();

        //4.判断是否存在 contains() isEmpty()
        boolean flag1 = list.contains("苹果");
        boolean flag2 = list.isEmpty();
        System.out.println(flag1);//true
        System.out.println(flag2);//false

        //5.获取位置 indexOf()
        int index = list.indexOf("华为");
        System.out.println(index);//0
    }

	public static void main(String[] args) {
        //创建集合
        List list = new ArrayList();
        //1.添加数字数据(自动装箱)
        list.add(20);
        list.add(30);
        list.add(40);
        list.add(50);
        list.add(60);
        System.out.println("元素个数:"+list.size());//元素个数:5
        System.out.println(list.toString());//[20, 30, 40, 50, 60]

        //2.删除操作
//        list.remove((Object)20);
        list.remove((Integer)20);
        System.out.println(list.toString());//[30, 40, 50, 60]

        //3.补充方法 subList() 返回子集合 左闭右开
        List list1 = list.subList(1, 3);
        System.out.println(list1.toString());//[40, 50]
    }

2.4 List实现类

  • ArrayList 【重点】
    • 数组结构实现,需连续空间,查询快、增删慢
    • jdk1.2版本,运行效率快、线程不安全
  • Vector
    • 数组结构实现,需连续空间,查询快、增删慢
    • jdk1.0版本,运行效率慢,线程安全
  • LinkedList
    • 双向链表结构实现,无需连续空间,增删快,查询慢

2.5 ArrayList

定义:ArrayList arrayList = new ArrayList<>();

位置:import java.util.ArrayList;

特点:有序、有下标、元素可重复

方法:

  1. 添加元素 arrayList.add();

  2. 删除元素 arrayList.remove(new Student("name", 10));

    这里重写了 equals(this == obj) 方法

    public boolean equals(Object obj){
      //1 判断是不是同一个对象
      if(this == obj){
        return true;
      }
      //2 判断是否为空
      if(obj == null){
        return false;
      }
      //3 判断是否是Student类型
      if(obj instanceof Student){
        Student == (Student)obj;
        //4 比较属性
        if(this.name.equals(s.getName()) && this.age == s.getAge()){
          return true;
        }
      }
      //5 不满足条件返回false
      return false;
    }
    
  3. 遍历元素【重点】

    1. 使用迭代器

      Iterator it = arrayList.iterator();
      while(it.hasNext()){
        Student s = (Student)it.next(); //强转
      }
      
    2. 列表迭代器

      ListIterator li = arrayList.listIterator();
      while(li.hasNext()){
        Student s = (Student)li.next(); //从前往后遍历
      }
      
      while(li.hasPrevious()){
        Student s = (Student)li.previous();//从后往前遍历
      }
      
  4. 判断

    arrayList.contains();arrayList.isEmpty();

  5. 查找

    arrayList.indexof();

原码分析

DEFAULT_CAPACITY = 10; //默认容量
//注意:如果没有向集合中添加任何元素时,容量0,添加一个后,容量为10
//每次扩容是原来的1.5倍
elementData存放元素的数组
size 实际元素个数

2.6 Vector

定义: Vector vector = new Vector<>();

位置:import java.util.Vector;

增加、删除、判断同上

遍历使用枚举器遍历Enumeration

Enumeration en = vector.elements();
while(en.hasMoreElements()){
  String o = (String)en.nextElement();
  sout(o);
}
firstElement();     
lastElement();
elementAt();

2.7 LinkedList

定义链表集合:LinkedList li = new LinkedList<>();

位置:import java.util.LinkedList;

常用方法与List一致

2.8 List和AarryList区别

List list = new ArrayList();
ArrayList arrayList = new ArrayList();

区别:

  ArrayListl类是数组列表类,实现了可变长度的数组。 List是一个接口,而ArrayList是List接口的一个实现类。 ArrayList类继承并实现了List接口。

  因此,List接口不能被构造,也就是我们说的不能创建实例对象,但是我们可以像第一个代码那样为List接口创建一个指向自己的对象引用,而ArrayList实现类的实例对象就在这充当了这个指向List接口的对象引用。


3 泛型

  • 本质是参数化类型,把类型作为参数传递
  • 常见形式有泛型类、泛型接口、泛型方法
  • 语法<T>,T称为类型占位符,表示一种引用类型,可以写多个逗号隔开
  • 好处:(1)提高代码重用性(2)防止类型转换异常,提高代码安全性

3.1 泛型类

语法:类名后<T>

/**
 * @Description: 泛型类
 * 语法: 类型<T>
 * T是类型占位符,表示一种引用类型
 */
// 定义泛型类
public class MyGeneric<T> {

    //使用泛型T
    //1.创建变量
    T t;

    //2.作为方法的参数
    public void show(T t) {
        System.out.println(t);
    }

    //3.使用泛型作为方法的返回值
    public T getT(){
        return t;
    }
}

// 使用泛型类
public class TestMyGeneric {
    public static void main(String[] args) {
        //使用泛型类创建对象
        //注意:
        //1.泛型只能使用引用类型
        //2.不用泛型类型对象之间不能相互赋值
        MyGeneric<String> myGeneric = new MyGeneric<String>();//后面一个String在jdk1.7之后可不写
        myGeneric.t = "hello";
        myGeneric.show("大家好");//大家好
        String str = myGeneric.getT();
        System.out.println(str);//hello

        MyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();//后面一个String在jdk1.7之后可不写
        myGeneric2.t = 100;
        myGeneric2.show(200);//大家好
        Integer integer = myGeneric2.getT();//200
        System.out.println(integer);//100
    }
}

3.2 泛型接口

语法:接口名后<T>

注意:不能泛型静态常量

/**
 * @Description: 泛型接口
 * 语法 接口名<T>
 * 不能创建泛型常量
 */
//定义接口
public interface MyInterface<T> {
    String name = "张三";
    T server(T t);
}
//定义实现类
//public class MyInterfaceImpl implements MyInterface<String>
//可以在实现类的指定类型,后面new的时候就不用指定了
public class MyInterfaceImpl<T> implements MyInterface<T> {
    @Override
    public T server(T t) {
        return t;
    }
}
//测试
public static void main(String[] args) {
    MyInterfaceImpl<String> impl = new MyInterfaceImpl<String>();
    System.out.println(impl.server("xxxx"));//xxxx
}

3.3 泛型方法

语法: 方法返回值类型之前

public class MyGenericMethod {

    //泛型方法
    public <T> T show(T t){
        System.out.println("泛型方法");
        return t;
    }

    public static void main(String[] args) {
        MyGenericMethod m = new MyGenericMethod();
        String str = m.show("hello,world");
        int i = m.show(123);
        System.out.println(str);//hello,world
        System.out.println(i);//123
    }
}

3.4 泛型集合

概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致

特点:

  • 编译时即可检查,而非运行时抛出异常
  • 访问时,不必类型转换(拆箱)
  • 不同泛型之间应用不能相互赋值,泛型不存在多态

4 Set集合

定义:Set<String> set = new HashSet<>();

位置:import java.util.Set;

特点:无序、无下标、元素不可重复

方法:全部继承自Collection中的方法,增、删、遍历、判断与collection一致

4.1 HashSet【重点】

定义:HashSet<String> hashSet = new HashSet<>();

位置:import java.util.HashSet;

特点:无序、无下标、元素不可重复(和Set一样)

存储结构:哈希表(数组+链表+红黑树)

存储过程(重复依据)

  1. 根据hashcode计算保存的位置,如果位置为空,直接保存,若不为空,进行第二步
  2. 再执行equals方法,如果equals为true,则认为是重复,否则形成链表

重点:【对象可重写equals和hashcode方法】

  • 利用31这个质数,减少散列冲突
    • 31提高执行效率 31 * i = (i << 5) - i 转为移位操作
  • 基于HashCode计算元素存放位置
  • 当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入

方法:

  1. 添加元素 hashSet.add( );

  2. 删除元素 hashSet.remove( );

  3. 遍历操作

    (1)增强for for( type type : hashSet)

    (2)迭代器 Iterator<String> it = hashSet.iterator( );

  4. 判断 hashSet.contains( ); hashSet.isEmpty();

4.2 TreeSet

定义:TreeSet<String> treeSet = new TreeSet<>();

位置:import java.util.TreeSet;

存储结构:红黑树

特点:

  • 基于排列顺序实现元素不重复
  • 实现SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparable接口,重写CompareTo()方法,指定排序规则
  • 通过CompareTo方法确定是否为重复元素

方法:

  1. 添加元素 treeSet.add();

  2. 删除元素 treeSet.remove();

  3. 遍历 (1)增强for(2)迭代器

  4. 判断 treeSet.contains();

补充:定制TreeSet集合Comparable的使用

Comparator 实现定制比较(比较器),Comparable 可比较的

//创建集合并定制比较规则
TreeSet<Person> person = new TreeSet<>(new Comparator<Person>(){
    //重写compare
    @override
    public int compare(Person o1, Person o2){
      int n1 = o1.getAge()-o2.getAge();
      int n2 = o1.getName().comareTo(o2.getName());
      return n1 == 0 ? n2 : n1;
    }
});

5 Map集合

image-20220525090441610

定义:Map<String, String> map = new HashMap<>();

位置:import java.util.Map;

Map接口的特点

1. 用于存储任意键值对(key - value)
2. 键:无序、无下标、不允许重复(唯一)
3. 值:无序、无下标、允许重复

方法:

1. V put(K key, V value) 将对象存到集合中,关联键值
2. Object get(Object key) 根据键获得对应的值
3. Set<K> 返回所有的Key
4. Collection<V> values() 返回包含所有值的Collection集合
5. Set<Map.Entry<K, V>> 键值匹配的Set集合
6. KeySet() 返回此映射中包含的键的Set视图

代码演示:

	public static void main(String[] args) {
        /**
         * Map接口的使用
         * 特点:(1)存储键值对(2)键不能重复,值可以重复(3)无序
         */
        //创建Map集合
        Map<String, String> map = new HashMap<>();
        //1.添加元素
        map.put("cn","中国");
        map.put("uk","英国");
        map.put("us","美国");
//        map.put("cn","zhongguo");//添加重复的键,值会被替换
        System.out.println("元素个数:" + map.size());//元素个数:3
        System.out.println(map.toString());//{uk=英国, cn=中国, us=美国}

        //2.删除元素
//        map.remove("cn");

        //3.遍历元素【重点】
        //3.1 使用KeySet从map转set集合遍历
        //Set<String> keyset = map.keySet();//所有key值的集合,后面通过map.get(key)就可以获取到value
        for (String key : map.keySet()) {
            System.out.println(key+"="+map.get(key));
        }
        //3.2 使用entrySet()方法,效率高于keySet方法  里面有getKey() getValue()可以获取键和值
//        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey()+"=="+entry.getValue());
        }

        //4.判断 containsKey();containsValue(); isEmpty()
    }

5.1 HashMap

定义:HashMap<String, String > hashMap= new HashMap<>();

位置:import java.util.HashMap;

存储结构:哈希表(数组+链表+红黑树)

线程不安全,运行效率快,允许null作为key或是value

使用key可使hashcode和equals作为重复(可重写)

增、删、遍历、判断与Map一致

源码分析总结:

  • HashMap刚创建时,table是null,节省空间,当添加第一个元素时,table容量调整为16
  • 当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目的是减少调整元素的个数
  • jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高效率
  • jdk1.8 当链表长度 <6 时 调整成链表
  • jdk1.8 以前,链表时头插入,之后为尾插入
1.static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 
	hashmap的初始容量大小
2.static final int MAXIMUM_CAPACITY = 1 << 30;
	hashmap的数组最大容量
3.static final float DEFAULT_LOAD_FACTOR = 0.75f;
	默认加载因子
4.static final int TREEIFY_THRESHOLD = 8;
	jdk1.8 当链表长度 >8时,会调整成红黑树
5.static final int UNTREEIFY_THRESHOLD = 6;
	jdk1.8 当链表长度 <6时 调整成链表
6.static final int MIN_TREEIFY_CAPACITY = 64;
	jdk1.8 当每个链表长度 >8,并且数组元素个数 ≥64时,会调整成红黑树
7.transient Node<K,V>[] table;
	哈希表中的数组 HashMap刚创建时,table是null
8.transient int size;
	元素个数,HashMap刚创建时,size是0

5.2 HashTable

特点:线程安全,运行效率慢;不允许null作为key或是value

5.3 Properties

特点:hashtable的子类,要求key和value都是string,通常用于配置文件的读取

5.4 TreeMap

定义:TreeMap<String, String> map = new TreeMap<>();

位置:import java.util.TreeMap;

存储结构:红黑树

特点:实现了SortedMap接口(是Map的子接口),可以对key自动排序

增、删、遍历、判断与Map一致

5.5 总结

遍历:使用entrySet()方法的遍历效率高于keySet()方法


6 Collections工具类

概念:集合工具类,定义了除了存取以外的集合常用方法

直接二分查找int i = Collections.binarySearch(list, x); 成功返回索引

其他方法 : copy复制、sort排序、reverse反转、shuffle打乱

注:

  • 使用sort方法的时候,元素类型必须实现了Comparable接口
  • List转数组 长度为0的话看list长度,如果溢出则默认赋值 Integer[] arr = list.toArray(new Integer[0]);
  • 数组转成集合,此时为受限集合,不能 添加和删除!List<String> list = Arrays.asList(arr);
  • 把基本类型数组转为集合时,需要修改为包装类 List<Integer> list = Arrays.asList(nums);

代码演示:

public static void main(String[] args) {
    /**
     * Collections工具类的使用
     */
    List<Integer> list = new ArrayList<>();
    list.add(20);
    list.add(5);
    list.add(12);
    list.add(11);
    list.add(9);
    //sort() 排序
    System.out.println("排序前:" + list.toString());//排序前:[20, 5, 12, 11, 9]
    Collections.sort(list);
    System.out.println("排序后:" + list.toString());//排序后:[5, 9, 11, 12, 20]

    //binarySearch() 二分查找 没找到返回-1
    int i = Collections.binarySearch(list, 12);
    System.out.println(i);//3

    //copy() 复制
    List<Integer> dest = new ArrayList<>();
    Collections.copy(list,dest);//原列表和目标列表的长度必须一直才能copy成功
    System.out.println(dest.toString());//[] 长度不一样不会成功,甚至可能报错

    //reverse() 反转
    Collections.reverse(list);
    System.out.println("反转后:" + list.toString());//[20, 12, 11, 9, 5]

    //shuffle() 打乱 每次随机
    Collections.shuffle(list);
    System.out.println("打乱后:" + list.toString());//随机

    //补充:list转数组 长度为0的话看list长度,如果溢出则默认赋值
    Integer[] arr = list.toArray(new Integer[0]);
    System.out.println("list转数组之后长度:"+arr.length+",arr="+ Arrays.toString(arr));//list转数组之后长度:5,arr=[5, 9, 12, 11, 20]

    //数组转成集合
    //此时为受限集合,不能 添加和删除!
    String[] names = {"张三","李四","王五"};
    List<String> list2 = Arrays.asList(names);
    System.out.println("数组转成集合后:" + list2.toString());//数组转成集合后:[张三, 李四, 王五]

    //把基本类型数组转为集合时,需要修改为包装类
    Integer[] nums = {100, 200, 300, 400, 500};
    List<Integer> list3 = Arrays.asList(nums);
    System.out.println(list3.toString());//[100, 200, 300, 400, 500]
}

总结

集合的概念:

  • 对象的容器,和数组类似,定义了对多个对象进行操作的常用方法。

List集合:

  • 有序、有下标、元素可以重复。(ArrayList、LinkedList、Vector)

Set集合:

  • 无序、无下标、元素不可重复。(HashSet、TreeSet)特殊:LinkHashSet:有序

Map集合:

  • 存储一对数据,无序、无下标,键不可重复,值可重复。(HashMap、HashTable、TreeMap)

Collections工具:

  • 集合工具类,定义了除了存取以外的集合常用方法。

END

posted @   lyluoye  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示