Java常用集合简介


前言

0、数组

      操作数组的工具类 Arrays 中的一些常用方法:

      int binarySearch(type[ ] a,type key):使用二分查找 key 元素在 a 数组中的下标(索引)。a 中不包含 key 元素,返回 -1。要求数组 a 已经升序排列。
      int binarySearch(type[ ] a,int fromIndex,int toIndex,type key):和上一个方法类似,只不过给定了查找区间而已 [fromIndex,toIndex)。

      type[ ] copyOf(type[ ] original,int length):复制 original 得到一个新数组,将其返回。length 为新数组的长度,如果 length < original.length,截取 original 前面 length 个元素;否则在 original 数组之后补齐 length 个元素,新补充的元素为 0、false 或 null。
      type[ ] copyOfRange(type[ ] original,int from,int to):和上一个方法类似,仅能复制 original 数组的 [from,to) 之间的元素。

      boolean equals(type[ ] a,type[ ] b):判断数组 a 和 b 是否相等。要求长度相等且每一个位置上的元素也相等。

      void fill(type[ ] a,type val):将数组 a 的所有元素都赋值为 val。
      void fill(type[ ] a,int fromIndex,int toIndex,type val):将数组 a 在 [fromIndex,toIndex) 之间元素都赋值为 val。

      void sort(type[ ] a):对 a 中的元素进行升序排序。
      void sort(type[ ] a,int fromIndex,int toIndex):对 a 在 [fromIndex,toIndex) 之间的元素进行升序排序。
      void sort(type[ ] a,Comparator c):对 a 中的元素排序,排序依据实现Comparator 接口中的 compare 方法来决定。

      String toString(type[ ] a):将数组 a 转化为一个字符串。每个元素采用 ", ”隔开。

      对数组降序排序示例:

    public static void main(String[] args) {
        Integer[] a={5,2,8,4};
        Arrays.sort(a,new Comparator<Integer>(){//匿名内部类
            public int compare(Integer i,Integer j){
                return i>j?-1:i<j?1:0;//return j.compareTo(i); 采用Integer.compareTo方法也可以。
            }
        });

        Arrays.sort(a,(Integer i,Integer j)->{//Lamda表达式
                return i>j?-1:i<j?1:0;//return j.compareTo(i); 采用Integer.compareTo方法也可以。
            }
        );
        System.out.println(Arrays.toString(a));
    }

      toString 方法源码:

    public static String toString(int[] a) {
        if (a == null)
            return "null";
        int iMax = a.length - 1;
        if (iMax == -1)
            return "[]";

        StringBuilder b = new StringBuilder();
        b.append('[');
        for (int i = 0; ; i++) {
            b.append(a[i]);
            if (i == iMax)
                return b.append(']').toString();
            b.append(", ");
        }
    }

1、数组和集合的转化

      数组转化为集合:采用 Arrays 的静态方法 asList();集合转化为数组:采用 Collection 接口中的 toArray() 方法。 在这里只简单给出示范代码:

        ArrayList<Integer> a=new ArrayList<>(Arrays.asList(1,3,5,7,9));//将数组转化为List,(适合初始化List)。
        
        Object[] aaa=a.toArray();//1,List转化为数组
        Integer[] c=new Integer[a.size()];//2,List转化为数组 (这里不能采用 int[])
        a.toArray(c);

      Java集合大致可分为四种。Set、LIst、Queue和Map,其中 Set 表示无序、不可重复的集合(由于没有顺序,如果还有元素重复的就无法区分了);List 代表有序、可重复的集合(和数组较像,但长度可变);而 Map 代表具有映射关系的集合(键值对中的 key 不能重复);Queue代表用来实现队列的集合。所有集合类均位于 java.util 包下。

      数组元素既可以是基本类型的值,也可以是对象的引用变量值;而集合里只能保存对象的引用变量值,也就是说,不能存放如int、long、float、double等基础类型的数据,但是如果存放一个 int 值,会自动装箱为 Integer。

      Java 集合类主要有两个接口派生而出:Collection 和 Map,它俩是 Java 集合框架的根接口,这两个接口又包含了一些子接口或实现类。

      所以示例基于 Java 8。

一、Collection 和 Map 接口

      1,Collection 派生出的三个子接口:Set、List 和 Queue

      Set 是 EnumSet、SortedSet 和 HashSet 的父类。SortedSet 是 TreeSet 的父类;HashSet 是 LinkedHashSet 的父类。

      Queue 是 Deque 和 PriorityQueue 的父类。Deque 是 ArrayQueue 的父类。

      List 是 ArrayList 和 Vector 的父类。Vector 是 Stack 的父类。 LinkedList 是 Deque 接口和 List 接口的实现类。

      2,Map 派生了 EnumMap、IdentityHashMap、HashMap、Hashtable、SortedMap 和 WeakHashMap。

      SortedMap 是 TreeMap 的父类。
      LinkedHashMap 是 HashMap 的子类,它是线程不安全的,key、value 允许为 null。
      Properties 是 Hashtable 的子类,它是线程安全的,key、value 不允许为 null。

      其中,加粗斜体表示常用的七个实现类。

1.1、Collection 接口中定义了一些操作集合元素的方法,可用来操作 Set、List 和 Queue 集合。

      例如:
boolean add (Object o):用来向集合中添加一个元素,成功返回 true;
void clear():用来清空集合;
boolean contains(Object o):判断集合中是否包含元素 o;
boolean isEmpty():判断集合是否为空;
Iterator iterator():返回一个迭代器对象,用来遍历集合中的元素;
boolean remove(Object o):删除集合中的元素 o ,如果集合中有多个 o ,则只会删除第一个符合条件的元素,成功返回 true;
int size():返回集合里元素的个数;
Object[] toArray():将集合转换为一个数组,所有集合元素变为对应的数组元素;
boolean containsAll(Collection c):判断当前集合是否可以包含集合 c 中的全部元素;
boolean removeAll(Collection c):相当于当前集合减去集合 c 的结果,如果存在元素被删除,返回 true;
boolean retainAll(Collection c):相当于当前集合与集合 c 取交集的结果 ,如果当前集合发生变化,返回 true;

      使用 System.out.println 可以直接打印出集合中所有元素。因为所有 Collection 实现类都重写了 toString 方法。

1.2、常用遍历集合中元素的方法为:Iterator 和 forEach

      1,Iterator 仅用于遍历集合,它本身不提供盛装对象的能力,如果想要创建 Iterator 对象,则必须有一个被迭代的集合。没有集合的 Iterator 如若无根之木,没有存在的价值。

      Iterator 接口定义了 4 个方法:

