集合

集合是什么?它是一个容器,存放数据的一个容器
使用集合的目的?更方便的存储和操作数据,CRUD

集合继承结构

Collection<E>:存放单值的最大父接口

List<E>:列表,线性表,和数组类似,List可以动态增长,查找元素效率高,插入删除元素的效率低,因为会引起其他元素位置的改变。
Set<E>:它也是线性表,检索元素效率低,删除和插入的效率高,插入和删除不会引起元素移位。

Map<K,V>:存放对值的最大父接口

Map,(映射)用于保存具有映射关系的数据,Map保存着两组数据,key和value,key和value都可以是任意的引用数据类型,但key不能重复。

List的简单运用

代码

public class Ch02 {

    public static void main(String[] args) {
        // 创建了一个ArrayList集合
        // 开发中,一般情况下,使用多态创建集合(向上转型)
        List<Integer> l1 = new ArrayList<>();
        l1.add(1);
        l1.add(2);
        l1.add(3);
        l1.add(4);
        l1.add(5);
        l1.add(1,-1);
        // 直接打印集合对象 "[1, -1, 2, 3, 4, 5]"
        System.out.println(l1);

        List<Integer> l2 = new ArrayList<>();
        l2.add(-1);
        l2.add(-2);
        l2.add(-3);
        l2.add(-4);
        l2.add(-5);
        l2.add(1,100);

        l1.addAll(l2);
        System.out.println(l1); // [1, -1, 2, 3, 4, 5, -1, 100, -2, -3, -4, -5]

        // contains 是否包含"-3"数据
        System.out.println(l1.contains(-3)); // true

        // 获取指定位置的元素
        System.out.println(l1.get(0)); // 1

        // 查询某个元素所在的位置,若不存在返回-1
        System.out.println(l1.indexOf(2)); // 2

        // 删除某个元素
        l1.remove((Object)100);
        System.out.println(l1); // [1, -1, 2, 3, 4, 5, -1, -2, -3, -4, -5]

        // 删除某个下标的元素
        l1.remove(1);
        System.out.println(l1); // [1, 2, 3, 4, 5, -1, -2, -3, -4, -5]

        // 设置某个位置的数据
        l1.set(0,200);
        System.out.println(l1); // [200, 2, 3, 4, 5, -1, -2, -3, -4, -5]

        // 长度
        System.out.println(l1.size()); // 10

        // 清空数据
        l1.clear();
        System.out.println(l1);

        // 列表是否为空
        System.out.println(l1.isEmpty()); // true


        int[] arr = new int[]{1,2,3,4,5};
        List<int[]> arr1 = List.of(arr); // 把arr当成一个元素存入arr1中
        System.out.println(arr1.get(0)[0]); // 1

        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
        System.out.println(integers); // [1, 2, 3, 4, 5]

    }
}

ArrayList内部结构是一个数组

  1. 如果初始化集合尽量指定初始化容量,如果确定不了,默认指定为16
  2. 使用泛型数据类型的时候,一定要使用引用数据类型

List集合中存放的数据

  1. 数据有顺序(添加的先后顺序)
  2. 数据可以重复

自己写一个转换工具类

public class ArrayConvertUtil {

    public static Object[] toArrayConvert(List list) {

        Object[] objects = new Object[list.size()];

        for (int i = 0; i < list.size(); i++) {
            objects[i] = list.get(i);
        }

        return objects;
    }

    public static List toListConvert(Object [] arr) {

        List list = new ArrayList();

        for (Object o : arr) {
            list.add(o);
        }

        return list;
    }

}

Collection的常用方法

返回值方法含义
booleanadd添加单个元素
booleanaddAll添加多个元素
viodclear清空
booleancontains查找元素是否存在
booleancontainsAll查找多个元素是否都存在
booleanequals比较此 collection 与指定对象是否相等。
booleanisEmpty判断是否为空
booleanremove删除指定元素
booleanremoveAll删除多个元素

Collection接口的遍历

使用Iterator迭代器

