Java学习——Collection集合

Java学习——Collection集合

今天我们来学习Collection集合,学习这个集合之前我们先要知道为什么要引入集合。我们都直到Java语言是一种面向对象的语言,所以为了存取对象方便,就引入了集合的概念。

那么集合和数组到底又有什么区别呢?

  • 长度区别:数组的长度一旦定义就不可变的;但是集合的长度是可变的,是可以自动扩容的
  • 存储的数据类型区别:我们知道数组是可以存储基本数据类型也可以存储引用数据类型;但是集合只能存储引用数据类型(当然我们Java语言有自动拆箱和自动装箱,这个存储的数据类型是无法限制集合的。比如我们想要存储int类型的数据,Java语言就会为我们自动装箱成Integer类型的数据存入,取的时候道理相同)
  • 存的内容种类区别:数组只能存一种数据类型类型的数据;而集合可以存储多种数据类型的数据

了解了集合的基本概念以后,我们也必须要掌握常用的Collection集合的继承体系,如下:
在这里插入图片描述
在Collection中我们最常用的就是List集合和Set集合这两种集合,那么就先要只知道顶层父类的方法:

  • boolean add(Object obj):添加一个元素
  • boolean addAll(Collection c):添加一个集合的元素 (给一个集合添加进另一个集合中的所有元素)
  • void clear():移除所有元素
  • boolean remove(Object o):移除一个元素
  • boolean removeAll(Collection c):移除一个集合的元素(移除一个以上返回的就是true) 删除的元素两个集合的交集元素,如果没有交集元素 则删除失败 返回false
  • boolean contains(Object o):判断集合中是否包含指定的元素
  • boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(这个集合 包含 另一个集合中所有的元素才算包含 才返回true)
  • boolean isEmpty():判断集合是否为空
  • Iterator iterator():获取集合的迭代器对象
  • int size():获取元素的个数
  • boolean retainAll(Collection c):获取两个集合的交集元素(交集:两个集合都有的元素)
  • Object[] toArray():把集合转换为数组

这些方法简单易懂,就不做详细的解释了

当然子类的方法会更加丰富,现在我们就先从List这个分支学起:

一、 List

List集合的特点:元素有序,并且每一个元素都存在一个索引,元素可以重复

1.ArrayList

ArrayList集合的底层数据结构是数组,查询快,增删慢;线程不安全,效率高

2.Vector

Vector集合底层数据结构是数组,查询快,增删慢。线程安全,效率低
Vector集合线程安全是因为它底层源码都用synchronized关键字所修饰

3.LinkedList

LinkedList集合底层数据结构是链表,查询慢,增删快,线程不安全,效率高

下面我们来看看使用迭代器对象遍历集合:

public class Test {
    public static void main(String[] args) {
        //创建ArrayList集合对象,泛型定为Integer类型
        ArrayList<Integer> list = new ArrayList<>();
        //向集合中添加元素
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        list.add(8);
        list.add(9);
        list.add(10);
        //获取Collection集合的父类迭代器对象
        Iterator<Integer> iterator = list.iterator();
        //iterator.hasNext()判断下一个是否有元素
        while (iterator.hasNext()){
            //拿出下个元素,并打印
            Integer next = iterator.next();
            System.out.println(next);
        }
    }
}

/**
 * 输出结果:1
 *          2
 *          3
 *          4
 *          5
 *          6
 *          7
 *          8
 *          9
 *          10
 */

当然List集合也有它特有的迭代器对象,listIterator,也都是一样的用法。

下来我们来看用迭代器对象遍历集合的时候,如果往集合中增加元素,会产生一个异常:

public class Test {
    public static void main(String[] args) {
        //创建ArrayList集合对象,泛型为Integer类型
        ArrayList<Integer> list = new ArrayList<>();
        //向集合中添加元素
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        list.add(8);
        list.add(9);
        list.add(10);
        //获取Collection集合的父类迭代器对象
        Iterator<Integer> iterator = list.iterator();
        //iterator.hasNext()判断下一个是否有元素
        while (iterator.hasNext()){
            //拿出元素
            Integer next = iterator.next();
            if (next==5){
                list.add(100);
            }
            System.out.println(next);
        }
    }
}
输出:	
			1
			2
			3
			4
			5
			Exception in thread "main" java.util.ConcurrentModificationException
				at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
				at java.util.ArrayList$Itr.next(ArrayList.java:851)
				at cn.xiyou.Test.main(Test.java:26)