boolean hasNext():如果被迭代的集合元素没有被遍历完,则返回 true。
Object next():返回集合中的下一个元素。
void remove():删除集合里上一次 next 方法返回的元素。
void forEachRemaining(Consumer action):(Java 8)采用 Lambda 表达式来遍历集合元素

        HashSet books=new HashSet();
        books.add("abc");
        books.add("def");
        books.add("hahahaha");
        books.add("opq");
        Iterator a=books.iterator();

        while(a.hasNext())
        {
            String tmp=(String)a.next();//a.next()返回的是集合 a 中元素的值,并不是元素本身。
            System.out.println(tmp);
            if(tmp.equals("def"))
                a.remove();//删除集合 a 中的元素 ”def"
            tmp="newValue";//因为 a.next() 返回的并不是元素本事,所以在对 tmp 赋值不会影响到原来集合。
            //不能在此改变集合(Iterator 接口的 remove()除外)
        }
        System.out.println("遍历结束");
        System.out.println(books);

      在迭代遍历时,只能通过 Iterator 接口的 remove() 来改变原来集合。(如果在 while 循环中,对集合采用 Collection 的 remove() 方法来删除集合元素,会引发异常。)

      2,foreach 遍历集合时与 Iterator 接口类似,foreach 中的迭代变量也不是集合元素本身,系统只是依次把集合元素的值赋给迭代变量,因此在foreach循环中修改迭代变量也没有实际意义。

      在 foreach 循环遍历中,任何改变该集合的行为都会触发异常。

        for(Object obj:books)
        {
            String tmp=(String)obj;
            System.out.println(tmp);
            tmp="newValue";
            //不能在此改变集合
        }
        System.out.println(books);

二、Set集合

      Set 集合不允许包含重复元素,它没有提供额外的方法。如果试图将两个重复的元素加入同一个 Set 集合中,add() 方法会返回 false ,且新元素不会被加入。

2.1、HashSet类

      HashSet 的特点:

1,不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
2,HashSet 不是同步的,如果多个线程同时访问一个 HashSet ,且有两个或者两个以上线程同时修改了 HashSet 集合,则必须通过代码来保证其同步。
3,集合元素值可以为 null。

      在 HashSet 集合中存入一个元素时,HashSet会调用对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据该 hashCode 值决定该对象在 HashSet 集合中的存储位置。如果在该 hashCode 处已经存在了元素的话,就会用 equals() 方法来比较两个元素是否相等,如果相等,add() 方法就会返回 false,新元素添加失败。

      HashSet 判断两个元素是否相等是通过两个对象的 equals() 方法以及 hashCode() 方法,只有这两个方法都返回 true,才会认为两个元素相等。

      a,如果有两个元素通过了 equals() 方法比较返回 true,但它们的 hashCode() 方法返回值并不相等,HashSet 将会根据它们的 hashCode 值把它们存储在不同的位置,依然可以添加成功(但是这就与 Set 集合的规则冲突了)。

      b,如果两个对象的 hashCode() 返回的 hashCode 值相同,但是它们通过 equals() 方法比较返回 false 时更麻烦。由于 hashCode 值相同,所以 HashSet 会试图将它们保存在同一个位置,但是在该位置已经有一个元素了,因此会在该位置以链式结构来保存这样的多个元素。这样就会导致 HashSet 在定位元素时性能下降。

      所以:如果两个对象通过 equals() 方法返回 true 时,那么这两个对象的 hashCode() 也应该相同,这样才符合 HashSet 的规则。并且:当我们将一个类的多个对象保存到 HashSet 集合中时,需要重写这个类的 equals() 和 hashCode() 方法,应该尽量保证任意两个对象通过 equals() 方法比较返回 true 时,它们的 hashCode() 方法返回值也应该相等。

      方法:将对象中用作 equals()方法比较标准的实例变量,都应该用于计算 hashCode() 的值。
      重写 hashCode()方法的一般步骤如下(针对于用作 equals() 方法比较标准的示例变量):

示例变量类型计算方式示例变量类型计算方式
booleanhashCode=(varible?1:0)floathashCode=Float.floatToIntBits(varible)
byte、short、char、inthashCode=(int)varibledoublelong l=Double.doubleToLongBits(varible) hashCode =(int)(l^(l>>>32))
longhashCode=(int)(varible^(varible>>>32))引用类型hashCode=varible.hashCode()

      然后,根据上表得到的多个 hashCode 值组合计算一个 hashCode 值返回。
      例如一个类中含有两个实例变量:int a;String b; 虽然可以采用直接相加 return (int) a + b.hashCode();但是会有极小概率导致实例变量的不同的两个对象的 hashCode 值相等。
      所以一般可以为每一个实例变量采用一个质数因子与它们相乘之后再相加。如:return (int) a*7 + b.hashCode()*13

      虽然采用了更为谨慎的方法来重写 hashCode() 方法,但是最好在将一个可变对象加入到 HashSet 中之后,不要再去修改这个集合元素参与 equals() 和 hashCode() 的实例变量,否则可能会发生混乱。因为修改了实例变量的值之后有可能导致 hashCode 值相同的。

      hash 算法的功能是,它能保证快速查找被检索的对象,其价值在于速度。数组的查找是通过下标,而 hash 算法是根据计算出来的 hash 值来查找目标的,也就比数组多了计算 hash 值花费的时间。数组的索引是连续的(内存中连续),且其长度固定。而 HashSet 是不连续的,并且自由增加 HashSet 的长度。

      从名称中也可以看出,HashSet 内部是采用 hash 算法来决定元素的存储位置。

2.1.1、LinkedHashSet类

      LinkedHashSet 类是 HashSet 的子类。它也是根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表来维护次序,这样使得元素看起来是以插入的顺序保存的。也就是说,当遍历 LinkedHashSet 集合中的元素时,LInkedHashSet 会按元素的添加顺序来访问集合中的元素。

      因为 LinkedHashSet 需要维护元素的插入顺序,所以它的性能略低于 HashSet,但是在迭代访问 Set 里的全部元素时将会有很好的性能,因为它用链表来维护内部顺序。

      LinkedHashSet 依然不允许元素重复。

2.2、TreeSet类

      TreeSet 是 SortedSet 接口的实现类,它可以确保集合元素处于排序状态。它提供的额外方法:
Comparator comparator():如果 TreeSet 采用了定制排序,则该方法返回定制排序所使用的的 Comparator;如果 TreeSet 采用了自然排序,则返回 null。
Object first():返回集合中的第一个元素。
Object last():返回集合中的最后一个元素。
Object lower(Object e):返回集合中位于指定元素之前的元素,e 不需要是 TreeSet 集合中的元素。
Object higher(Object e):返回集合中位于指定元素之后的元素,e 不需要是 TreeSet 集合中的元素。
SortedSet subSet(Object fromElement,Object toElement):返回此 Set 的子集合,范围:[ fromElement,toElement )
SortedSet headSet(Object toElement):返回此 Set 的子集,由小于 toElement 的元素组成。
SortedSet tailSet(Object fromElement):返回此 Set 的子集,由大于或等于 fromElement 的元素组成。

    public static void main(String[] args)
    {
        TreeSet a=new TreeSet<>();
        a.add(0);
        a.add(-2);
        a.add(9);
        a.add(5);
        System.out.println(a);
        System.out.println(a.first());
        System.out.println(a.last());
        System.out.println(a.lower(7));
        System.out.println(a.higher(1));
        System.out.println(a.subSet(-1,3));
    }

      可以看出 TreeSet 是按元素的实际值大小来排序的。TreeSet 采用红黑树来存储集合元素。TreeSet 支持两种排序方法:自然排序和定制排序。在默认情况下,TreeSet 采用自然排序。

