java中的Collection集合(详解)

Collection集合


集合是:存储对象的容器,存储对象的对象(elements)。在数组中也可以存储对象,可代替数组,而用Collection集合存储对象,可以使对象拥有更多的特点和功能。 ​ 特点是:容器的工具类,定义了对多个对象进行操作的方法。

public interface Collection<E> extends Iterable<E>

Collection接口的子类集合有些是允许有重复元素,有些却没有。JDK不提供任何实现类直接实现此接口。Collection接口有很多抽象方法,是它的子接口或者实现类共性的标准。 Collection中有20个方法:


List接口集合

List接口的特点:有序,有下标,元素可以重复。 从List接口的特点,可以猜出List接口中定了一些抽象方法。

public interface List<E> extends Collection <E>

List接口中有41个方法

  1. void add(int index,Object o);//在index的位置上插入对象o。

  2. boolean addAll(int index,Collection c);//将一个集合中的元素添加到此集合中的index位置。

  3. Object get(int index);//返回指定位置的元素。

  4. List subList(int fromIndex,int toIndex);//返回它们之间的集合元素。


List接口---ArrayList实现类(重点)

ArrayList实现类遵循Collection和List接口的标准,所以ArrayList实现类具备有序、有下标、元素可以重复的3种特点,底层是数组结构实现,查询快,增删慢。

注:当在中间插入元素时,后面的每个元素需要往后按顺序移动。

public class ArrayList<E> extends AbstractList <E> implements List <E>, RandomAccess , Cloneable , Serializable

List 接口的可调整大小数组实现。实现所有可选列表操作,并允许所有元素,包括 null 。除了实现 List 接口之外,此类还提供了一些方法来操纵内部用于存储列表的数组的大小。 (这个类大致等同于 Vector ,除了它是不同步的,所以线程不安全,但是运行效率快)。

ArrayList的构造方法:

 ArrayList()     构造一个初始容量为 10 的空列表。
 ArrayList(int initialCapacity)      构造一个具有指定初始容量的空列表。
 ArrayList(Collection<? extends E> c)    构造一个包含指定集合元素的列表,按照集合迭代器返回元素的顺序。

注:ArrayList实现类底层是一个数组;数组结构实现,查询快、增删慢。JDK6初始容量为10,JDK7初始化容量改为0。思考:为什么会改为0?答:一开始初始化容量为10的话,如果不使用这么多容量会造成资源浪费,初始化改为0时,只需添加一个元素会自动+1。


List接口---Vector实现类

Vector实现类与ArrayList实现类差不多时一样的,同样具备有序、有下标、元素可以重复三种特点,底层是数组结构实现,查询快,增删慢。

public class Vector<E> extends AbstractList <E> implements List <E>, RandomAccess , Cloneable , Serializable

(重点)Vector类与ArrayList类区别在于:Vector类是线程安全的,运行效率慢;而ArrayList类是不安全的,运行速率快。如果不考虑线程安全问题,建议使用ArrayList代替Vector。


List接口---LinkedList实现类

LinkedList实现类具备有序、有下标、元素可以重复三种特点,底层是链表结构实现,查询慢,增删快

public class LinkedList<E> extends AbstractSequentialList <E> implements List <E>, Deque <E>, Cloneable , Serializable

所有操作的执行都符合双向链表的预期。索引到列表中的操作将从开头或结尾遍历列表,以更接近指定索引的为准。

注:在中间插入元素时,无需移动元素,直接开辟空间让前面的元素指向该空间。


泛型集合

泛型集合

泛型集合的概念:参数化类型、类型安全的集合,强制集合的元素类型一致。一个容器的泛型是什么引用类型,就只能放入相对应的数据类型。

特点: 1、编译时即可检查,而非运行时抛出异常。 2、访问时,不必类型转换(拆箱)。 3、不同泛型之间引用不能相互赋值,泛型集合不存在多态

泛型集合的由来:早期使用Object的引用来实现参数的“任意化”,而该特点的缺陷是要做显示的强制类型转换。对于强制转换类型错误的情况,编译器可能不提示错误,而在运行时才出现异常,这是一个类型的安全隐患,所以泛型就是为了阻止这个安全问题产生的。

泛型的好处:更好的安全性、可读性,省去强转类型的麻烦。

程序正常运行的重要目标是把bug(异常)扼杀在摇篮里,能在写代码的时候处理异常,就不要等到程序运行的时候。

