Java--Collection集合

掌握Collection接口下每个集合底层的数据结构,熟悉集合的常用方法,学会创建集合并对其进行操作


集合概述

  • 集合实际上是一个容器,一个载体,可以容纳其他类型的数据。
  • 集合不能直接存储基本数据类型,也不能直接存储Java对象,集合当中存储的都是Java对象的内存地址(存储的是引用)。
list.add(100); //自动装箱 Integer
  • 在Java中每一个不同的集合,底层会对应不同的数据结构,往不同的集合中存储元素,等于数据放到了不同的数据结构当中。数据存储的结构就是数据结构。不同的数据结构,数据存储方式不同。
  • 所有的集合类和集合接口在java.until包下

Collection集合继承结构

结构继承图:
在这里插入图片描述

Collection接口

Collection接口的常用方法

以为Collection接口是公共的,所有集合都有这个接口中的方法,Collection接口的常用方法如下:
boolean add(Object e); 向集合中添加元素
int size(); 获取集合元素的个数
void clear(); 清空集合
boolean contains(Object o); 判断集合是否包含元素o
boolean remove(Object o); 删除集合中某个元素
boolean isEmpty(); 判断集合中元素个数是否为0
Object[ ] toArray();把集合转换成数组

import java.util.ArrayList;
import java.util.Collection;
public class Test01 {
    public static void main(String[] args) {
        //创建集合对象
       Collection c = new ArrayList();

        //向集合中添加元素
        c.add(1100); //自动装箱  Integer x = new Integer();
        c.add(true);
        c.add(new Object());

        //获取集合中元素个数
        System.out.println("集合中元素个数:"+c.size()); //3
        //删除集合中某个元素
        c.remove(1100);
        System.out.println("集合中元素个数:"+c.size()); //2

        //清空集合
        c.clear();
        System.out.println("集合中元素个数:"+c.size()); //0


        //判断集合中是否包含某个元素
        c.add("Hello");
        c.add("word");
        c.add("lic");
        System.out.println(c.contains("lic")); //true

        //判断集合是否为空(集合中是否存在元素)
        System.out.println(c.isEmpty()); //false

        //集合转化成数组
        Object[] objects = c.toArray();
        for (Object o: objects
             ) {
            System.out.print(o+" ");
        }
    }
}

运行结果如下:
在这里插入图片描述

常用方法中的contains方法和remove方法在使用时会调用equals方法。
在这里插入图片描述
以上源码可知,contains方法调用indexOf方法,而indexOf方法调用equals方法。所以集合在判断是否包含某个元素o,集合会拿着自己集合中每一个元素和o比较,如果equals方法返回为true,则表示包含元素o。

示例:自定义Date类,此时没有重写equals方法,看看会出现问题吗。

class Date{
    private int year;
    private int month;
    private int day;

    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

}

测试类:

import java.util.ArrayList;
import java.util.Collection;
public class Test02 {
    public static void main(String[] args) {
        //创建集合
       Collection c = new ArrayList();
       //创建Date对象 d1
        Date d1 = new Date(2022, 8, 27);
        //将d1添加到集合c
        c.add(d1);
        //判断集合中是否包含
        Date d2 = new Date(2022, 8, 27);
        System.out.println(c.contains(d2));
    }
}

运行结果:
在这里插入图片描述
但是通过看代码,实际上集合中包含“2022年8月27日”这个数据,但结果说明不包含,这是出现了什么问题?
问题在于没有重写Date的equals方法,不重写equals方法,调用的是Object类的equals。比较对象的内存地址,这里应该比较内容,就需要重写Date类的equals方法。

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Date date = (Date) o;
        return year == date.year && month == date.month && day == date.day;
    }

运行结果:在这里插入图片描述
说明放在集合中的元素是需要重写equals方法的!!

测试remove方法有没有调用equals方法。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

public class Test02 {
    public static void main(String[] args) {
        //创建集合
       Collection c = new ArrayList();
        //添加a元素
        Integer a = new Integer(100);
        c.add(a);
        //删除b元素
        Integer b = new Integer(100);
        c.remove(b);
        //元素个数
        System.out.println(c.size());
    }

运行结果:
在这里插入图片描述
以上程序中删除集合的b元素,a也被删除了。说明remove方法调用equals方法。更加说明了存储在集合中的元素需要重写equals方法。

Collection接口的通用迭代

集合的遍历又叫集合的迭代,Java的集合框架中,Collection接口继承了Iterable接口,表示Collection集合元素都是可迭代的,集合Collection通过调用iterator方法获取迭代器对象,通过Iterator迭代器接口的hasNext和next方法完成集合元素的迭代。
示例:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
/*
集合遍历、迭代专题
 */
public class Text03 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add(100);
        c.add("hello");
        c.add(new Object());
        c.add(100);