2.2.1、自然排序

      自然排序:TreeSet 会调用集合元素的 compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列。 Java 提供了一个 Comparable 接口,该接口里定义了一个 compareTo(Object obj)方法,该方法返回一个整数值,实现该接口的类必须实现该方法,实现了该接口的类的对象就可以比较大小。当一个对象调用该方法的与另一个对象比较时,如:obj1.compareTo(obj2),如果该方法返回0,则表明这两个对象相等;如果该方法返回一个正整数,表明 obj1 大于 obj2,返回一个负整数,表示 obj1 小于 obj2。

      Java 的一些常用类已经实现了 Comparable 接口,并提供了比较大小的标准。如:

1,BigDeciaml、BigInteger 以及所以的数值型的包装类;按照它们对应的数值大小来比较。
2,Character:按字符的 Unicode 值进行比较。
3,Boolean:true 对应的包装类实例大于 false。
4,String:依次比较字符串中每个字符的 Unicode 值。
5,Date、Time:后面的时间、日期比前面的时间、日期大。

      如果一个类没有实现 Comparable 接口,那么将该类的实例对象加入 TreeSet 中会引发异常。一般来讲:TreeSet 只能添加同一种类型的对象,因为不同类型的对象的 compareTo 方法没法来比较(除非自定义强制类型转换)

      当把一个对象加入 TreeSet 集合中时,TreeSet 调用该对象的 compareTo(Object obj) 方法与容器中的其他对象比较大小,然后根据红黑树结构找到它的存储位置。如果两个对象通过compareTo(Object obj) 方法比较结果相等(即返回 0 ),新对象将无法添加到 TreeSet 集合中。

      注意:当把一个对象放入 TreeSet 中,重写该对象对应类的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果;即当 equals() 方法返回 true 时,compareTo(Object obj) 方法应该返回 0。      如果两个对象通过 compareTo(Object obj) 方法比较返回 0,但是它们的 equals() 方法比较却不相等。那么这两个对象不会被一起添加到 TreeSet 中。这会与 Set 不允许有重复元素的规则冲突。      并且如果修改了 TreeSet 中元素的实例变量,这将与其他对象的大小顺序发生了改变,但是 TreeSet 不会再次调整它们的顺序,并且调整了之后可能会导致两个对象相等(即compareTo(Object obj) 方法比较返回 0 ),这与 Set 不允许有重复元素的规则冲突。

class R implements Comparable
{
    int count;
    public R(int count)
    {
        this.count=count;
    }
    public String toString()
    {
        return "R[count:"+count+"]";
    }
    public boolean equals(Object obj)
    {
        if(this==obj)
            return true;
        else if(obj!=null&&obj.getClass()==R.class)
        {
            if(this.count==((R) obj).count)
                return true;
            else
                return false;
        }
        else
            return false;
    }
    public int compareTo(Object obj)
    {
        R r=(R)obj;
        return this.count>r.count?1:this.count<r.count?-1:0;
    }
}
public class HelloWorld {
    public static void main(String[] args)
    {
        TreeSet a=new TreeSet<>();
        a.add(new R(5));
        a.add(new R(-3));
        a.add(new R(9));
        a.add(new R(-2));

        System.out.println(a);
        
        R first=(R)a.first();
        first.count=20;
        R last=(R)a.last();
        last.count=-2;
        System.out.println(a);
        
        System.out.println(a.remove(new R(-2)));//删除失败
        System.out.println(a);
        System.out.println(a.remove(new R(5)));//删除成功
        System.out.println(a);
    }
}

      所以:最好不要修改放入 HashSet 和 TreeSet 集合中元素的实例变量(因为这些变量通常都用来比较)

2.2.2、定制排序

      因为 TreeSet 的自然排序也是默认排序是升序排列的,如果要实现降序排列,这可以通过 Comparator 接口中的 int compare(T o1,T o2)方法,该方法用于比较 o1 和 o2 的大小。如果该方法返回正整数,表明 o1 大于 o2;返回 0 ,表明 o1 等于 o2;返回负整数,表明 o1 小于 o2。

      实现:在创建一个 TreeSet 集合对象时,提供一个 Compatator 对象与其相关联,由该 Comparator 对象负责集合元素的排列逻辑。由于 Comparator 是一个函数式接口,因此可使用 Lambda 表达式来代替 Comparator 对象。

class R
{
    int count;
    public R(int count)
    {
        this.count=count;
    }
    public String toString()
    {
        return "R[count:"+count+"]";
    }
}
public class HelloWorld {
    public static void main(String[] args)
    {
        TreeSet a=new TreeSet((o1,o2)->
        {
            R a1=(R)o1;
            R a2=(R)o2;
            return a1.count>a2.count?1:a1.count<a2.count?-1:0;
        });

        a.add(new R(5));
        a.add(new R(-3));
        a.add(new R(9));
        a.add(new R(-2));
        System.out.println(a);
    }
}

      对于包装类实现逆序的方法如下:

		TreeSet<Integer> a=new TreeSet<>((o1, o2)->
        {
            return o2-o1; //实现 Comparator接口中 compare 函数   自己来实现,这是通用的实现方法!!!
            
            //取巧:
            //return o2.compareTo(o1);  //也可以采用包装类中的 compareTo 来实现。
            //return Integer.compare(o2,o1);  //采用包装类中的已经实现的 compare 静态方法。
        });

2.2、EnumSet类

      EnumSet 是一个专为枚举类设计的集合类,其中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建 EnumSet 时显式或隐式指定。EnumSet 中的集合元素都是有序的,它以枚举值在 Enum 类中的定义顺序来决定集合元素的顺序。

      EnumSet 在内部以位向量的形式存储,故 EnumSet 对象占用内存很小,而且运行效率很好,尤其是进行批量操作(containsAll()、retainAll() 方法调用)时。

      EnumSet 集合不允许加入 null 元素,但是如果想判断 EnumSet 中是否包含 null 元素或试图删除 null 元素都不会抛出异常,只是删除操作将会返回 false,因为 EnumSet 中本来就不存在 null 元素。

      EnumSet 类没有暴露构造器来创建类对象,只能通过它提供的类方法来创建 EnumSet 对象。这些类方法如下:

      EnumSet allOf(Class elementType):创建一个包含指定枚举类里所有枚举值的 EnumSet 集合。
      EnumSet complementOf(EnumSet s):创建一个元素类型与指定 EnumSet 里元素类型相同的 EnumSet 集合,新的 EnumSet 集合包含原 EnumSet 集合所不包含的、此枚举类剩下的枚举值。 新 EnumSet + s = 枚举类。
      EnumSet copyOf(Collection c):使用一个普通集合来创建 EnumSet 集合。
      EnumSet copyOf(EnumSet s):创建一个与指定 EnumSet 具有相同类型、相同集合元素的 EnumSet 集合。
      EnumSet noneOf(Class elementType):创建一个元素类型与指定枚举类型的空 EnumSet。
      EnumSet of(E first,E… rest):创建一个包含一个或多个枚举值的 EnumSet 集合,传入的多个枚举值必须属于同一个枚举类。
      EnumSet range(E from,E to):创建一个包含从 from 枚举值到 to 枚举值内所有枚举值的 EnumSet 集合。

