关于集合的一些总结和理解

目录

前言:

集合框架总体结构

Collection概述

1.ArrayList

2.LinkedList

1.LinkedList集合的特有功能:

2.ArrayList和LinkedList的区别:

3.HashSet

重要特性和用法:

4.LinkedHashSet

特性与区别:

5.TreeSet

特性:

排序说明:

1.自然排序:

2.定制排序:

6.Map集合的特征

7.HashMap

8.HashTable与HashMap的区别

9.TreeMap

10.ConcurrentHashMap(拓展)

11.泛型

12.Collections 集合的工具类

13.总结


前言:

1.下面我将阐述一些关于集合的理解和笔记分析,理论方面的解释较少,主要是一些实例说明,闲话少说,立刻开始。

集合框架总体结构

Java 中集合类定义主要是 java.util.* 包下面,常用的集合在系统中定义了三大接口,这三类的区别是:
java.util.Set 接口及其子类, set 提供的是一个无序的集合;
java.util.List 接口及其子类, List 提供的是一个有序的集合;
java.util.Map 接口及其子类, Map 提供了一个映射(对应)关系的集合数据结构;

Collection概述

Collection接口-定义了存取对象的方法。两个非常常用的子接口:
List接口:存放的元素有序且允许有重复的集合接口。
Set接口:存放的元素无序不包含重复的集合接口,所有的重复内容是靠hashCode()euqals()两个 方法区分的。
注:
元素 -对象,实例
重复 -两个对象通过 equals 相等。
有序 -元素存入的顺序与取出的顺序相同

1.ArrayList

ArrayList 底层是基于数组实现的:根据索引定位元素快,增删需要做元素的移位操作。
注意:实现List接口的集合类中的元素是有序的,且允许重复
下面将讲解一些常用方法,请看代码实例:
package day08;
import java.util.ArrayList;
import java.util.Iterator;
public class demo {
    public static void main(String[] args) {
        ArrayList List1 = new ArrayList();
        //添加元素
        List1.add(29);
        List1.add("张三");
        List1.add(true);
        List1.add("张三");
        List1.add("李四");
        //集合长度
        System.out.println(List1.size());
        //返回此列表中指定位置的元素。
        System.out.println(List1.get(1));
        //按索引删除指定位置的元素
        List1.remove(2);
        //删除指定的元素内容
        List1.remove("张三");
        //用指定的元素替换此列表中指定位置的元素。
        List1.set(2,"王五");
        //for循环遍历
        for (int i=0;i<List1.size();i++){
            System.out.println(List1.get(i));
        }
        //迭代器的运用,遍历集合,快捷键itit
        //查看所有代码段的快捷键ctrl+j
        Iterator iter=List1.iterator();
        while (iter.hasNext()) {
            Object next =  iter.next();
            System.out.println(next);
        }
    }
}

2.LinkedList

底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有 API

1.LinkedList集合的特有功能:

 方法名称说明
public void addFirst(E e)
在该列表开头插入指定的元素
public void addLast(E e)
将指定的元素追加到此列表的末尾
public E getFirst()
返回此列表中的第一个元素
public E getLast()
返回此列表中的最后一个元素
public E removeFirst()
从此列表中删除并返回第一个元素
public E removeLast()
从此列表中删除并返回最后一个元素

2.ArrayListLinkedList的区别:

ArrayList
LinkedList
底层封装数组实现,分配的是一块连续的内
存空间
底层封装链表实现,分配的是不连续的内存
空间
读取数据效率更高
读取数据效率相对较低
增,删等操作效率相对偏低
增,删等操作效率高
相对于 ArrayList, 多了对于首元素和尾元素的
操作

3.HashSet

重要特性和用法:

  1. 无序集合HashSet中的元素没有特定的顺序,每次调用iterator()方法时,返回的迭代器遍历的顺序也可能不同。

  2. 不允许重复元素:向HashSet中添加元素时,如果元素已经存在,则添加操作不会成功,会抛出IllegalStateException异常。

  3. 线程不安全HashSet不是线程安全的,多个线程同时修改一份HashSet实例时需要外部同步。

  4. 大小可变HashSet的大小可以根据需要动态调整,当元素数量达到容量和负载因子(load factor)的乘积时,哈希表会自动扩容。

  5. null值问题HashSet允许包含一个null值。