        //获取集合的迭代器对象
        Iterator it = c.iterator();
        /*
        迭代器对象的两个方法
        boolean hasNext  返回true表示还有元素可以迭代
        Object next 让迭代器前进一位,并将指向的元素返回
         */
        while (it.hasNext()){
            //存进去什么类型,取出来还是什么类型
            Object obj = it.next();
            //输出转换成字符串,println调用toString类型
            System.out.println(obj);
            }
        }
    }

运行结果如下:
在这里插入图片描述

集合迭代过程中的删除

使用迭代器遍历集合过程中删除集合的元素,调用迭代器的remove方法删除元素

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

/*
集合遍历、迭代专题
 */
public class Text03 {
    public static void main(String[] args) {
             //创建集合
             Collection c2 = new HashSet();
             //加入元素
             c2.add(100);
             c2.add(100);
             c2.add("lic");
             c2.add(200);
             c2.add(400);
             c2.add("li");
             //生成迭代器
            Iterator it2 = c2.iterator();
            while(it2.hasNext()){
                Object obj2 = it2.next();
                //使用迭代器的remove方法删除元素
                it2.remove();
                System.out.println(obj2);
            }
        System.out.println(c2.size());
        }
    }

List接口

  • 1.List集合特点:有序可重复。 元素有下标;从0开始,以1递增。存储一个1可以再存储一个1
  • 2.List集合是Collection接口的子接口,有特有的方法。
  • 在Java中,List接口是一个有序的集合,它允许我们按顺序存储和访问元素。
  • 来看一下List集合的特有的方法。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
1.List集合特点:有序可重复。 元素有下标;从0开始,以1递增。存储一个1可以再存储一个1
2.List集合是Collection接口的子接口,有特有的方法

 */
public class Test01 {
    public static void main(String[] args) {
        //创建List接口的集合
        List list = new ArrayList();
        //添加元素
        list.add("A");
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add(1,"lic");
        //生成迭代器
        Iterator it = list.iterator();
        //遍历
        while ((it.hasNext())){
            System.out.println(it.next());
        }
        
        //根据下标获取元素
        System.out.println(list.get(0));
       
        //有下标,通过下标遍历集合的元素
        for (int i = 0; i < list.size(); i++) {

            System.out.println(list.get(i));
        }

        //获取指定对象第一次出现的索引
        System.out.println(list.indexOf("A"));

        //获取指定对象最后一次出现的索引
        System.out.println(list.lastIndexOf("A"));

        //删除指定下标位置的元素
        list.remove(1);
        System.out.println(list.size());

        //修改指定位置的元素
        System.out.println(list.set(1, "lng"));

        for (int i = 0; i < list.size(); i++) {

            System.out.println(list.get(i));
        }
    }
}

List集合之ArrayList

  • 默认初始化容量是10
  • 集合底层是一个Object[ ] 数组
  • 底层是数组的优点:检索效率比较高;缺点:随意增删元素效率低
  • 构造方法: new ArrayList(); (无参构造)。 new ArrayList(int a);(有参构造)ArrayList(Collection c); (构造一个包含指定collection的元素的列表,元素按照该collection的迭代器返回排列顺序)
  • ArrayList集合的扩容:原容量的1.5倍
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

public class Test02 {
    public static void main(String[] args) {
        //默认初始化为0
        List list1 = new ArrayList();
        //指定初始化容量100
        List list2 = new ArrayList(100);
        //创建HashSet集合
        Collection c = new HashSet();
        //添加元素
        c.add(1);
        c.add(2);
        c.add(3);
        //HashSet集合转化为List集合
        List list3 = new ArrayList(c);
        for (int i = 0; i < list3.size(); i++) {
            System.out.println(list3.get(i));
        }
    }
}

List集合之LinkedList

LinkedList底层数据结构的链表:单向链表、双向链表、循环链表。

链表最基本的单元是结点,在单向链表中,每一个结点由两部分组成:存储的数据data、指向下一结点的内存地址next。并且每个结点在空间存储上内存地址不连续,和数组完全不同。

在双向链表中,有三部分组成:存储的数据data、指向上一结点的内存地址、指向下一结点的内存地址。

每个结点在空间存储上内存地址不连续,无法通过数学表达式计算要查找的元素的内存地址,所以只能从头节点开始,一个一个挨着查找,所以检索效率低。但是新增或删减元素时,就不需要涉及大量元素位移问题,所以增删效率高。
综上
链表的优点:随机增删元素效率高。
链表的缺点:检索效率较低。

List集合之Vector

Vector底层也是数组,初始化容量是10,扩容后是原容量的2倍,Vector中所有的方法都是线程同步的,带有synchronized关键字,是线程安全的。效率低,使用少。

将线程不安全的ArrayList集合转换成线程安全:

Collections.synchronizedList(ArrayList);

Set接口

Set集合存储元素的特点:无序不可重复。无序指元素没有下标,不可重复就是存一个元素后,就不能存相同的元素了。