enum Season{
    SPRING,SUMMER,FALL,WINTER
}
public class HelloWorld {
    public static void main(String[] args)
    {
        EnumSet a=EnumSet.allOf(Season.class);
        EnumSet b=EnumSet.noneOf(Season.class);
        System.out.println(a);
        System.out.println(b);

        b.add(Season.SPRING);
        b.add(Season.WINTER);
        b.add(Season.SUMMER);
        System.out.println(b);

        EnumSet c =EnumSet.of(Season.FALL,Season.SPRING);
        EnumSet d=EnumSet.range(Season.SUMMER,Season.WINTER);
        System.out.println(c);
        System.out.println(d);

        EnumSet e=EnumSet.complementOf(d);
        System.out.println(e);
        
        HashSet f=new HashSet();
        f.clear();
        f.add(Season.FALL);
        f.add(Season.SPRING);
        EnumSet enumSet=EnumSet.copyOf(f);//注意:此Collection集合中元素必须都是同一个枚举类的枚举值
        System.out.println(enumSet);
    }
}

2.3、Set实现类总结

      HashSet 比 TreeSet 的性能要好(特别是最常用的添加、查询元素等操作),因为 TreeSet 需要额外的红黑树来维护集合的次序。只有当需要一个保持排序的 Set 时,才应该使用 TreeSet。

      LInkedHashSet 对于普通的插入、删除操作,比 HashSet 要慢一点,这是由于维护链表所带来的的额外开销造成的,但相应的,它的遍历操作会更快。

      EnumSet 是所有 Set 实现类中性能最好的,但是它只能保存同一个枚举类的枚举值作为集合元素。

      HashSet、TreeSet 和 EnumSet 都是线程不安全的,如果有多个线程同时访问一个 Set 集合,并且有超过一个线程修改了该 Set 集合,需要手动保证该 Set 集合的同步性。

三、List集合

      List 集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。默认按照元素的添加顺序设置元素的索引,如第一次添加的元素索引为 0,第二次添加的元素索引为 1…

      List 子接口在 Collection 接口之上新增的方法:

      void add(int index,Object element):将元素 element 插入到 List 集合的 index 处。
      boolean addAll(int index,Collection c):将集合 c 所包含的所有元素都插入到 List 集合的 index 处。
      Object get(int index):返回集合 index 索引处的元素。
      int indexOf(Object o):返回对象 o 在 List 集合中第一次出现的下标。
      int lastIndexOf(Object o):返回对象 o 在 List 集合中最后一次出现的下标。
      Object remove(int index):删除并返回 index 索引处的元素。
      List subList(int fromIndex,int toIndex):返回 [fromIndex, toIndex) 处的子集合。

    public static void main(String[] args)
    {
        ArrayList a=new ArrayList();
        a.add("abc");
        a.add("efg");
        a.add("hijklmn");
        System.out.println(a);

        a.add(1,"d");
        System.out.println(a);
        for(int i=0;i<a.size();i++) //因为List是根据位置索引来访问集合中的元素的,所以可以使用普通for循环来遍历。
            System.out.println(a.get(i));

        a.remove(2);
        System.out.println(a);

        System.out.println(a.indexOf("hijklmn"));
        a.set(0,"a");
        System.out.println(a);
        System.out.println(a.subList(0,2));
    }

      List 集合在查找一个对象在集合中的下标时,是通过 equals() 方法来比较,见下面两段代码:

        ArrayList a=new ArrayList<String>();
        a.add("abc");
        a.add(new String("abc"));
        String b=new String("abc");
        System.out.println(a.get(0)==a.get(1));  //false
        System.out.println(a.get(1)==b);    //false
        System.out.println(a.indexOf(b));   // 0
        System.out.println(a.lastIndexOf(b));  //1
class Tmp{
    public boolean equals(Object obj)
    {
        return true;
    }
}
public class HelloWorld {
    public static void main(String[] args)
    {
        ArrayList a=new ArrayList<String>();
        a.add("abc");
        a.add("def");
        a.add("g");
        System.out.println(a);
        //在删除一个Tmp对象时,List集合会调用该对象的equals()方法依次与集合元素进行比较,
        // 如果该equals()方法以某个集合元素作为参数时返回true,则删除该集合元素。
        a.remove(new Tmp());
        
        System.out.println(a);
        
        a.remove(new Tmp());
        System.out.println(a);
    }
}

      List 集合有一个额外的 listIterator()方法,该方法返回一个 ListIterator 对象,ListIterator 接口继承了 Iterator 接口,提供了专门操作 List 的方法。ListIterator 接口在 Iterator 基础上增加了如下方法:

      boolean hasPrevious():返回该迭代器关联的集合是否还有上一个元素。
      Object previous():返回该迭代器的上一个元素。
      void add (Object o):在当前元素之后插入一个元素 o 。
      void set (Object o):设置当前元素值为 o 。

      这些增加的方法为 List 增加了向前迭代的功能(Iterator 只能向后迭代),并且可以通过 add() 方法向 List 集合中添加元素(Iterator 只能删除元素)。

    public static void main(String[] args)
    {
        ArrayList a=new ArrayList<String>();
        String[] tmp={"abc","def","g","hijklnm"};
        for(int i=0;i<tmp.length;i++)
        {
            a.add(tmp[i]);
        }
        System.out.println(a);

        ListIterator listIter=a.listIterator();
        while(listIter.hasNext())
        {
            System.out.println(listIter.next());
            listIter.add("---分隔符---");
        }
        System.out.println(a);
        while(listIter.hasPrevious())
        {
            System.out.println(listIter.previous());
        }
    }

      如果直接对新的迭代器对象 listIter 进行向前遍历,没有输出,因为此时 listIter 之前没有元素,需要向后迭代之后才能向前迭代。

