一些之前不太了解的东西

一、概述

  • 集合是对象的容器,能够填充和存储不同类型的对象,也能够通过范式规范存储对象的类型,存入相同类型的对象。集合能够自动扩充,是不定长的“数组”。这些容器具有几个特征:存储数据的特征(单列/键值对)、对象的类型(范式)、容器的数据结构(数组、链表、红黑树)、索引、数据的不重复性、有序性、非空性和安全性。Java针对数据的批量存储提供了Collection和Map两类容器,分别存储单列数据和键值对数据。两类容器都有对应的不同存储数据类型的实现类和接口。不同集合对象的主要的特点详见下面的思维导图。(ᴵ上标表示是一个接口) 集合 - 图1
  • 集合工具类:位于java.util.Arrays(操作数组对象的工具类)、java.util.Collections(操作集合对象的工具类)中,其中都是静态方法。

    1. Collections.fill(list, 20); // 将list中存在的元素替换为20
    2. Collections.max(list); // 返回list最大值
    3. Collections.min(list); // 返回list最大值
    4. Collections.reverse(list); // 反转list
    5. Collections.sort(list); // 将list按自然顺序排序
    6. Collections.shuffle(list); // 打乱list顺序
    7. Collections.addAll(list, 1, 3, 5, 7); // 向list中批量添加数据

    二、Collection集合

  • Collection是实现单列数据的接口,子接口包括List和Set。List的实现类包括ArrayList和LinkedList;Set的实现类包括HashSet和TreeSet。

    • Collection是迭代器Iterable的实现接口。每个Collection的实现类都有一个迭代器对象,能够像指针一样指向下一个对象。可以通过循环和迭代器遍历数据。使用迭代器时不可增删数据。

      1. Iterator iterator = arraylist.iterator();
      2. while(iterator.hasNext()) {
      3. Object obj = iterator.next();
      4. System.out.println(obj);
      5. }
    • HashSet是Set接口的实现类,同时继承了HashMap(详见哈希们)。TreeSet是Set接口的子接口SortedSet的实现类,同时继承了TreeMap,将数据存入Key中。

      三、Map集合

  • Map是实现键值对(Key-Value)的接口,能够存储映射数据,其实现类包括HashMap和TreeMap。

    • Map可以单独遍历Key和Value,也可以通过内部接口entrySet遍历每一对键值对:
      1. Set entrySet = map.entrySet();
      2. for(Object obj : entrySet){
      3. Map.Entry entry = (Map.Entry)obj;
      4. System.out.println(entry.getKey()+" : "+entry.getValue());
      5. }

      四、不重复性

  • 实现HashMap、HashSet中对象的不重复性:比较两个对象是否相同,是根据数据的哈希值和equals()方法进行判断的:首先调用类中的hashCode()方法,若为true,再调用equals()(默认判断地址),若都返回true则判断该数据与其内的某一数据相同。可以重写这两个方法以判断一个数据是否可以加入HashMap或HashSet中。当加入是数据Key值相同而Value值不同时,会更新Key值对应的Value值。

    • hashCode()方法:在Object的hashCode()方法是根据对象在内存中的特征返回一个哈希值,可以重写这个方法,返回通过Objects.hash()静态方法来生成对象数据的哈希值,而不是地址的哈希值。
    • equals()方法:在Object的equals()方法是比较地址,当然这有很多局限性。故可以对这个方法进行重写,以比较内部属性是否相等,而不是仅比较地址。很多包装类都对equals()进行了重写,以比较包装的内容。
      • 对这个方法重写时,需要满足几个约定俗成的条件:自反性、对称性、传递性、一致性、非空性。相等的一般依据是:两个对象同类、两个同时为空或同时不为空、对应属性值相等。
    • List集合类型是可以存入重复数据的,故不需要判断存入的数据是否相同。而TreeMap和TreeSet则通过 comparaTo()方法或比较器来判断是否重复。

      五、有序性和元素可比较性

  • 集合对象的有序性:集合类型在内存中的顺序主要有三种:按存储顺序、按哈希值、自然排序(定制化排序)。

    • List接口的实现类ArrayList、LinkedList,以及LinkedHashMap是按存储顺序排序。
    • HashMap和HashSet是按哈希值存储,故表现出数据是“无序”的。
    • TreeMap和TreeSet调用了java.lang.Comparable接口的comparaTo()方法,或实现比较器java.util.Comparator接口来比较存入的对象,并放入红黑树中。当存入的对象重写了comparaTo()方法,便可以比较这些对象,并放入红黑树中。大部分包装类(字符串、基本数据类型的包装类)都默认重写了comparaTo()方法,对对象进行合适地比较,呈现出“自然”的顺序。当对象不具有可比性时,便不能存入其中。
  • 实现TreeMap、TreeSet中对象的可比较性:为了实现普通对象的可比较性,需要通过对对象的某些特征进行比较。

    • comparaTo()方法:自然排序实现的方法。该方法放在要放入集合的对象的类中,然后该类的对象便是可比较的。该方法返回值的正负,决定了要存入的数据是放在比较节点的前面还是后面。

      1. public class Student implements Comparable { // 实现接口
      2. int age;
      3. @Override // 重写方法
      4. public int compareTo(Object o) { // o是要存入的对象
      5. Student other = (Student)o; // 将对象转型,用other表示要存入的对象,用this表示当前比较的节点
      6. if(this.age > other.age) { // 要传入的对象较小时
      7. return 1; // 正数,放在比较节点的后面
      8. } else if(this.age < other.age) { // 要传入的对象较大时
      9. return -1; // 负数,放在比较节点的前面
      10. } else {
      11. return 0; // 表示两个对象相同(对于TreeMap,将修改对应的Value值为新值;对于TreeSet,该数据不放入)
      12. }
      13. } // 大的放前面,小的放后面,降序
      14. }
    • 比较器排序:又称客户化排序。该方法写在一个实现类(一般使用匿名内部类实现)中,并将实现类对象传入集合类型构造器即可实现排序。同样是返回一个正负值。

      1. Comparator c = new Comparator() {
      2. @Override
      3. public int compare(Object o1, Object o2) {
      4. Student s1 = (Student) o1;
      5. Student s2 = (Student) o2;
      6. return s1.age > s2.age ? 1 : (s1.age == s2.age ? 0 : -1);
      7. // 或者 return s1.age - s2.age;
      8. }
      9. };
      10. Set set = new TreeSet(c);

      六、其它

  • 容器对象的非空性:HashTable是非空的集合。

  • 容器对象的安全性:Vector和Hashtable是线程安全的集合,其中的大部分方法具有synchronized修饰符。
  • 容器对象可以存储任意的引用类型数据。若要对存入的类型进行规范,则需要使用范式,详见范型