Iterator对象称为迭代器,主要用于编列Collection集合中的元素

//得到当前集合的迭代器对象
Iterator<Object> iter = listname.iterator();
while(iter.hasNext){
    Object outname = iter.next();
    System.out.println(name);
}

List集合

List 接口下面主要有两个实现 ArrayList 和 LinkedList,他们都是有顺序的,也就是放进去
是什么顺序,取出来还是什么顺序,也就是基于线性存储,可以看作是一个可变数组

ArrayList:查询数据比较快,添加和删除数据比较慢(基于可变数组)
LinkedList:查询数据比较慢,添加和删除数据比较快(基于链表数据结构)
Vector:Vector 已经不建议使用,Vector 中的方法都是同步的,效率慢,已经被 ArrayList取代
Stack:是继承 Vector 实现了一个栈,栈结构是后进先出,目前已经被 LinkedList 取代

List的四种种遍历方式

使用Iterator

Iterator iter = col.iterator();
 while(iter.hasNext()){
     Object o = iter.next();
 }

使用增强for

for(Object o : col){
    
}

使用普通for

for(int i = 0;i<list.size();i++){
    Object object = list.get(i);
    System.out.print(object);
}

Lambda表达式

lists.forEach(s -> {
    System.out.println(s);
});

遍历存在的问题

  • 迭代器遍历集合且直接用集合删除元素可能出现
  • 增强for遍历集合且直接用集合删除元素可能出现

解决方案

  • 用迭代器自身的remove去删除元素
  • 使用普通for循环采取i– 或倒序删除
  • 不能使用增强for循环删除集合中元素

Vector

Vector底层也是一个对象数组
Vector是线程同步的,即线程安全。Vector类的操作方法带有synchronized
在开发中,需要线程同步安全,考虑Vector

ArrayList与Vector比较

ArrayList:可变数组;不安全,效率高;如果有参构造1.5倍;如果无参:第一次10、第二次1.5倍扩
Vector:可变数组;安全效率不高;如果无参,默认是10;之后2倍扩容

LinkedList

  1. LinkedList实现了双向链表和双端队列特点
  2. 可以添加任意元素(元素可重复),包括null
  3. 线程不安全,没有实现同步

LinkedList底层原理

底层数据结构是双链表、查询慢、首尾操作的速度极快
LinkedList中维护两个属性first和last分别指向首节点和尾节点

Set接口

  1. 无序(添加与取出的顺序不一致,没有索引
  2. 不允许添加重复元素,最多只有一个null
注意:不能使用索引来获取对象,虽然是随机添加顺序,但取出的是固定的顺序

HashSet

HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)


LinkedHashSet

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

LinkedHashSet底层机制

LinkedHashSet维护了一个hash表和双向链表


Map接口

  1. Map和Collection并列存在。
  2. Map中的key和value可以是任何引用类型的数据
  3. Map中的key不可以重复;value可以重复
  4. Map中的key和value可以为null;但key中只能有一个null
  5. 常用String类作为Map中的key
  6. key与value是一对一的关系

运用

public class MapMethod {
    public static void main(String[] args) {
        //演示map接口常用方法
        Map map = new HashMap();
        map.put("邓超", new Book("", 100));//OK
        map.put("邓超", "孙俪");//替换-> 一会分析源码
        map.put("王宝强", "马蓉");//OK
        map.put("宋喆", "马蓉");//OK
        map.put("刘令博", null);//OK
        map.put(null, "刘亦菲");//OK
        map.put("鹿晗", "关晓彤");//OK
        map.put("hsp", "hsp的老婆");
        System.out.println("map=" + map);

//        remove:根据键删除映射关系
        map.remove(null);
        System.out.println("map=" + map);
//        get:根据键获取值
        Object val = map.get("鹿晗");
        System.out.println("val=" + val);
//        size:获取元素个数
        System.out.println("k-v=" + map.size());
//        isEmpty:判断个数是否为0
        System.out.println(map.isEmpty());//F
//        clear:清除k-v
        //map.clear();
        System.out.println("map=" + map);
//        containsKey:查找键是否存在
        System.out.println("结果=" + map.containsKey("hsp"));//T
    }
}
class Book {
    private String name;
    private int num;
    public Book(String name, int num) {
        this.name = name;
        this.num = num;
    }
}