3.1、ArrayList和Vector实现类

      ArrayList 和 Vector 是 List 类的两个典型实现,它们都是基于数组实现的 List 类,所以 ArrayList 和 Vector 类封装了一个动态的、允许在分配的 Object[] 数组。ArrayList 或 Vector 对象使用 initialCapacity 参数来设置该数组的长度,当向 ArrayList 或 Vector 中添加元素超出了该数组的长度时,它们的 initialCapacity 会自动增加。

      如果需要向 ArrayList 或 Vector 中添加大量元素时,可以使用 ensureCapacity(int minCapacity) 方法一次性的增加 initialCapacity ,提高性能。

      如果想创建一个固定长度的 ArrayList 或 Vector,可以在创建时直接指定 initialCapacity 的大小。创建一个空的 ArrayList 或 Vector 时,默认的 initialCapacity 为10。

        ArrayList a=new ArrayList<String>(4);// initialCapacity 为4.
        ArrayList aa=new ArrayList<String>();// initialCapacity 为10.

      void ensureCapacity(int minCapacity):将 ArrayList 或 Vector 集合的 Object[] 数组长度增加为大于或等于 minCapacity 的值。
      void trimToSize():调整 ArrayList 或 Vector 集合的 Object[] 数组长度为当前元素的个数(等于 size() 的返回值),从而减少这两个集合对象占用的存储空间。

      ArrayList 是线程不安全的。Vector 是线程安全的,所以其性能比 ArrayList 要低。一般不推荐使用 Vector 和它的子类 Stack,因为它们比较古老。

3.2、固定长度的List

      操作数组的工具类:Arrays,该工具类里提供了 asList(Object… a)方法,用来把一个数组或指定个数的对象转换成为一个 List 集合,这个 LIst 集合不是 ArrayList 和 Vector 实现类的实例,而是 Arrays 的内部类 ArrayList 的示例。

      Arrays.ArrayList 是一个固定长度的 List 集合,程序只能遍历访问该集合中的元素,不能增加、删除该集合中的元素。

        List a= Arrays.asList("abc","def","g");
        System.out.println(a.getClass());// class java.util.Arrays$ArrayList
        a.forEach(System.out::println);
        a.add("kjlkj");//java.lang.UnsupportedOperationException
        a.remove(0);//java.lang.UnsupportedOperationException

四、Queue集合

      Queue 用来模拟队列,队列是一种先进先出的容器。元素从队尾进,从队头出,通常队列不允许随机访问其中的元素。Queue 接口中定义的方法:

      void add(Object o):将指定元素加入此队列的尾部。
      boolean offer(Object e):将指定元素加入此队列的尾部。当使用容量有限的队列时,此方法通常要比 add() 方法更好。
      Object element();获取队列头部的元素,但是不删除该元素。
      Object remove();获取队列头部的元素,并删除该元素。
      Object peek():获取队列头部的元素,但是不删除该元素。若队列为空,则返回 null。
      Object poll():获取队列头部的元素,并删除该元素。若队列为空,返回 null。

4.1、PriorityQueue实现类

      PriorityQueue 是一个比较标准的队列实现类,它保存队列元素的顺序并不是按照加入队列的顺序,而是按队列元素的大小重新排序。因此当调用 peek() 方法或 poll() 方法取出队列中的元素时,并不是取出最先进入队列中元素,而是取出队列中最小的元素。 也就是说,队头是最小的元素 ,队尾是最大的元素。(但是有时候打印 PriorityQueue 对象,会看到元素并没有按照大小进行排序,这是因为受到 toString() 方法的影响)

      PriorityuQueue 不允许插入 null 元素,它还需要对队列元素进行排序,这里也依然有两种排序方式:自然排序,采用自然排序的 PriorityQueue 集合中的元素必须实现了 Comparable 接口,并且元素必须是一个类的多个实例;定制排序,在创建 PriorityQueue 对象时,传入一个 Comparator 对象,由该对象来负责实现队列中的元素排序。PriorityQueue 的排序和 TreeSet 的要求基本一致。

4.2、Deque接口和ArrayDeque实现类

      1,Deque 接口是 Queue 接口的子接口,它代表了一个双端队列,Deque 定义了一些双端队列的方法:

      void addFirst(Object e):将指定元素插在该双端队列的开头。
      void addLast(Object e):将指定元素插入在该双端队列的末尾。
      Iterator descendingIterator():返回该双端队列的迭代器,该迭代器将以逆向顺序来迭代队列中的元素。
      boolean offerFirst(Object e):将指定元素插在该双端队列的开头。
      boolean offerLast(Object e):将指定元素插在该双端队列的末尾。
      Object getFirst():获取但不删除双端队列的第一个元素。队列为空时,引发异常。
      Object getLast():获取但不删除双端队列的最后一个元素。队列为空时,引发异常。
      Object removeFirst():获取并删除双端队列的第一个元素。队列为空时,引发异常。
      Object removetLast():获取并删除双端队列的最后一个元素。队列为空时,引发异常。
      Object peekFirst():获取但不删除双端队列的第一个元素。队列为空时,返回 null。
      Object peekLast():获取但不删除双端队列的最后一个元素。队列为空时,返回 null。
      Object pollFirst():获取并删除双端队列的第一个元素。队列为空时,返回 null。
      Object pollLast():获取并删除双端队列的最后一个元素。队列为空时,返回 null。
      Object pop():栈方法,pop 出该双端队列所表示的栈的栈顶元素。队列为空时,引发异常。 栈顶元素是Deque 的第一个元素。所以 pop 和 removeFirst()、pollFirst() 类似。
      void push(Object e):栈方法,将一个元素push 进该双端队列所表示的栈的栈顶。push 和 addFirst()、offerFirst() 类似。
      Object removeFirstOccurrence(Object e):删除该双端队列的第一次出现的元素 e 。
      Object removeLastOccurrence(Object e):删除该双端队列的最后一次出现的元素 e 。

      2,ArrayDeque 实现类,它是一个基于数组实现的双端队列,类似于 ArrayList,在创建时可以指定一个 numElement 参数,用来指定 Object[ ] 数组的长度,默认长度为 16。

      如果对一个用 ArrayDeque 表示的栈,只想访问栈顶元素,可采用:peak()、peekFirst()、getFirst() 方法。栈顶元素是 Deque 的第一个元素,也是 Queue 的头部元素。

      用 ArrayDeque 表示栈和队列的示例见下面代码:

 public static void main(String[] args)
    {
        ArrayDeque stack=new ArrayDeque();
        stack.push("abc");
        stack.push("def");
        stack.push("g");
        System.out.println(stack);
        System.out.println(stack.peek());//即栈顶是队列头部。
        System.out.println(stack.peekFirst());
        System.out.println(stack.pop());
        System.out.println(stack.poll());
        System.out.println(stack);

        ArrayDeque queue=new ArrayDeque();
        queue.offer("啊啊");
        queue.offer("哈哈");
        queue.offer("哦哦");
        System.out.println(queue.peek());
        System.out.println(queue.poll());
        System.out.println(queue);
    }