Set集合之HashSet

  • HashSet底层就是HashMap
    在这里插入图片描述

  • 向HashSet中添加元素,实际就是把该元素作为键添加到底层的HashMap

  • HashSet就是HashMap键的集合
    在这里插入图片描述

        HashSet hashSet = new HashSet();
        hashSet.add("a");
        hashSet.add("a");
        hashSet.add("b");
        hashSet.add("ff");
        hashSet.add("ee");
        for (Object s:hashSet
             ) {
            System.out.println(s);
        }

运行结果:

在这里插入图片描述

Set集合之TreeSet

TreeSet集合实现了SortSet接口。特点是:没有下标,不可重复,但是存进去的元素会自动按照大小顺序排序,称为可排序集合(无法对自定义类型排序,因为没有说明自定义类型的比较规则)。

  • TreeSet底层是TreeMap
  • 在创建TreeSet时,可以指定Comparator比较器,对集合中的元素进行比较
import java.util.Comparator;
import java.util.TreeSet;

public class Test06 {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<>(Comparator.reverseOrder());
        treeSet.add("ad");
        treeSet.add("ac");
        treeSet.add("bc");
//调用比较器  降序排序
        System.out.println(treeSet);
    }
}
  • 没有指定Comparator比较器,就要求元素的类实现Comparable接口
import java.util.Iterator;
import java.util.TreeSet;
//TreeSet里编写Comparable接口
//如果年龄相同,比较名字
public class Test08 {
    public static void main(String[] args) {

        TreeSet<user> users = new TreeSet<>();

        users.add(new user(12,"ued"));
        users.add(new user(12,"lic"));
        users.add(new user(15,"drc"));
        users.add(new user(13,"wsc"));

        Iterator<user> iterator = users.iterator();
        while (iterator.hasNext()){
            user next = iterator.next();
            System.out.println(next);
        }

    }
}
class user implements  Comparable<user>{
    int age;
    String name;

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

    @Override
    public String toString() {
        return "user{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo(user o) {
        if(this.age==o.age){
            return this.name.compareTo(o.name);
        }else{
            return this.age-o.age;
        }
    }
}

结果如下:
在这里插入图片描述

  • 如果不调用,默认是升序
//不调用  默认升序
        TreeSet<String> treeSet1 = new TreeSet<>();
        treeSet1.addAll(treeSet);
        System.out.println(treeSet1);

结果如下:
在这里插入图片描述

泛型

泛型就是把数据类型作为参数传递,在集合框架使用频繁,泛型的好处是在编译时可以进行数据类型的检查。

  • 没有使用泛型,不明确集合存储元素是什么类型,可能会进行强制转型
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test07 {
    public static void main(String[] args) {
        Collection list = new ArrayList();
        //添加元素
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        //遍历
        Iterator iterator = list.iterator();
                
        while (iterator.hasNext()){
            //没有使用泛型,返回Object类型
            Object s = iterator.next();
            //使用String类的方法需要 向下转型
            String str = (String) s;
            System.out.println(str.substring(1));
        }

    }
}
  • 使用泛型后,在编译阶段起作用,明确元素类型,不用强转类型了
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test07 {
    public static void main(String[] args) {
        //定义集合使用泛型,list只能存储String类型的元素
        Collection<String> list = new ArrayList<>();
        //添加元素
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        //遍历
        Iterator<String> iterator = list.iterator();
        //使用泛型后,iterator返回String类型,而不是Object类型
        while (iterator.hasNext()){
            String s = iterator.next();
            System.out.println(s.substring(1));
        }
    }
}

如何自定义泛型

自定义泛型时,<>里面的内容是标识符,任意定义合法的标识符。比如下面Test05使用的泛型类型是,那么Method方法的参数类型也必须是T

import java.util.*;
//自定义泛型
public class Test05 <T> {

    public void Method(T o){
        System.out.println(o);
    }

    public static void main(String[] args) {
        Test05<Integer> a = new Test05<>();
        a.Method(12);
        Test05<String> b = new Test05<>();
        b.Method("aa");
    }
}

Collections工具类

Collection是一个集合接口,Collections是一个集合工具类,升序排序、降序排序、二分法查找、非线程安全集合转换成线程安全集合,但是Collections传进去的参数只能是List。

import java.util.*;

//Collection是一个集合接口 Collections是一个集合工具类
public class collections {
    public static void main(String[] args) {

        Set<Integer> set = new HashSet<>();
        //Set集合之后就是线程安全的
        Collections.synchronizedSet(set);
        //添加元素
        set.add(21);
        set.add(5);
        set.add(15);
        set.add(8);

        //通过构造方法 Set集合转化为List集合
        List<Integer> list = new ArrayList<>(set);
        //升序排序
        Collections.sort(list);
        //输出
        for (Integer s:list
             ) {
            System.out.println(s);
        }

        //二分法查找
        System.out.println("5所在的下标:"+Collections.binarySearch(list, 8));

        //降序排序 反转
        Collections.reverse(list);
        for (Integer in:list
             ) {
            System.out.println(in);
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值