不加泛型时,例如:

 public class TestGenericityArrayList{
     public static void main(String[] args){
         List list = new ArrayList();
         list.add('a');
         list.add(20D);
         list.add(true);
         list.add(20);
         
         int sum = 0;
         for(int i=0;i<list.size();i++){
 //            sum += list.get(i);//error,不同类型之间不能做运算
         }
         System.out.printin(sum);
     }
 }

加泛型时,例如:

 public class TestGenericityArrayList {
     public static void main(String[] args) {
         List<Double> list = new ArrayList<Double>();
 //      list.add('a');//error,加了泛型之后,需要遵循泛型的定义标准,不能往集合添加指定泛型以外的类型
         list.add(20D);
         list.add(50D);
         list.add(200D);
         list.add(150D);
 //      list.add(true);
 //      list.add(20);
 ​
         int sum = 0;
         for(int i=0;i<list.size();i++){
             sum += list.get(i);
         }
         System.out.println(sum);//420
     }
 }
 ​

注:<>里面放的必须是引用数据类型,例如:自定义的类,或者包装类等;泛型集合可以添加类和子类的对象

泛型的注意事项:

泛型的前后<>的引用数据类型必须一致,或者后面的那个<>不写;数组的类型前后也要一致。

 //泛型
 ArrayList<Integer> list = new ArrayList<Integer>();
 List<Double> list = new Vector<>();
 ​
 //数组
 int[] arr = new int[]{};
 ​
 //错误示范
 List<Object> list = new ArrayList<Student>();//Error,泛型不存在多态
 int[] arr = new String[]{};

Set接口集合

Set接口的特点:无序、无下标、元素不可重复。 从Set接口的特点来看,List接口中有一些定义的包含有下标(index)的方法是没有的。

public interface Set<E> extends Collection <E>

Set接口中有29个方法:


Set---HashSet实现类

HashSet类实现了Set接口,则HashSet类具备无序、无下标、元素不可重复三种特点。

public interface Set<E> extends Collection <E>

不包含重复元素的集合。更正式地说,集合不包含满足 e1.equals(e2) 的一对元素 e1 和 e2,并且最多包含一个空元素。顾名思义,这个接口模拟数学set抽象。因为没有下标,只能使用forEach循环遍历。

构造方法:

 HashSet()
 构造一个新的空集;后备 HashMap 实例具有默认初始容量 (16) 和负载因子 (0.75)。
 HashSet(int initialCapacity)
 构造一个新的空集;后备 HashMap 实例具有指定的初始容量和默认负载系数 (0.75)。
 HashSet(int initialCapacity, float loadFactor)
 构造一个新的空集;后备 HashMap 实例具有指定的初始容量和指定的负载因子。
 HashSet(Collection<? extends E> c)
 构造一个包含指定集合中的元素的新集合。

【复习:】Object类的hashCode方法

public int hashCode(){} 作用:返回该对象的十进制的哈希码值。 哈希算法根据对象的地址或者字符串或者数字计算出来的int数值。 哈希码值并不唯一,但是可以保证相同对象返回相同的哈希码值,尽量保证不同的对象返回不同的哈希码值。

【思考:】如何保证HashSet集合的元素不重复??

HashSet集合是首先通过判断对象的hashCode()哈希码值是否相同,如果哈希码值相同,则会自动调用equals()来判断是否为同一对象(可以重写equals方法判断认为内容相同也是相同元素);如果哈希码值不相同,则可插入该元素。

例如:

 public class Test_HashSet {
     public static void main(String[] args) {
         HashSet<Student> students = new HashSet<Student>();
         Student s1 = new Student("chen",21,"男",98D);
         Student s2 = new Student("ding",19,"女",99D);
         Student s3 = new Student("wang",15,"男",92D);
         Student s4 = new Student("lily",20,"女",93D);
         Student s5 = new Student("chen",21,"男",98D);
 ​
         students.add(s1);
         students.add(s2);
         students.add(s3);
         students.add(s4);
         students.add(s1);  //地址相同(hashCode返回的值相同),被认定为重复元素。
         students.add(s5);  //地址不同、内容相同,被认定为重复元素
 ​
         for(Student stu : students){
             System.out.println(stu);
         }
     }
 }
 ​
 class Student{
     String name;
     Integer age;
     String sex;
     Double score;
 ​
     public Student() {}
     public Student(String name, Integer age, String sex, Double score) {
         this.name = name;
         this.age = age;
         this.sex = sex;
         this.score = score;
     }
 ​
     @Override
     public String toString() {
         return "Student     [" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + ", score=" + score + ']' + "\t" + this.hashCode();
     }
 ​
     @Override
     public int hashCode() {
         return this.name.hashCode() + this.age + this.sex.hashCode() + this.score.hashCode();
     }
 ​
     //当返回的hashCode值与HashSet里的某一个值相同时,会自动调用equals方法再判断
     @Override
     public boolean equals(Object o) {
         System.out.println("---equals Executed---");
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         Student student = (Student) o;
         return Objects.equals(name, student.name) && Objects.equals(age, student.age) && Objects.equals(sex, student.sex) && Objects.equals(score, student.score);
     }
 }