4.3、LinkedList实现类

      LinkedList 是 List 接口和 Deque 接口的实现类,这意味着它是一个 List 集合,可以根据索引来随机访问集合中的元素。还可以被当成 Deque 来使用(包括 栈和队列)。它是一个功能十分强大的集合类。

      LinkedList 内部以双链表的形式来保存集合中的元素。

    public static void main(String[] args)
    {
        LinkedList a=new LinkedList();
        a.offer("abc"); //队尾插入
        a.push("def");  //相当于 队头插入
        a.offerFirst("g"); //队头插入
        for(int i=0;i<a.size();i++)
            System.out.println("遍历中:" + a.get(i));

        System.out.println(a.peekFirst());
        System.out.println(a.peekLast());
        System.out.println(a.pop());
        System.out.println(a);
        System.out.println(a.pollLast());
        System.out.println(a);
    }

4.5、线性表性能分析

      List 是一个线性表接口,而ArrayList、LinkedList 是线性表的两种典型实现:基于数组和基于链表。Queue 代表了队列,Deque 代表了双端队列(包括栈和队列)。

      数组的随机访问性能最好,链表在插入、删除操作时性能较好。但总体上,ArrayList 比 LinkedList 性能要好。

      1,如果需要遍历 List 集合,对于 ArrayList 集合,应该采用随机访问方法(get() )来遍历;对于 LinkedList 集合,应该采用迭代器(iterator() )来遍历。
      2,如果需要经常执行插入、删除操作来改变 List 集合的大小,可以考虑使用 LinkedList 。

五、Map集合

      Map 用来保存具有映射关系的数据,所以 Map 集合中保存着一组值 key,另一组值 value。key 和 value 都可以是任何应用类型的数据。其中 key 不允许重复,即任何两个 key 通过 equals() 方法总是返回 false。

      key 和 value 之间是一一映射关系。给定一个 key ,就可以取出对应的 value。

      Map 中的所有 key 集合放在一起就组成了 Set 集合(所有的 key 没有顺序,key 与 key 之间不能重复),而 Map 中存在一个方法 keySet() 方法,用来返回 Map 中所有 key 组成的 Set 集合。

      而 Map 的子类和 Set 的子类在名称上很是相似。比如在 Set 接口下有:HashSet、LinkedHashSet、SortedSet、TreeSet、EnumSet 等子接口和实现类;而在 Map 接口下有:HashMap、LinkedHashMap、SortedMap、TreeMap、EnumMap 等子接口和实现类。Map 的这些子类中 key 集的存储方式和对应 Set 集合中元素的存储形式完全相同。(事实上,Map 提供了 Entry 内部类来封装 key-value 对,而在计算 Entry 存储时只需考虑 Entry 封装的 key。在 Java 源码中,Java 先是实现了 Map,然后通过包装一个所有 value 都为空对象的 Map 就实现了 Set 集合。)

      Map 中的所有 value 放在一起来看,它们非常类似于一个 List(元素和元素之间可以重复),每个元素都可以通过索引来查找和取出元素(List 采用下标,而 Map 采用另一个对象 - key)。

      Map 接口中的常用方法:

      void clear():删除该 Map 对象中的所有 key-value 对。
      boolean containsKey(Object key):查询 Map 中是否包含指定的 key,如果包含则返回 true。
      boolean containsValue(Object value):查询 Map 中是否包含一个或多个的该 value,如果包含则返回 true。
      Set entrySet():返回 Map 中包含的 key-value 对所组成的 Set 集合,每个集合元素都是 Map.Entry 对象。Entry 是 Map 的内部类。
      boolean isEmpty():判断该 Map 是否为空,即不包含任何的 key-value 对,为空返回 true。
      Set keySet():返回该 Map 中所有 key 组成的 Set 集合。
      Object get(Object key):返回该 Map 中 key 对应的 value,若此 Map 中不含有该 key ,则返回 null。
      Object put(Object key,Object value):添加一个 key-value 对,成功返回 null ;如果当前 Map 中有一个与该 key 相等的 key-value 对,那么新的 key-value 对会覆盖旧的,并且返回旧的value 值。
      void putAll(Map m):将 m 中的 key-value 对复制到本 Map 中。
      Object remove(Object key):删除指定 key 所对应的 key-value 对,返回被删除 key 所关联的 value,如果该 key 不存在,则返回 null。
      boolean remove(Object key,Object value):Java 8 新增,删除由 key、value 所对应的 key-value 对。成功删除返回 true,否则返回 false。
      int size():返回该 Map 中的 key-value 对的个数。
      Collection values():返回该 Map 中所有 value 组成的 Collection。

      Map 中的内部类 Entry,该类封装了一个 key-value 对。Entry 包含了如下三个方法:

      Object getKey():返回该 Entry 中包含的 key 值。
      Ojbect getValue():返回该 Entry 中包含的 value 值。
      Object setValue(V value):设置该 Entry 中包含的 value 值,并返回新设置的 value 值。

    public static void main(String[] args)
    {
        HashMap a=new HashMap();
        a.put("abc",1);
        a.put("def",2);
        a.put("g",3);
        a.put("hijk",2);
        System.out.println(a);
        a.put("g",9);
        System.out.println(a);
        System.out.println(a.put("kkj",0));
        System.out.println(a);
        System.out.println(a.containsKey("abc"));
        System.out.println(a.containsValue(0));
        for(Object tmp:a.keySet())
        {
            System.out.println((String)tmp + "-->" + a.get((String)tmp));
        }
        a.remove("abc");
        Iterator tmp=a.keySet().iterator();
        while(tmp.hasNext())
        {
            String t=(String)tmp.next();
            System.out.println(t +" " +a.get(t));
        }
    }

5.1、HashMap和Hashtable实现类

      HashMap 和 Hashtable 都是 Map 的典型实现类,它们之间的关系完全类似于 ArrayList 和 Vector : Hashtable 是一个古老的 Map 实现类,它是线程安全的,它不允许使用 null 作为 key 或者 value;而 HashMap 是线程不安全的,它可以使用 null 作为 key 或者 value。

      现在一般很少用 Hashtable,如果需要线程安全的 Map 实现类,可以同过 Collections 工具类将 HashMap 变为线程安全的。

      对应着 HashSet,在 HashMap、Hashtaable 中存储、获取对象,key 对象的类必须实现 hashCode() 和 equals() 方法。和 HashSet 一样,HashMap、Hashtable 不能保证其中的 key-value 对的顺序。判断两个 key 相等的标准是:两个 key 通过 equals() 方法比较返回 true,两个 key 的 hashCode() 方法也相等(所以如果重写一个作为 key 的类的 equals() 和 hashCode() 时,应该保证这两个方法的判断结果一致;且如果采用可变对象作为 key,那么尽量不要修改该可变对象。)。判断两个 value 相等的标准是:两个 value 通过 equals() 方法比较返回 true。