HashMap小结

  1. Map接口的常用实现类:HashMap、Hashtable、Properties
  2. HashMap是Map接口中使用频率最高的实现类
  3. HasMap是以key-val对的方式存储数据
  4. key不能重复,但是值可以重复,允许使用null键和null值
  5. 如果添加相同的key,则会覆盖原来的key-val,等同于修改
  6. 和HashSet一样,不保证映射的顺序,因为底层是以hash表的方式存储的
  7. HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作

Hashtable的基本介绍

  1. 存放键值对K-V
  2. Hashtable的键值都不能为null,否则会抛异常
  3. Hashtable使用的方法基本和HashMap方法一样
  4. Hashtable是线程安全的,HashMap是线程不安全的
  5. 与HashMap比效率较低

Collections工具类

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

基础运用


public class Collections_ {
    public static void main(String[] args) {
        //创建ArrayList 集合,用于测试.
        List list = new ArrayList();
        list.add("tom");
        list.add("smith");
        list.add("king");
        list.add("milan");
        list.add("tom");
        
//        reverse(List):反转 List 中元素的顺序
        Collections.reverse(list);
        System.out.println("list=" + list);
//        shuffle(List):对 List 集合元素进行随机排序
//        for (int i = 0; i < 5; i++) {
//            Collections.shuffle(list);
//            System.out.println("list=" + list);
//        }

//        sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
        Collections.sort(list);
        System.out.println("自然排序后");
        System.out.println("list=" + list);
//        sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
        //我们希望按照 字符串的长度大小排序
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //可以加入校验代码.
                return ((String) o2).length() - ((String) o1).length();//List允许重复,所以能同时有两个长度相同的
            }
        });
        System.out.println("字符串长度大小排序=" + list);
//        swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
        //比如
        Collections.swap(list, 0, 1);
        System.out.println("交换后的情况");
        System.out.println("list=" + list);

        //Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
        System.out.println("自然顺序最大元素=" + Collections.max(list));
        //Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
        //比如,我们要返回长度最大的元素
        Object maxObject = Collections.max(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length() - ((String)o2).length();
            }
        });
        System.out.println("长度最大的元素=" + maxObject);

        //Object min(Collection)
        //Object min(Collection,Comparator)
        //上面的两个方法,参考max即可

        //int frequency(Collection,Object):返回指定集合中指定元素的出现次数
        System.out.println("tom出现的次数=" + Collections.frequency(list, "tom"));

        //void copy(List dest,List src):将src中的内容复制到dest中
        ArrayList dest = new ArrayList();
        //为了完成一个完整拷贝,我们需要先给dest 赋值,大小和list.size()一样
        for(int i = 0; i < list.size(); i++) {
            dest.add("");
        }
        //注意:size是指元素个数,而length是数组长度,构造器是不会改变size的。不能通过初始化集合来给定大小,因为这并不会改变size,底层是用两个集合的size比较的,size 和 length 不能等同,size 表示 当前集合的元素个数, 随着元素的增加而增加。
        
        //拷贝
        Collections.copy(dest, list);
        System.out.println("dest=" + dest);

        //boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
        //如果list中,有tom 就替换成 汤姆
        Collections.replaceAll(list, "tom", "汤姆");
        System.out.println("list替换后=" + list);
    }
}

时间变得如此宝贵,坐下来休息是件不堪设想的事情。只要朝着某个方向去,或朝任何方向走,就多少会有进展,说不定就会有好结果,否则就是坐以待毙,就是缩短死神赶上他们的时间。 ——马克·吐温《汤姆·索亚历险记》
最后修改:2023 年 01 月 09 日
如果觉得我的文章对你有用,请随意赞赏