ConcurrentModificationException并发修改异常,产生这个异常的原因是因为使用迭代器进行遍历的时候,迭代器会计算好集合的长度,但是你在迭代的过程中添加元素,集合长度改变,迭代器就不知道长度为多少了,就会出现并发修改异常。

那么解决的办法有两个:

  1. 使用迭代器特有的add方法去添加元素
  2. 使用for循环遍历集合

这里我们介绍一种新式的for循环:

public class Test {
    public static void main(String[] args) {
        //创建ArrayList集合对象,泛型为Integer类型
        ArrayList<Integer> list = new ArrayList<>();
        //向集合中添加元素
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        list.add(8);
        list.add(9);
        list.add(10);
        //新式for循环遍历集合
        for (Integer i : list) {
            System.out.println(i);
        }
    }
}

二、Set

Set集合的特点:元素无序(存取的顺序不一致)且唯一

1.HashSet

HashSet的底层数据结构是哈希表(JDK1.7之前:链表+数组+红黑树;JDK1.7之后:链表+数组+红黑树),线程不安全,可以存null值。

那么HashSet集合是如何保证元素唯一性的呢?
为了保证HashSet集合的元素唯一性,HashSet集合必须要重写hashCode()和equals()方法。
1.当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据算出来的hashCode值去确定该对象在HashSet中的存储位置。
2.当两个对象的hashCode值相等时,我们会重写equals()方法,让两个对象去比较其内容,如果不一致则存储,如果一致则不存储
所以,要保证HashSet集合元素唯一就必须重写hashCode()和equals()方法。

2.LinkedHashSet

LinkedHashSet底层数据结构是哈希表+链表。链表保证元素有序,哈希表保证元素唯一。

3.TreeSet

TreeSet底层数据结构是二叉树,保证了元素有序

那么在TreeSet中有两种排序方式:

1). 自然排序
比较的对象要实现Comparable接口并重写该接口中compareTo方法,如下:

//实现Comparable接口,并将泛型定为Student
public class Student implements Comparable<Student>{
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public int compareTo(Student student) {
    	//以姓名的字典顺序排序,如果姓名一样,则以年龄大小排序
        int num = student.name.compareTo(this.name);
        int num2 = num==0?student.age-this.age:num;
        return num2;
    }
}

然后新建一个测试类,使用TreeSet集合添加元素,遍历显示结果

public class Test {
    public static void main(String[] args) {
    	//创建TreeSet集合并存储Student对象
        TreeSet<Student> set = new TreeSet<>();
        set.add(new Student("张三",23));
        set.add(new Student("李四",24));
        set.add(new Student("王五",25));
        set.add(new Student("赵六",26));
        set.add(new Student("田七",27));
        set.add(new Student("牛二",28));
        //遍历集合,查看自然排序结果
        for (Student student : set) {
            System.out.println(student.getName()+"=="+student.getAge());
        }
    }
}

结果:

赵六==26
田七==27
王五==25
牛二==28
李四==24
张三==23

2). 比较器排序
比较器排序就比较简单了,比较的类不用实现任何接口,直接向TreeSet集合中传入一个比较器Comparator即可:

public class Test {
    public static void main(String[] args) {
   		 //创建TreeSet集合并传入一个Comparator比较器,然后重写compare方法
        TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getName().compareTo(s2.getName());
                int num2 = num==0?s1.getAge()-s2.getAge():num;
                return num2;
            }
        });
        //向集合中存入对象
        set.add(new Student("张三",23));
        set.add(new Student("李四",24));
        set.add(new Student("王五",25));
        set.add(new Student("赵六",26));
        set.add(new Student("田七",27));
        set.add(new Student("牛二",28));
		//遍历集合看结果
        for (Student student : set) {
            System.out.println(student.getName()+"=="+student.getAge());
        }
    }
}

结果:

张三==23
李四==24
牛二==28
王五==25
田七==27
赵六==26

我们可以看到,比较器排序与自然排序的结果是一样的,在我们平时,建议使用比较器排序

集合的学习是为了以后在编码中选取更合适的集合去存储数据,后面我们还会学到map集合,敬请期待哦!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值