class A{
    int count;
    public A(int count){
        this.count=count;
    }
    public boolean equals(Object obj)
    {
        if(obj==this)
            return true;
        if(obj!=null&&A.class==obj.getClass())
        {
            A tmp=(A)obj;
            return count==tmp.count;
        }
        else
            return false;
    }
    public int hashCode(){
        return count;
    }
}
class B
{
    String a;
    public B(String b){
        a=b;
    }
    public boolean equals(Object obj) {
        return true;
    }
}
public class HelloWorld {
    public static void main(String[] args) {
        HashMap a = new HashMap();
        a.put(new A(1), "abc");
        a.put(new A(2), "def");
        a.put(new A(3), "g");
        a.put(new A(4),new B("a"));
        System.out.println(a);

        System.out.println(a.containsKey(new A(3)));// A 实例对象只需要 count 相等即相等。(equals() 和 hashCode())
        System.out.println(a.containsValue(new B("dsaf")));// B 的实例对象总是相等的。
        a.remove(new A(2));
        System.out.println(a);
    }
}

5.1.1、LinkedHashMap实现类

      LinkedHashMap 作为 HashMap 的子类,它使用双向链表来维护 key-value 对的顺序(实际上只需要考虑 key 的顺序),用来保证对 Map 的迭代顺序与 key-value 对的插入顺序保持一致。

      LinkedHashMap 由于需要维护元素的插入顺序,它的性能略低于 HashMap,但是在迭代访问 Map 中的元素时将会有更好的性能。

      LinkedHashMap 使用 == 而不是 equals() 来判断元素相等。

    public static void main(String[] args) {
        LinkedHashMap a = new LinkedHashMap();
        a.put(0, "abc");
        a.put(211, "def");
        a.put(23, "g");
        a.put(null,"hijk");
        for(Object obj:a.keySet())
        {
            System.out.println(obj + "-->"+ a.get(obj));
        }
        //a.forEach((key,value)->System.out.println(key+"  "+value));
    }