因为List 接口一样, Set 接口也是 Collection 的子接口,因此,常用方法和 Collection 接口一样,这里就不赘述了。

请看代码实例:

package day09;

import java.util.HashSet;
import java.util.Iterator;

public class SetDemo1 {
    public static void main(String[] args) {
           /*set集合的特点:
           1.添加元素的顺序与输出的顺序不一定相同
           2.set的不能使用普通的for循环进行遍历,因为set集合没有索引
           3.添加的元素不能重复*/
        HashSet hashSet = new HashSet();
        hashSet.add("hello");
        hashSet.add("world");
        hashSet.add("java");
        hashSet.add("world");
        //增强型for
        for (Object item:hashSet){
            System.out.println(item);
        }
        //迭代器
        Iterator iterator = hashSet.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }
        System.out.println(hashSet);
    }
}

4.LinkedHashSet

特性与区别:

1.   LinkedHashSet HashSet 的子类
2. LinkedHashSet 底层是一个 LinkedHashMap ,底层维护了一个 数组 + 双向链表
3.LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
4.   LinkedHashset 不允许添重复元素

5.方法与HashSet大致都一样

5.TreeSet

特性:

  1. 自动排序:TreeSet 会自动保持其元素的排序状态,元素会按照它们的自然顺序进行排序,或者根据 Comparator 提供的顺序进行排序。

  2. 不包含重复元素:和所有 Set 实现一样,TreeSet 不允许有重复的元素。

  3. 有序性TreeSet 中的元素是有序的,支持一系列有序的操作,如 first()last()ceiling()floor() 等。

  4. Null 值TreeSet 不允许使用 null 值。如果尝试插入 null 值,将抛出 NullPointerException

  5. 线程不安全TreeSet 的设计不是线程安全的。如果需要在多线程环境中使用,可以使用 Collections.synchronizedSet(new TreeSet<>()) 来包装。

排序说明:

TreeSet可是采用两种方法实现排序:自然排序和定制排序。默认情况,TreeSet采用自然排序。
TreeSet调用调用集合元素的CompareTo()方法,根据该方法的返回值来比较元素之间的大小,
然后进行升序排列,这种排序方式我们称之为自然排列。
1.自然排序:
注意:如果想采用自然排序,则要存储的对象所属类必须实现 Comparable 接口。该接口只有
一个方法 public int compareTo(Object obj) ,必须实现该方法。
compareTo 方法的实现规则:
返回 0 ,表示 this == obj // 则不会添加新对象 (this)
返回正数,表示 this> obj // 添加到原来对象 (obj) 的右边
返回负数,表示 this < obj // 添加到原来对的左边
2.定制排序:
使用 Comparable 接口定义排序顺序有局限性:实现此接口的类只能按 compareTo() 定义的这一种方
式排序。
如果需要更加灵活地排序,我们可以自定义 (Comparator) 比较器,在创建 TreeSet 集合对象时把
我们自定义的比较器传入,则可以 TreeSet 会按照我们的比较器中定义的规则进行排序。
自定义比较器类,需要实现 Comparator 接口。 Comparator 接口只有一个抽象方法需要实现:
public int compare(Object a, Object b);
判断规则:
返回 0,表示a == b
返回正数,表示a > b
返回负数,表示a < b

下面我将重点讲述定制排序,请看实例:

键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从低到高输出到控制台,使用TreeSet保存学生的信息

首先我们先创建一个学生类:

package day09;

public class Student implements Comparable<Student>{
    private String name;
    private int math;
    private int china;
    private int english;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getMath() {
        return math;
    }
    public void setMath(int math) {
        this.math = math;
    }
    public int getChina() {
        return china;
    }
    public void setChina(int china) {
        this.china = china;
    }
    public int getEnglish() {
        return english;
    }
    public void setEnglish(int english) {
        this.english = english;
    }
    public Student(String name, int math, int china, int english) {
        this.name = name;
        this.math = math;
        this.china = china;
        this.english = english;
    }