Set---LinkedHashSet实现类

上面的HashSet的特点是无下标、无序、元素不可重复。当需要一个有序但不可重复的集合时,可以用LinkedHashSet类。LinkedHashSet类比HashSet多了链表结构,与其无差多少。

LinkedHashSet实现类的特点: 1、元素不可重复 2、没有下标 3、有序(按插入的顺序排列或者自然排序)

LinkedHashSet类的底层是哈希表+链表,与HashSet相比多了链表,也就是有了链表才能保证有序

public class LinkedHashSet<E> extends HashSet <E> implements Set <E>, Cloneable , Serializable

构造方法:

 LinkedHashSet()使用默认初始容量 (16) 和加载因子 (0.75) 构造一个新的空链接哈希集。
 LinkedHashSet(int initialCapacity)使用指定的初始容量和默认加载因子 (0.75) 构造一个新的空链接哈希集。
 LinkedHashSet(int initialCapacity, float loadFactor)使用指定的初始容量和加载因子构造一个新的空链接哈希集。
 LinkedHashSet(Collection<? extends E> c)使用与指定集合相同的元素构造一个新的链接哈希集。

Set---TreeSet实现类

特点: 1、元素不可重复 2、无下标 3、对元素自动排序

TreeSet集合中的元素必须是可以排序的。

public class TreeSet<E> extends AbstractSet <E> implements NavigableSet <E>, Cloneable , Serializable

构造方法:

 TreeSet()构造一个新的空树集,根据其元素的自然顺序进行排序。
 TreeSet(Collection<? extends E> c)构造一个新的树集,包含指定集合中的元素,按照自然排序它的元素。
 TreeSet(Comparator<? super E> comparator)构造一个新的空树集,根据指定的比较器排序。
 TreeSet(SortedSet<E> s)构造一个包含相同元素并使用与指定排序集相同顺序的新树集。

【思考:】TreeSet集合中是如何对元素进行排序的?

【答:】TreeSet实现了SortedSet接口,所以集合中的元素必须是可以进行排序的,则会对集合中的元素自动排序。也可以通过compareTo方法指定排序规则。如果是自定义的类对象元素,类必须实现Comparable接口,当compareTo返回的是0,则会被认定为重复元素。

例如:

 public class TestTreeSet2 {
     public static void main(String[] args) {
         TreeSet<Student> ts = new TreeSet<Student>();
         Student stu1 = new Student("wang",18,"男",94D);
         Student stu2 = new Student("wang",18,"女",94D);
         Student stu3 = new Student("ding",19,"女",99D);
         Student stu4 = new Student("chen",22,"男",97D);
         ts.add(stu1);
         ts.add(stu2);
         ts.add(stu3);
         ts.add(stu4);
         for(Student stu : ts){
             System.out.println(stu);
         }
     }
 }
 ​
 class Student implements Comparable<Student>{//必须实现Comparable接口中的抽象方compareTo
     String name;
     int age;
     String sex;
     double score;
     public Student(String name, int age, String sex, double score) {
         this.name = name;
         this.age = age;
         this.sex = sex;
         this.score = score;
     }
 ​
     @Override
     public String toString() {
         return "Student{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 ", sex='" + sex + '\'' +
                 ", score=" + score +
                 '}';
     }
     @Override
     public int compareTo(Student student) {//compareTo等于0时,TreeSet会被认定为重复元素
         //年龄降序
         if(this.age > student.age) {
             return -1;
         }else if(this.age < student.age){
             return 1;
         }else{
             //如果年龄相等时,以分数做降序排序
             if(this.score > student.score){
                 return -1;
             }else if(this.score < student.score){
                 return 1;
             }else{
                 //如果年龄和分数都相等,以姓名做升序排序
                 if(this.name.compareTo(student.name) > 0){//True为升序
                     //System.out.println(this.name.compareTo(student.name));
                     //System.out.println("被执行");
                     return 1;
                 }else if(this.name.compareTo(student.name) < 0){//True为降序
                     return -1;
                 }else {
                     //如果年龄、分数、姓名都相同,则判断性别是否为相同,如果相同会被认为同一元素或对象
                     return this.sex.compareTo(student.sex);
                 }
             }
         }
     }
 }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值