5.2、SortedMap和TreeMap实现类

      和 Set 接口派生出 SortedSet 接口,SortedSet 接口有一个 TreeSet 实现类一样,Map 接口也派生出 SortedMap 接口,SortedMap 接口也有一个 TreeMap 实现类。

      TreeMap 就是一个红黑树结构,每个 key-value 对作为红黑树的一个节点。TreeMap 存储 key-value 对时,需要根据 key 对节点进行排序。从而依据 key 来保证所有 key-value 对处于有序状态。

      1,自然排序:TreeMap 所有 key 对象的类必须实现 Comparable 接口,而且所有的 key 最好是同一个类的对象。

      2,定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不要求 TreeMap 中的 key 实现 Comparator 接口。

      类似于 TreeSet,TreeMap 中判断两个 key 相等的标准是:两个 key 通过 compareTo() 方法返回 0。如果采用自定义类作为 key 时,应该重写该类的 equals() 方法和 compareTo() 方法,使得它俩的比较结果保持一致。

      TreeMap 中提供了一系列可以根据 key 顺序来访问 key-value 对的方法:

      Map.Entry firstEntry():返回该 Map 中最小 key 所对应的 key-value 对,如果该 Map 为空,返回 null。
      Map.Entry lastEntry():返回该 Map 中最大 key 所对应的 key-value 对,如果该 Map 为空或不存在这样的 key-value 对,返回 null。
      Object firstKey():返回该 Map 中的最小 key 值,如果该 Map 为空,返回 null。
      Object lastKey():返回该 Map 中的最大 key 值,如果该 Map 为空,返回 null。
      Map.Entry higherEntry(Object key):返回该 Map 中位于 key 后一位(大于 key)的 key-value 对,如果该 Map 为空,返回 null。
      Map.Entry lowerEntry(Object key):返回该 Map 中位于 key 前一位(小于 key)的 key-value 对,如果该 Map 为空,返回 null。
      Object higherKey(Object key):返回该 Map 中位于 key 后一位(大于 key)的 key 值,如果该 Map 为空,返回 null。
      Object lowerKey(Object key):返回该 Map 中位于 key 前一位(小于 key)的 key 值,如果该 Map 为空,返回 null。
      SortedMap subMap(Object fromKey,Object toKey):返回该 Map 的子Map,[fromKey,toKey)。
      SortedMap tailMap(Object fromKey):返回该 Map 的子Map, [ fromKey,~)。
      SortedMap headMap(Object toKey):返回该 Map 的子Map,[~,toKey

class A implements Comparable{
    int count;
    public A(int count){
        this.count=count;
    }
    public boolean equals(Object obj)
    {
        if(obj==this)
            return true;
        if(obj!=null&&A.class==obj.getClass())
        {
            A tmp=(A)obj;
            return count==tmp.count;
        }
        else
            return false;
    }
    public String toString()
    {
        return "A: "+count;
    }
    public int compareTo(Object obj)
    {
        A tmp=(A)obj;
        return count>tmp.count?1:count<tmp.count?-1:0;
    }
}
public class HelloWorld {
    public static void main(String[] args) {
        TreeMap a=new TreeMap();
        a.put(new A(-3),"abc");
        a.put(new A(3),"def");
        a.put(new A(-8),"g");
        System.out.println(a);
        System.out.println(a.firstEntry());
        System.out.println(a.lastEntry());
        System.out.println(a.higherKey(new A(0)));
        System.out.println(a.lowerEntry(new A(19)));
        System.out.println(a.subMap(new A(-1),new A(20)));
    }
}

5.3、EnumMap实现类

      EnumMap 是一个与枚举类一起使用的 Map 实现,EnumMap 中的所有 key 都必须是单个枚举类的枚举值。创建 Enummap 时必须显示或隐式指定它对应的枚举类。

      EnumMap 在内部以数组形式保存,所以这种实现形式非常紧凑、高效;EnumMap 根据 key 的自然顺序(枚举值在枚举类中的定义顺序)来维护 key-value 对的顺序。不允许使用 null 作为 key 值。

      创建一个 EnumMap 时必须指定一个枚举类:

enum Char{
    A,B,C,D
}
public class HelloWorld {
    public static void main(String[] args) {
        EnumMap a=new EnumMap(Char.class);
        a.put(Char.A,"abc");
        a.put(Char.B,"bcd");
        a.put(Char.C,"cde");
        a.put(Char.D,"def");
        System.out.println(a);
    }
}

5.4、Map实现类总结

      HashMap 比 TreeMap 的性能要好(特别是最常用的添加、查询元素等操作),因为 TreeMap 需要额外的红黑树来维护集合的次序。只有当需要一个保持排序的 Map 时,才应该使用 TreeMap。当 TreeMap 被填充之后,就可以调用 keySet() 方法,取得由 key 组成的 Set,然后使用 toArray() 方法生成 key 数组,接下来使用 Arrays 的 binarySearch() 方法在已排序的数组中快速查找对象。

      LInkedHashMap 对于普通的插入、删除操作,比 HashMap 要慢一点,这是由于维护链表所带来的的额外开销造成的,但相应的,它的遍历操作会更快。

      EnumMap 是所有 Map 实现类中性能最好的,但是它只能保存同一个枚举类的枚举值作为 key。

      HashMap、TreeMap 和 EnumMap 都是线程不安全的,如果有多个线程同时访问一个 Map 集合,并且有超过一个线程修改了该 Map 集合,需要手动保证该 Map 集合的同步性。

六、HashSet和HashMap的性能

      这两个实现类也包括名称带有 Hash 的实现类,其内部都是采用 hash 算法来实现的,存储方式为 hash 表。这个 hash 表在一旦发生冲突时,会在同一个位置建立一个链表来存储元素。

      HashSet 和 HashSet 的 hash 表属性:

      容量(capacity):hash 表的大小。
      初始化容量(initial capacity):创建 hash 表时的初始大小,HashSet 和 HashSet 都可以在创建时指定初始化容量。
      尺寸(size):当前 hash 表中元素的数量。
      负载因子(load factor):负载因子等于 size/capacity 。负载因子为 0,表示一个空的 hash 表;0.5 表示一个半满的 hash 表。负载因子较低的 hash 表具有冲突少、适宜插入、查询的特点(但是使用 Iterator 迭代元素时比较慢)。

      负载极限: 它是一个介于 0~1 之间的数值,它决定了 hash 表的最大填满程度。当 hash 表的负载因子达到指定的 负载极限 时,hash 表会自动的成倍增加 容量,并将原有对象重新分配,这个过程称为 rehashing。

      HashSet 和 HashSet 默认的负载极限为 0.75。这是在时间和空间上的一种折中。如果在一开始就能确定 HashSet 和 HashSet 存储元素的数量,可以参考负载因子来设置一个合适的初始化容量。

七、Collections工具类

      Collections 工具类提供了大量的方法来对集合(Set、List 和 Map)元素进行排序、查询和修改等操作,还可以将集合对象设置为不可变、对集合对象设置实现同步控制等方法。

7.1、对 List 集合的排序操作

      void reverse(List list):反转指定 List 集合中元素的顺序。
      void shuffle(List list):对 List 结合元素进行随机排序,类似于 洗牌 。
      void sort (List list):根据元素的自然顺序对指定 List 集合按升序进行排序。
      void sort(List list,Comparator c):根据指定 Comparator 产生的顺序对 List 集合元素排序。
      void swap (List list,int i,int j):将 list 集合中 i 处元素和 j 处元素进行交换。
      void rotate(List list,int distance):当 distance 为正数时,将 list 集合的后 distance 个元素“整体”移到前面;当 distance 为负数时,将 list 集合的前 distance 个元素“整体”移到后面。该方法不会改变集合的长度。

    public static void main(String[] args) {
        ArrayList a=new ArrayList();
        a.add(1);
        a.add(-9);
        a.add(0);
        a.add(-4);
        System.out.println(a);

        Collections.sort(a);
        System.out.println(a);

        Collections.reverse(a);
        System.out.println(a);

        Collections.shuffle(a);
        System.out.println(a);

        Collections.swap(a,0,2);
        System.out.println(a);

        Collections.sort(a, (o1,o2) ->{//降序排列
            int b=(int)o1;
            int c=(int)o2;
            return b<c?1:b>c?-1:0;
        });
        System.out.println(a);

        Collections.rotate(a,3);
        System.out.println(a);
    }

7.2、查找、替换操作

      int binarySearch(List list,Object key):使用二分搜索法搜索指定的 List 集合,以获得指定对象在集合的索引。使用该方法前,需要保证 List 集合中的元素已经处于有序状态。
      Object max(Collection coll):根据元素的自然排序,返回给定集合中的最大元素。
      Object max(Collection coll,Comparator comp):根据 comp 指定的顺序,返回给定集合中的最大元素。
      Object min(Collection coll):根据元素的自然排序,返回给定集合中的最小元素。
      Object min(Collection coll,Comparator comp):根据 comp 指定的顺序,返回给定集合中的最小元素。
      void fill(List list,Object obj):使用指定元素 obj 替换 list 中的所有元素。
      int frequency(Collection c,Object o):返回 c 中的 o 出现的次数。
      int indexOfSubList(List source,List target):返回子 List 对象在父 List 对象中第一次出现的位置索引;如果父 List 中没有子 List ,返回 -1。
      int lastindexOfSubList(List source,List target):返回子 List 对象在父 List 对象中最后一次出现的位置索引;如果父 List 中没有子 List ,返回 -1。
      boolean replaceAll(List list,Object oldVal,Object newVal):使用 newVal 替换 list 中的所有 oldVal。

    public static void main(String[] args) {
        ArrayList a=new ArrayList();
        a.add(1);
        a.add(-9);
        a.add(0);
        a.add(-4);
        System.out.println(a);

        System.out.println(Collections.max(a));
        System.out.println(Collections.min(a));
        Collections.replaceAll(a,1,10);
        System.out.println(a);

        System.out.println(Collections.frequency(a,0));
        Collections.sort(a);
        System.out.println(a);
        
        System.out.println(Collections.binarySearch(a,10));
    }

7.3、同步控制

      Collections 类中提供了多个 synchronizedXxx() 方法,用来将指定集合包装成为线程同步的集合。前面介绍的集合如:HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap、TreeMap 都是现成不安全的。

    public static void main(String[] args) {
        Collection a=Collections.synchronizedCollection(new ArrayList());
        List aa=Collections.synchronizedList(new ArrayList());
        Set aaa=Collections.synchronizedSet(new HashSet());
        Map aaaa=Collections.synchronizedMap(new HashMap());

        System.out.println(a.getClass());
        System.out.println(aa.getClass());
        System.out.println(aaa.getClass());
        System.out.println(aaaa.getClass());
    }

      
      
      
      
      
      
      

7.4、设置不可变集合

      1,Collections 提供了下面三类方法来返回一个不可变集合。它们的参数是原有的集合对象,返回值是该集合的“只读”版本。

      emptyXxx():返回一个空的、不可变的集合对象,此处的集合可以是 List、SortedSet、Set、SortedMap、Map 等。
      singletonXxx():返回一个只包含指定对象(只有一个或一项元素)的、不可变的集合对象,此处的集合只能是 Set。
      unmodifiableXxx():返回指定集合对象的不可变视图,此处的集合可以是 List、SortedSet、Set、SortedMap、Map 等。

    public static void main(String[] args) {
        List a=Collections.emptyList();
        Set b=Collections.singleton("abcd");
        HashMap c=new HashMap();
        c.put("abc",1);
        c.put("def",33);
        Map cUnmodefiable=Collections.unmodifiableMap(c);
        cUnmodefiable.put("afa",999); //运行时引发异常
        a.add("dsaf");//运行时引发异常
        b.add("kjjj");//运行时引发异常
    }

      2,Java 9 增加了 of() 方法用来创建不可变集合。可以一次创建包含多个元素的不可变 Set、List、Map。

    public static void main(String[] args) {
        Set a=Set.of("a","b","c","d");
        List b=List.of(1,2,3,4,34);
        Map c=Map.of("K",23,"J",43,"JJ",3);
        Map d=Map.ofEntries(Map.entry("a",1),Map.entry("b",2),Map.entry("c",3));
    }

总结

      上面介绍的都是常用的方法,具体的请查看 API 文档。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值