    public Student() {
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", math=" + math +
                ", china=" + china +
                ", english=" + english +
                '}';
    }
    public int Score(){
        return this.china+this.english+this.math;
    }
    @Override
    public int compareTo(Student o) {
         //根据成绩升序排序
        int rs = this.Score() - o.Score();
        //根据成绩降序排列
        //int rs1=o.Score()-this.Score();
        if(rs == 0 ){
            if(o == this){
                return 0;
            }else{
                return -1;
            }
        }
        return rs;
    }
}

然后创建一个测试类:

package day09;

import java.util.ArrayList;
import java.util.TreeSet;

public class tes01 {
    public static void main(String[] args) {
        TreeSet<Student> students = new TreeSet<>();
        students.add(new Student("zs",24,45,89));
        students.add(new Student("ww",12,39,78));
        students.add(new Student("ls",34,61,56));
        for (Student as:students){
            System.out.println(as);
        }
    }
}

最后它将会输出

显而易见这里是按总成绩升序排列。

6.Map集合的特征

1.  通过键 - (key-value) 对的形式来存储数据
2 .Map 的实现: HashMap( 使用频率最高的 ),TreeMap,HashTable
3 .Map 中, key 可以为任意类型,但这里建议使用 String,value 也可以是任意类型
4 .Map 里面多个 value 可以是不同类型
5 .Map里面key是可以重复的,当key重复时,后存入的数据会覆盖前面的数据
6 .Map 里面, value 可以重复 .
7 .Map 里面的 key 可以为 null, 但是只能有一个,多个的时候,后面的会覆盖前面的
8 .Map value 可以是 null, 多个 value 可以同时为 null
9 .Map 中的 key 在底层可以理解为是一个 Set

7.HashMap

简述:基于哈希表实现,键值对无序,允许空键和空值。

下面讲解一些主要方法,请看实例:

package day10;

import java.util.Collection;
import java.util.HashMap;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        //添加键值对
        map.put("CN","中国");
        map.put("CN","中国香港");
        map.put("USA","美国");
        map.put("null","空值");
        map.put("Null",null);
        //获取对应键的值
        System.out.println(map.get("CN"));
        System.out.println(map.get("USA"));
        System.out.println(map.get("null"));
        //获取map集合的长度
        System.out.println(map.size());
        //判断集合是否包含指定key
        System.out.println(map.containsKey("CN"));
        //判断集合是否包含指定value
        System.out.println(map.containsValue(null));
        // 获取所有的键
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println("键:" + key + ",值:" + map.get(key));
        }
        // 获取所有的值
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println("值:" + value);
        }
        //遍历
        map.forEach((key,value)->{
            System.out.println("Key:"+key+",Value:"+value);
        });
    }
}

8.HashTable与HashMap的区别

hashtable jdk1.0提出来的,是同步的,线程安全的,keyvalue都不能为空,继承自Dictionary 有contains()方法直接判断键-值对
hashMap jdk1.2 提出来的 , 不是同步的,线程不安全, key value 都可以为空 , 继承自
AbstractMap, 通过 containsKey() containsValue() 分别判断

9.TreeMap

