浅析Java中的Collections

76 阅读5分钟

Collections

java.utils.Collections 是集合工具类,用来对集合进行操作。Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法。

常用方法:

  • public static <T> boolean addAll(Collection<T> c, T...elements): 将所有指定元素添加到指定集合中

    参数列表中的T...elements表示可变参数,当方法的参数数据类型已经确定,但参数的个数不确定就可以使用可变参数。

    • 格式:定义方法时使用

      修饰符 返回值类型 方法名(数据类型... 变量名){
      	// 方法体
      }
      
    • 原理:可变参数的底层是一个数组,根据传递参数的个数不同会创建不同长度的数组来存储这些参数;传递的参数格式可以是0到多个

    可变参数的使用示例:

    import java.util.Arrays;
    
    public class argsMain {
        public static void main(String[] args) {
            int[] array = new int[]{1,2,3};
            System.out.println(add(array));  // 6
    
            int[] array1 = new int[]{1,2,3,4,5,6,7};
            System.out.println(add(array1));  // 28
        }
        public static int add(int... array){
            System.out.println(array); // [I@1b6d3586, 底层是一个数组
            System.out.println(Arrays.toString(array)); // [1, 2, 3]
            int sum = 0;
            for(int ele : array){
                sum += ele;
            }
            return sum;
        }
    }
    

    NOTE:

    • 一个方法的参数列表只能用一个可变参数

    • 如果方法的参数有多个,那么可变参数必须写在参数列表的末尾

    • 特殊写法,它可以接收任意数据类型的数据:

      public static void method(Object... obj){
      	// 方法体
      }
      

    Python中同样有类似的机制:

    • 当在方法的参数列表中声明类似于*args的参数时,从此处开始直到结束的所有位置参数都将被收集到一个成为param元组
    • 当在方法的参数列表中声明类似于**args的参数时,从此处开始直到结束的所有位置参数都将被收集到一个成为param字典
    def method(a, *numbers, **phonebook):
        print('a', a)
        print ('-' * 10)
    
        print (numbers) # (1, 2, 3)
        for i in numbers:
            print(i)
        print ('-' * 10)
    
        print(phonebook)  # {'Jack': 1123, 'John': 2231, 'Inge': 1560}
        for k, v in phonebook.items():
            print(k,v)
        
        # output:
        # a 10
        # ----------
        # 1
        # 2
        # 3
        # ----------
        # Jack 1123
        # John 2231
        # Inge 1560
    
    
    if __name__ == "__main__":
        method(10,1,2,3,Jack=1123,John=2231,Inge=1560)
    
  • public static void reverse(List<?> list): 反转指定集合中元素的顺序

  • public static void shuffle(List list): 将集合中的元素打乱

  • public static int frequency(Collection<?> c,Object o): 返回指定集合中指定元素的出现次数

  • public static void swap(List<?> list,int i,int j): 将指定集合中的 i 处元素和 j 处元素进行交换

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    
    public class CollectionsTest {
        public static void main(String[] args) {
            ArrayList<Integer> list1 = new ArrayList<>();
            ArrayList<String> list2 = new ArrayList<>();
    
            // addAll()
            System.out.println(list1); // []
            Collections.addAll(list1, 1,2,3,4,5);
            System.out.println(list1); // [1, 2, 3, 4, 5]
    
            Collections.addAll(list2, "abc", "ccb", "bde");
            System.out.println(list2);  // [abc, ccb, bde]
    
            // reverse()
            Collections.reverse(list1);
            System.out.println(list1);  // [5, 4, 3, 2, 1]
    
            // shuffle()
            Collections.shuffle(list1);
            System.out.println(list1);  // [1, 4, 2, 3, 5]
    
            // swap()
            Collections.swap(list1, 0, list1.size() - 1);
            System.out.println(list1);  //[1, 4, 3, 2, 5]
    
            // frequency()
            System.out.println(Collections.frequency(list1, 1)); // 1
    
  • public static <T> void sort(List<T> list): 将集合中的元素按照默认规则进行排序,默认为升序排列,而且被排序的集合里面存储的元素必须实现Comparable接口并重写接口中的compareTo方法。

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    
    public class CollectionsTest {
        public static void main(String[] args) {
            ArrayList<Integer> list1 = new ArrayList<>();
            ArrayList<String> list2 = new ArrayList<>();
    
            // addAll()
            System.out.println(list1); // []
            Collections.addAll(list1, 1,2,3,4,5);
            System.out.println(list1); // [1, 2, 3, 4, 5]
    
            Collections.addAll(list2, "abc", "ccb", "bde");
            System.out.println(list2);  // [abc, ccb, bde]
    
            Collections.sort(list1);
            Collections.sort(list2);
            System.out.println(list1); // [1, 2, 3, 4, 5]
            System.out.println(list2);  // [abc, bde, ccb]
        }
    }
    

    例如在String中实现了Comparable<String>接口,并重写了compareTo方法:

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        		...
        	
            	public int compareTo(String anotherString) {
                int len1 = value.length;
                int len2 = anotherString.value.length;
                int lim = Math.min(len1, len2);
                char v1[] = value;
                char v2[] = anotherString.value;
        
                int k = 0;
                while (k < lim) {
                    char c1 = v1[k];
                    char c2 = v2[k];
                    if (c1 != c2) {
                        return c1 - c2;
                    }
                    k++;
                }
                return len1 - len2;
            }
        }
    

    如果我们想要对包含自定义的类对象的集合使用sort方法,同样需要实现Comparable<String>接口,并重写compareTo方法。假设Person类如下所示,我们实现接口并重写了其中的compareTo方法:

    public class Person implements Comparable<Person>{
        private int age;
        private String name;
    
        public Person() {
        }
    
        public Person(int age, String name) {
            this.age = age;
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public int compareTo(Person o) {
            // 按照age大小升序
            // 降序:o.getAge() - this.Age()
            return this.getAge() - o.getAge();
        }
    }
    

    那么,就可以调用包含Person对象的Collections中的sort方法。

    package collections;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    
    public class CollectionsTest {
        public static void main(String[] args) {
            ArrayList<Person> list3 = new ArrayList<>();
            list3.add(new Person(22,"Forlogen"));
            list3.add(new Person(20, "kobe"));
    
            System.out.println(list3); // [Person{age=22, name='Forlogen'}, Person{age=20, name='kobe'}]
            Collections.sort(list3);
            System.out.println(list3); // [Person{age=20, name='kobe'}, Person{age=22, name='Forlogen'}]
        }
    }
    
  • public static <T> void sort(List<T> list, Comparator<? super T>): 将集合中的元素按照指定的规则进行排序

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    
    public class CollectionsTest {
        public static void main(String[] args) {
            ArrayList<String> list2 = new ArrayList<>();
            Collections.addAll(list2, "abc", "ccb", "bde");
            System.out.println(list2);  // [abc, ccb, bde]
    		
            // 新建一个Comparator并重写其中的compare方法
            Collections.sort(list2, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    // 按照字符串中中索引为1的元素升序排列
                    return o1.charAt(1) - o2.charAt(1);
                }
            });
            System.out.println(list2);  // [abc, ccb, bde]
        }
    }
    

    那么两种sort方法中的Comparable和Comparator有什么区别呢?

    • Comparable:自己和传入的参数进行比较,使用时需要实现Comparable<String>接口,并重写compareTo方法,它相当于一个内部的排序器
    • Comparator:自定义的排序规则来比较两个对象,它相当于一个外部的排序器
  • public static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key): 在集合中查找某个元素的下标,但集合的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定

  • public static <T> int binarySearch(List<? extends T> list,T key,Comparator<? super T> c): 在集合中查找某个元素的下标,但集合的元素必须是T或T的子类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定

    package collections;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    
    public class CollectionsTest {
        public static void main(String[] args) {
            ArrayList<Integer> list1 = new ArrayList<>();
            ArrayList<String> list2 = new ArrayList<>();
    
            Collections.addAll(list1, 1, 5, 7, 2, 10, 3);
    
            System.out.println(Collections.binarySearch(list1, 10)); // 4
            System.out.println(Collections.binarySearch(list1, 1)); // 0
            
            Collections.addAll(list2, "abc", "ccb", "bde");
            int i = Collections.binarySearch(list2, "abc", new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return  o1.charAt(1) - o2.charAt(1);
                }
            });
            System.out.println(i); // 0
        }
    }
    

Collection和Collections的区别

  • java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式
  • java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法,此类不能实例化,通过类名直接使用其中的方法