TreeMap 是 Java 集合框架(Java Collections Framework)中的一种基于红黑树(Red-Black Tree)的有序映射表。它存储键值对,并确保键的顺序性。以下是 TreeMap 的几个重要特点:

  1. 键的排序性TreeMap 会根据键的自然顺序或者用户指定的比较器来保持键的顺序。如果没有任何排序,它默认会按照键的字符串顺序进行排序。

  2. 红黑树实现TreeMap 使用红黑树来存储键值对,这样可以在对数时间复杂度内完成查找、插入和删除操作。

  3. 无序集合:与 LinkedHashMap 不同,TreeMap 不会保持插入顺序,而是保持基于键的排序顺序。

  4. 不保证映射的迭代顺序:自 Java 8 开始,TreeMap 不保证迭代顺序,因为迭代顺序可能会在结构修改后发生改变。

  5. null 值TreeMap 不允许键或值是 null。如果尝试插入 null 键,会抛出 NullPointerException

  6. 无界性TreeMap 没有预定义的最大容量,但是由于它基于内存,所以会受到系统资源的限制。

  7. 性能:在理想情况下,TreeMap 的 getput 和 remove 操作的时间复杂度为 O(log n),其中 n 是树中节点的数量。

  8. 功能方法TreeMap 提供了多种方法,如 ceilingKeyfloorKeylowerKeyhigherKey 等,用于在树中查找特定的键。

下面讲解一些主要方法,请看实例:

package day10;

import java.util.*;

public class TreeMap_Demo {
    public static void main(String[] args) {
        TreeMap<String, Integer> map = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                //当两个字符串长度一致
                if (o1.length()==o2.length()){
                //按顺序依次比较每一个字符
                    for (int i = 0; i <o1.length() ; i++) {
                        if (o1.charAt(i)==o2.charAt(i)){
                            continue;
                        }
                        return o1.charAt(i)-o2.charAt(i);
                    }
                }
                return o1.length()-o2.length();
            }
        });
        //添加元素,为了更好的体现各种方法,你可以改变所添加的元素
        map.put("a",32);
        map.put("bc",13);
        map.put("def",10);
        map.put("cccc",29);
        map.put("eeeee",24);
        //返回此地图中包含的映射的Set视图。
        Set<Map.Entry<String,Integer>> es=map.entrySet();
        for (Map.Entry en:es){
            System.out.println("key:"+en.getKey()+",value:"+en.getValue());
        }
        System.out.println("------------");
        //返回与大于或等于给定键的最小键相关联的键值映射,如果没有此键,则 null
        Map.Entry entry=map.ceilingEntry("d");
        System.out.println(entry.getKey()+"---"+entry.getValue());
        //严格大于
        entry=map.higherEntry("d");
        System.out.println(entry.getKey()+"---"+entry.getValue());
        //返回大于或等于给定键的 null键,如果没有此键,则返回 null 。
        System.out.println(map.ceilingKey("d"));
        //返回与小于或等于给定键的最大键相关联的键值映射,如果没有此键,则 null
        entry=map.floorEntry("d");
        System.out.println(entry.getKey()+"---"+entry.getValue());
        //严格小于
        entry=map.lowerEntry("d");
        System.out.println(entry.getKey()+"---"+entry.getValue());
        //返回小或等于给定键的 null键,如果没有此键,则返回 null 。
        System.out.println(map.floorKey("d"));
        //获取第一个实体对
        entry=map.firstEntry();
        System.out.println(entry.getKey()+"---"+entry.getValue());
        //获取第一个key
        String key=map.firstKey();
        System.out.println(key);
        //获取最后一个实体对象
        entry=map.lastEntry();
        System.out.println(entry.getKey()+"---"+entry.getValue());
        //截取Map集合当中的一部分
        SortedMap sm=map.subMap("b","d");
        Set<Map.Entry> entrys=sm.entrySet();
        for (Map.Entry en:entrys){
            System.out.println("key:"+en.getKey()+",value:"+en.getValue());
        }

    }
}

10.ConcurrentHashMap(拓展)

主要特点:

  1. 线程安全ConcurrentHashMap 是线程安全的,这意味着它可以在多个线程之间安全地共享,而无需额外的同步或包装。

  2. 高并发性能:它通过分段技术(Segment)或原子操作(如 CAS)来实现高并发性能。这允许在绝大多数情况下进行无锁操作,只有在数据结构需要扩容或者极少数的竞争情况下才会使用锁。

  3. 可扩展性ConcurrentHashMap 能够在不影响并发性能的情况下进行动态扩容。

稍微看一下实列吧

package day10;

import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMaps_Demo {
    public static void main(String[] args) {
        ConcurrentHashMap<Integer, Integer> con = new ConcurrentHashMap<>();
       /* Random random = new Random();
        for (int i=0;i<=10;i++){
            int a= random.nextInt(100);
            con.put(i,a);
        }*/
        con.put(1,2);
        con.put(2,3);
        con.put(3,4);
        con.put(4,5);
        con.put(5,6);
        //多线程
        long before=System.currentTimeMillis();
        con.forEach(5,(key,value)->{
            System.out.println("key:"+key+",value:"+value);
        });
        long after=System.currentTimeMillis();
        System.out.println("总消耗时间:"+(after-before));
        //查找
        String str=con.search(5,(key,value)->{
            if(key==5){
                return "存在";
            }
            return null;
        });
        System.out.println(str);
        //统计1
       Integer var = con.reduce(5,(key,value)->{
           return key;},(o1,o2)->{
            return o1+o2;
       });

        System.out.println(var);
       //统计2
        Integer val = con.reduceEntries(5,entry->{
                    return entry.getKey();},
                (o1,o2)->{
                    return o1+o2;
                });
        System.out.println(val);
    }
}

11.泛型

Java 集合框架(Java Collections Framework)中的泛型是一种类型安全机制,它允许程序员在集合中存储任何类型的对象,同时仍然保持类型检查。泛型在 Java 5 中引入,极大地增强了 Java 编程语言的类型安全性和表达力。

泛型主要通过以下几个关键字来实现:

  1. 泛型类型参数:在集合接口和类中,尖括号(<>)中的类型参数表示集合可以存储的类型。例如,List<Integer> 表示一个存储 Integer 对象的列表。

  2. 泛型方法:泛型方法允许在不知道具体类型的情况下执行操作。它通过在方法签名中使用类型参数来实现。例如,Collections.sort(list) 中的 list 可以是任何类型的 List

  3. 限定泛型:使用 extends 和 super 关键字可以限定泛型的类型参数。例如,List<Integer> 表示存储 Integer 对象的列表,而 List<? extends Number> 表示存储任何 Number 子类型的列表。

  4. 通配符泛型:通配符 ? 可以用作泛型的占位符,提供更多的灵活性。例如,List<?> 表示一个可以存储任何类型对象的列表。

12.Collections 集合的工具类

java.util.Collections 是集合工具类 , 用来对集合进行操作 . 常用方法如下
请看实例:
package day11;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Collection {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(3);
        //添加
        Collections.addAll(list,4,5,6,7);
        for (Integer as:list){
            System.out.println(as);
        }
        //查询
        int index=Collections.binarySearch(list,6);
        System.out.println("位置:"+index);
        //复制
        ArrayList<Integer> list1 = new ArrayList<>();
        Collections.addAll(list1,0,0,0,0,0);
        Collections.copy(list1,list);
        for (Integer at:list1){
            System.out.println(at);
        }
        //最大值
        int a=Collections.max(list);
        System.out.println(a);
        //最小值
        int b=Collections.min(list);
        System.out.println(b);
        System.out.println("-------------");
        //填充
        Collections.fill(list1,20);
        for (Integer at:list1){
            System.out.println(at);
        }
        //反转
        Collections.reverse(list);
        for (Integer as:list){
            System.out.println(as);
        }
        //替换
        Collections.replaceAll(list,6,29);
        for (Integer as:list){
            System.out.println(as);
        }
        //打乱顺序
        System.out.println("--------");
        Collections.shuffle(list);
        for (Integer as:list){
            System.out.println(as);
        }
        System.out.println("-------");
        //排序(降序,升序)
        Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1-o2;
            }
        });
        for (Integer as:list){
            System.out.println(as);
        }
        System.out.println("--------");
        //换位
        Collections.swap(list,1,3);
        for (Integer as:list){
            System.out.println(as);
        }
        //转换为线程安全的列表
        List<Integer> list2=Collections.synchronizedList(list);
    }
}

13.总结

以上就是我个人对集合的一些理解和总结,如有描述不到之处,请批评指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值