JAVA基础之集合框架

时间:2022-02-15 19:25:07

集合框架体系

  • 集合类的由来
1、对象用于封装持有对象,对象多了需要存储,如果对象的个数不确定,就使用集合容器进行存储。
2、集合容器因为内部的数据结构不同,有多种具体容器,不断向上抽取,就形成了集合框架。
3、Java容器类类库的用途是“保存对象”
  • 集合特点
1、用于存储对象的容器
2、集合的长度是可变的
3、集合不可以存储基本数据类型值
  • 集合框架结构

Collection

I. Collection

  • Collection框架

Collection:一个独立元素的序列,这些元素都服从一条或多条规则
 -List:必须按照插入的顺序保存元素
 -Set:不能有重复元素
 -Queue:按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)
  • Collection方法
1.添加
boolean add(E e);  //添加元素
boolean addAll(Collection<? extends E> c);  //将集合c添加到当前集合中

2.删除
boolean remove(Object o);   // 从集合中移除元素o,会改变集合长度
boolean removeAll(Collection<?> c);   // 移除所有与c集合中相同的元素
void clear();  //清空集合

3.判断
boolean contains(Object o);  //判断集合中是否包含元素c
boolean containsAll(Collection<?> c);  //判断集合中是否包含c集合中所有元素
boolean isEmpty();  //判断集合是否为空

4.获取
int size();  //集合大小
Iterator<E> iterator();  // 获取集合迭代器(取出元素的方式)

5.其他
boolean retainAll(Collection<?> c);   //取交集,只保留集合和c集合相同的元素
Object[] toArray();  //集合转数组
  • toArray()方法
1、将集合转成数组,可以对集合中的元素操作的方法进行限定,不允许对其进行增删。
2、toArray方法需要传入一个指定类型的数组。
   如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同size的数组
   如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,其他位置默认为null。
   所以,长度建议指定为集合的size。
  • 添加元素
 
public class Test {
    public static void main(String[] args) {
        Collection<Integer> collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

        Integer[] moreInts = {6,7,8,9,10};
        collection.addAll(Arrays.asList(moreInts));

        Collections.addAll(collection, 11,12,13,14,15);
        Collections.addAll(collection, moreInts);

        List<Integer> list = Arrays.asList(1,2,3,4,5);
        list.set(1, 0);
        // 由此产生的list底层是数组,对其进行add,delete操作就会导致
        //java.lang.UnsupportedOperationException
        //list.add(1, 10);
        //list.add(20);

        List<Person> persons = Arrays.asList(new Worker(), new Student());

        // Arrays.asList中只有Student类型,只会创建List<Student>,需要显示说明
        // List<Person> students = Arrays.asList(new SmallStudent(), new HighStudent());
        List<Person> students = Arrays.<Person>asList(new SmallStudent(), new HighStudent());

        List<Person> lists = new ArrayList<Person>();
        Collections.addAll(lists, new SmallStudent(),new HighStudent());
    }
}

class Person {}
class Worker extends Person {}
class Student extends Person {}
class SmallStudent extends Student {}
class HighStudent extends Student {}

II. List

  • List共性特点
1、都可以操作角标,故List集合是可以完成对元素的增删改查
2、它以特定的顺序保持一组元素
  • 常用方法
1、添加
void add(int index, E element);
boolean addAll(int index, Collection<? extends E> c);

2、删除
E remove(int index);

3、修改
E set(int index, E element);

4、获取
E get(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
List<E> subList(int fromIndex, int toIndex);
  • List特有取出元素方式 - get(index)
 
private void getItem(List<Integer> list) {
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
}
  • List特有迭代器 - ListIterator
可以在迭代过程中进行增删改查
 
public class Test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
        test2(list);
        System.out.println();
        test1(list);
    }

    // 不要同时使用迭代和集合操作,否则会抛出ConcurrentModificationException
    private static void test1(List<Integer> list) {
        Iterator<Integer> iterator = list.iterator();
        // 迭代过程中不要使用集合操作元素,否则引发以上异常
        // 可以使用Iterable接口的子接口ListIterator来完成迭代中对元素进行更多的操作
        while (iterator.hasNext()) {
            int num = iterator.next();
            if (num == 3) {
                // list.add(4); //java.util.ConcurrentModificationException
            }
        }
        System.out.print(list);
    }

    private static void test2(List<Integer> list) {
        ListIterator<Integer> iterator = list.listIterator();
        // 只有List集合具备ListIterator,可以实现在迭代过程中完成对元素的增删改查
        while (iterator.hasNext()) {
            int num = iterator.next();
            if (num == 3) {
                iterator.add(4);
            }
        }
        System.out.print(list);
    }
}
  • 常用List集合特点
Vector:内部是数组数据结构,是同步的,查询元素速度快
ArrayList:内部是数组数据结构,是不同步的,替代了Vector;在List中间插入和移除元素时较慢,随机访问元素较快
LinkedList:内部是链表数据结构,是不同步的;随机访问元素较慢,在List中间插入和移除元素较快
  • eauals()方法
1、当确定一个元素是否属于某个List,发现某个元素的索引,以及从某个List中移除一个元素时,都会用到equals()方法
2、retainAll(Collection<?> c)方法也依赖于eauals()方法
3、sub = list.subList();那么对sub进行修改会导致list也会被修改,containsAll(sub)方法中,不会因为sub修改影响结果containsAll()结果
 
public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("android");
        list.add("java");
        list.add("sql");
        list.add("web");
        List<String> sub = list.subList(0, 3);
        System.out.println("Origin List:" + list);
        System.out.println("Origin Sub:" + sub);
        Collections.reverse(sub);
        System.out.println("Reverse List:" + list);
        System.out.println("Reverse sub:" + sub);
        System.out.println("List contain sub:" + list.containsAll(sub));
        sub.remove(0);
        System.out.println(list);
    }
}

/** 输出
Origin List:[android, java, sql, web]
Origin Sub:[android, java, sql]
Reverse List:[sql, java, android, web]
Reverse sub:[sql, java, android]
List contain sub:true
[java, android, web]
*/

II-1. ArrayList

ArrayList:在List中间插入和移除元素时较慢,随机访问元素较快

II-2. LinkedList

LinkedList提供了方法以支持队列的行为,并实现了Queue接口
  • 常用方法
public E poll():获取并移除此列表的头(第一个元素)
public E peek():获取但不移除此列表的头(第一个元素)
public void addFirst(E e):将指定元素插入此列表的开头
public boolean offerFirst(E e):在此列表的开头插入指定的元素
public void addLast(E e):将指定元素添加到此列表的结尾
public boolean offerLast(E e):在此列表末尾插入指定的元素
public E removeFirst():移除并返回此列表的第一个元素。等同于E remove()/E pop()
public E pollFirst():获取并移除此列表的第一个元素;如果此列表为空,则返回 null
public E removeLast():移除并返回此列表的最后一个元素
public E pollLast():获取并移除此列表的最后一个元素;如果此列表为空,则返回 null
public E getFirst() :返回此列表的第一个元素。等同于E element()
public E peekFirst():返回第一个元素,list为空时返回null
public E getLast():返回此列表的最后一个元素。
public E peekLast():获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null
  • LinkedList模拟堆栈和队列
堆栈:先进后出
队列:先进先出
 
// 堆栈:
public class Stack<T> {
    private LinkedList<T> list = new LinkedList<T>();

    public void push(T t) {
        list.addFirst(t);
    }

    public T peek() {
        if (!list.isEmpty())
            list.getFirst();
        return null;
    }

    public T pop() {
        if (!list.isEmpty()) {
            return list.removeFirst();
        }
        return null;
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }
}
 
// 队列:
public class Queue<T> {
    private LinkedList<T> list = new LinkedList<T>();

    public void insert(T t) {
        list.addLast(t);
    }

    public T get() {
        if (!list.isEmpty()) {
            return list.removeFirst();
        }
        return null;
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }
}

III. Set

  • 特性
Set元素不可以重复,是无序的
Set接口中的方法和Collection一致

III-1. HashSet

  • 特性
1、HashSet内部数据结构是哈希表,是不同步的,允许使用null元素
2、HashSet集合数据结构是哈希表,所以存储元素的时候使用元素的hashCode方法来确定位置,如果位置相同,再通过元素的equals来确定是否相同
  • 哈希表确定元素是否相同
1.判断的是两个元素的哈希值是否相同,如果相同,再判断两个对象的内容是否相同
2.判断哈希值相同,其实判断的是对象的hashCode的方法。判断内容相同,用的是equals方法
注意:如果哈希值不同,是不需要判断内容是否相同
 
class Person implements Comparable<Person> {
    String name;
    int age;

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

    // HashSet比较,先使用hashCode()比较,再使用equals()比较
    @Override
    public int hashCode() {
        return name.hashCode() + age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof Person))
            return false;
        if (this == obj)
            return true;
        Person person = (Person) obj;
        return this.name.equals(person.name) && this.age == person.age;
    }
}
  • LinkedHashSet
LinkedHashSet具有可预知迭代顺序的Set接口的哈希表和链接列表

III-2. TreeSet

  • 特性
TreeSet可以对Set集合中的元素进行排序,是不同步的
  • 判断元素唯一性的方式
根据比较方法compareTo()的返回结果是否是0,若为0则相同
  • TreeSet元素排序方式
方式一:让元素自身具备比较功能,元素就需要实现Comparable接口,覆盖compareTo方法
方式二(较常用):让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare()方法,将该类对象作为参数传递给TreeSet集合的构造函数
 
// 方式一
class Person implements Comparable<Person> {
    String name;
    int age;

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

    // TreeSet比较,使用compareTo
    public int compareTo(Person o) {
        return this.name.compareTo(o.name) == 0 ? this.age - o.age : this.name.compareTo(o.name);
    }
}
 
//方式二
public class Test {
    public static void main(String[] args) {
        TreeSet<Person> persons = new TreeSet<Person>(new ComparaByAge());
        persons.add(new Person("android", 3));
        persons.add(new Person("java", 2));
        persons.add(new Person("c", 2));
        System.out.println(persons);
    }
}

class Person {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Name:" + name + " Age:" + age;
    }
}

class ComparaByAge implements Comparator<Person> {
    public int compare(Person p1, Person p2) {
        return p1.age - p2.age;
        // return 1; 有序。
    }
}

//输出:
//[Name:java Age:2, Name:android Age:3]

IV. Queue

  • Queue - 队列
队列是一个典型的先进先出的容器
 
public class Test {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<String>();
        queue.offer("Android");
        queue.offer("JAVA");
        queue.offer("SHELL");
        while (queue.peek() != null) {
            System.out.print(queue.remove() + " ");
        }
    }
}

/**输出:
Android JAVA SHELL 
*/
  • PriorityQueue - 优先级队列
申明下一个弹出元素是最需要的元素(具有最高优先级),当调用offer方法来插入一个对象时,这个对象会在队列中被排序,默认的排序将使用对象在队列中的自然排序。
 
public class Test {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("java", "android", "c");
        PriorityQueue<String> queue = new PriorityQueue<String>(
                Collections.reverseOrder(new ComparatorByLength()));
        queue.addAll(list);
        queue.offer("Shell");
        while (queue.peek() != null) {
            System.out.print(queue.remove() + " ");
        }
    }
}

class ComparatorByLength implements Comparator<String> {
    public int compare(String o1, String o2) {
        int value = o1.length() - o2.length();
        return value == 0 ? o1.compareTo(o2) : value;
    }
}


/** 输出:
android Shell java c 
*/

迭代器

  • 迭代器特点
1、迭代器对象必须依赖于具体容器,因为每一个容器的数据结构都不同,所以迭代器对象是在容器中进行实现的
2、对于使用容器而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可,也就是iterator()方法
3、Iterator接口就是对所有的Collection容器进行元素取出的公共接口
4、迭代器Iterator,统一了对容器的访问方式
 
public class Test {
    public static void main(String[] args) {
        Collection<Integer> col = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));
        getItem(col);
    }

    private static void getItem(Collection<Integer> col) {
        /*
        Iterator<Integer> iterator = col.iterator();
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        */
        for(Iterator<Integer> iterator = col.iterator();iterator.hasNext();) {
            System.out.println(iterator.next());
        }
    }
}
  • 注意事项
不要同时使用迭代和集合操作,否则会抛出ConcurrentModificationException
 
public class Test {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>(Arrays.asList("abc", "bcd"));
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().equals("abc")) {
                list.add("abcd"); //Exception in thread "main" java.util.ConcurrentModificationException
            }
        }
    }
}

I. Iterator

1、java的Iterator只能单向移动
2、使用iterator()要求容器返回一个Iterator
3、使用next()获得序列中的下一个元素
4、使用remove移除由next()产生的最后一个元素,意味着在调用remove之前必须先调用next()
 
public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("JAVA");
        list.add("ANDROID");
        list.add("OBJECT C");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            iterator.next();
            iterator.remove();
        }
    }
}

II. ListIterator

ListIterator是一个更加强大的Iterator的子类型,只能用于各种List类的访问
1、调用listIterator()方法产生一个指向List开始处的ListIterator
2、ListIterator可以双向移动
3、可以产生相对于迭代器在列表中指向当前位置的前一个和后一个元素的索引
4、可以使用set()方法替换它访问过的最后一个元素
5、通过调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator
 
public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("JAVA");
        list.add("ANDROID");
        list.add("OBJECT_C");
        ListIterator<String> iterator = list.listIterator();
        while (iterator.hasNext()) {
            System.out.print(iterator.next() + " ");
        }
        System.out.println();
        while (iterator.hasPrevious()) {
            System.out.print(iterator.previous() + " ");
        }
        iterator = list.listIterator(1);
        System.out.println();
        while (iterator.hasNext()) {
            System.out.print(iterator.next() + " ");
            iterator.set("C#");
            iterator.add("Shell");
        }
        System.out.println();
        System.out.println(list);
    }
}

/** 输出:
JAVA ANDROID OBJECT_C 
OBJECT_C ANDROID JAVA 
ANDROID OBJECT_C 
[JAVA, C#, Shell, C#, Shell]
*/

III. Iterable

任何实现了迭代器Iterable的类都可以用在foreach语句中
 
public class Test {
    public static void main(String[] args) {
        String[] arrs = { "aa", "bb", "cc" };
        MultiIterableClass iterable = new MultiIterableClass(arrs);
        print(iterable);
        print(iterable.reversed());
        print(iterable.randomized());
    }

    private static void print(Iterable<String> iterable) {
        // 适配器方法,foreach中接收Iterable对象
        // 通过reversed(),randomized()创建不同的Iterable
        for (String string : iterable) {
            System.out.print(string + " ");
        }
        System.out.println();
    }
}

class IterableClass implements Iterable<String> {
    protected String[] arrays;

    public IterableClass(String[] arr) {
        arrays = arr;
    }

    public Iterator<String> iterator() {
        return new Iterator<String>() {
            private int index = 0;

            public boolean hasNext() {
                return index < arrays.length;
            }

            public String next() {
                return arrays[index++];
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

class MultiIterableClass extends IterableClass {
    public MultiIterableClass(String[] arr) {
        super(arr);
    }

    public Iterable<String> reversed() {
        return new Iterable<String>() {
            public Iterator<String> iterator() {
                return new Iterator<String>() {
                    int current = arrays.length - 1;

                    @Override
                    public boolean hasNext() {
                        return current > -1;
                    }

                    @Override
                    public String next() {
                        return arrays[current--];
                    }

                    @Override
                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }

    public Iterable<String> randomized() {
        return new Iterable<String>() {
            @Override
            public Iterator<String> iterator() {
                List<String> shuffle = new ArrayList<String>(Arrays.asList(arrays));
                Collections.shuffle(shuffle, new Random(47));
                return shuffle.iterator();
            }
        };
    }
}

/** 输出:
aa bb cc 
cc bb aa 
bb aa cc 
*/

Map

  • 特性
1、Map一次添加一组成对的“键值对”对象,key是唯一的,允许使用键值来查找值(Collection一次添加一个元素)
2、Map也称为双列集合,Collection集合称为单列集合
3、Map与数组和其他的Collection一样,可以很容易扩展到多维,只需将其值设置为Map(这些Map的值可以是其他容器,甚至是其他Map)

  • Map常见子类
Hashtable : 内部结构是哈希表,是同步的,不允许null作为键和值;提供了最快的查找技术,没有按照任何明显的顺序来保存其元素
 |--- Properties : 用来存储键值对的配置文件的信息,可以和IO技术相结合
HashMap : 内部结构是哈希表,是不同步,允许null作为键和值
 LinkedHashMap:有序的HashMap,按照插入顺序保存键,同时还保留了HashMap的查询速度
TreeMap : 内部是二叉树,是不同步的,可以对Map集合中的键值对排序;按照比较结果的升序保存键
  • 常用方法
1.添加
V put(K key, V value); //存相同键,值会覆盖。返回前一个和key关联的值,如果没有返回null

2.删除
void clear(); //清空集合
V remove(Object key); //根据指定key删除键值对

3.判断
boolean containsKey(Object key);
boolean containsValue(Object value);
boolean isEmpty();

4.获取
V get(Object key); //通过键获取值,如果没有该键返回null;可以通过返回null,来判断是否包含指定键
int size();
 
public class Test {
    public static void main(String[] args) {
        Map<Integer, String> maps= new HashMap<Integer, String>();
        print(maps.put(0, "zhangsan"));
        print(maps.put(0, "lisi"));
        print(maps.put(1, "wangwu"));
        print(maps.put(2, "zhaoliu"));
        print(maps.get(0));
        print(maps.containsKey(2));
        print(maps.remove(1));
        print(maps);
    }

    private static void print(Object object) {
        System.out.println(object);
    }
}

/*
输出:
null
zhangsan
null
null
lisi
true
wangwu
{0=lisi, 2=zhaoliu}
*/
  • 重点方法
Set<K> keySet(); //获取map中所有的键所在的Set集合

Set<Map.Entry<K, V>> entrySet();  //获取map中所有的键值对

Collection<V> values();  //获取map中所有的值
 
public class Test {
    public static void main(String[] args) {
        Map<Integer, String> maps= new HashMap<Integer, String>();
        maps.put(10, "zhangsan");
        maps.put(6, "wangwu");
        maps.put(5, "zhaoliu");
        maps.put(8, "lisi");

        Set<Integer> keySet = maps.keySet();
        Iterator<Integer> iterator1 = keySet.iterator();
        while(iterator1.hasNext()) {
            Integer key = iterator1.next();
            String value = maps.get(key);
            System.out.println(key + " : " + value);
        }

        System.out.println("--------------------------");

        Set<Map.Entry<Integer, String>> entrySet = maps.entrySet();
        Iterator<Map.Entry<Integer, String>> iterator2 = entrySet.iterator();
        while(iterator2.hasNext()) {
            Map.Entry<Integer, String> me = iterator2.next();
            Integer key = me.getKey();
            String value = me.getValue();
            System.out.println(key + " : " + value);
        }

        System.out.println("--------------------------");

        Collection<String> collection = maps.values();
        Iterator<String> iterator3 = collection.iterator();
        while(iterator3.hasNext()) {
            String value = iterator3.next();
            System.out.println(value);
        }
    }
}

/*
输出:
5 : zhaoliu
6 : wangwu
8 : lisi
10 : zhangsan
--------------------------
5 : zhaoliu
6 : wangwu
8 : lisi
10 : zhangsan
--------------------------
zhaoliu
wangwu
lisi
zhangsan
*/

I. HashMap

1、HashMap内部数据结构是哈希表,是不同步的,允许使用null元素
2、HashMap集合数据结构是哈希表,所以存储元素的时候使用元素的hashCode方法来确定位置,如果位置相同,再通过元素的equals来确定是否相同

II. TreeMap

  • 特性
TreeMap可以对Map集合中的元素进行排序,是不同步的
  • 判断元素唯一性的方式
根据比较方法compareTo()的返回结果是否是0,若为0则相同
  • TreeMap元素排序方式
方式一:让元素自身具备比较功能,元素就需要实现Comparable接口,覆盖compareTo方法
方式二(较常用):让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare()方法,将该类对象作为参数传递给TreeMap集合的构造函数
  • TreeMap应用
 
public class Test {
    public static void main(String[] args) {
        String in = "ashfdskjfiefasjhdasfklsjaf";
        System.out.println(getCount(in));
    }

    private static TreeMap<Character, Integer> getCount(String input) {
        TreeMap<Character, Integer> maps = new TreeMap<Character, Integer>();
        char[] in = input.toCharArray();
        for (char c : in) {
            int count = 1;
            Integer value = maps.get(c);
            if (value != null) {
                count = value + 1;
            }
            maps.put(c, count);
        }
        return maps;
    }
}

/**
输出:
{a=4, d=2, e=1, f=5, h=2, i=1, j=3, k=2, l=1, s=5}
*/

集合框架工具类

集合框架的工具类,里面的方法都是静态的。

I. Collections

  • 常用方法
void sort(List<T> list) :自然排序
void sort(List<T> list, Comparator<? super T> c) :带比较器的排序
void swap(List<?> list, int i, int j) :交换顺序
void reverse(List<?> list) :反转
T max(Collection<? extends T> coll)   :查找最大值
T max(Collection<? extends T> coll, Comparator<? super T> comp) :按照比较器查找最大值
int binarySearch(List<? extends Comparable<? super T>> list, T key) :折半查找
int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) :按照比较器折半查找
<T> boolean replaceAll(List<T> list, T oldVal, T newVal) :替换所有oldVal为newVal
<T> void fill(List<? super T> list, T obj) :替换所有元素为obj
void shuffle(List<?> list) :随机置换元素位置
<T> List<T> synchronizedList(List<T> list) :将非同步转为同步
  • 实例
 
public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("bcde");
        list.add("cdefg");
        list.add("abcdefg");
        list.add("defgh");
        System.out.println(list);

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

        int index = Collections.binarySearch(list, "defgh");
        String max = Collections.max(list);
        System.out.println("index:" + index + " max:" + max);

        index = Collections.binarySearch(list, "defgh", new CompartorByLength());
        max = Collections.max(list, new CompartorByLength());
        System.out.println(list);
        System.out.println("index:" + index + " max:" + max);

        Collections.sort(list, new CompartorByLength());
        System.out.println(list);

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

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

        Collections.replaceAll(list, "bcde", "aaaa");
        System.out.println(list);

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

        Collections.synchronizedList(list);

        Collections.fill(list, "bbbb");
        System.out.println(list);

        TreeSet<String> ts1 = new TreeSet<String>(Collections.reverseOrder());
        addElement(ts1);
        System.out.println(ts1);

        TreeSet<String> ts2 = new TreeSet<String>(Collections.reverseOrder(new CompartorByLength()));
        addElement(ts2);
        System.out.println(ts2);
    }

    private static void addElement(TreeSet<String> ts) {
        ts.add("bcde");
        ts.add("cdefg");
        ts.add("abcdefg");
        ts.add("defgh");
    }
}

class CompartorByLength implements Comparator<String> {
    public int compare(String o1, String o2) {
        int tmp = o1.length() - o2.length();
        return tmp == 0 ? o1.compareTo(o2) : tmp;
    }
}

II. Arrays

  • 常用方法
boolean equals(int[] a, int[] a2) :比较两个数组是否相等
String toString(int[] a) :数组转String
void sort(int[] a) :数组排序
int binarySearch(int[] a, int key) :在数组中查找元素
<T> List<T> asList(T... a):将数组转成集合
  • 好处
可以使用集合的方法操作数组中的元素
  • 注意
1、数组的长度是固定的,所以对已集合的增删方法是不可以使用的,否则会发生UnsupportedOperationException
2、如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储。
3、如果数组中的元素是基本类型数值,那么会将数组作为集合中的元素进行存储。
  • 实例
 
public class Test {
    public static void main(String[] args) {
        int[] arr1 = { 5, 1, 4, 2, 3};
        int[] arr2 = { 1, 3, 5, 7, 9};

        System.out.println(Arrays.equals(arr1, arr2));

        System.out.println(Arrays.toString(arr1));

        Arrays.sort(arr1);
        System.out.println(Arrays.toString(arr1));

        System.out.println(Arrays.binarySearch(arr1, 4));

        String[] str = { "Hello", "JAVA", "!" };
        List<String> list = Arrays.asList(str);
        System.out.println(list.contains("Hello"));
    }
}

/** 输出:
false
[5, 1, 4, 2, 3]
[1, 2, 3, 4, 5]
3
true
*/
  • Arrays.asList(T[])
Arrays.asList(T[])对返回列表的修改会直接写到数组T里。
new ArrayList<Integer>(Arrays.asList(T[]))创建的list修改后,不会影响数组T。
 
public class Test {
    public static void main(String[] args) {
        Integer[] data = { 1, 2, 3, 4, 5 };
        Random random = new Random(47);
        List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(data));
        System.out.println("Before:" + list1);
        Collections.shuffle(list1, random);
        System.out.println("After:" + list1);
        System.out.println("Array:" + Arrays.toString(data));

        List<Integer> list2 = Arrays.asList(data);
        System.out.println("Before:" + list2);
        Collections.shuffle(list2, random);
        System.out.println("After:" + list2);
        System.out.println("Array:" + Arrays.toString(data));
    }
}

/** 输出:
Before:[1, 2, 3, 4, 5]
After:[3, 1, 5, 2, 4]
array:[1, 2, 3, 4, 5]
Before:[1, 2, 3, 4, 5]
After:[4, 1, 5, 3, 2]
array:[4, 1, 5, 3, 2]
*/

对比

HashMap - Hashtable

1、继承不同。
2、Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。
3、Hashtable中,key和value都不允许出现null值,在HashMap中,null可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为null。
4、两个遍历方式的内部实现上不同,Hashtable、HashMap都使用了 Iterator,而由于历史原因,Hashtable还使用了Enumeration的方式 。
5、哈希值的使用不同,HashTable直接使用对象的hashCode,而HashMap重新计算hash值。
6、Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。

Comparator - Comparable

comparetor可以把具体的比较者分离开来,comaprable是需要具体的比较者去实现这个接口
class Person implements Comparable<Person> {}

TreeSet<Person> persons = new TreeSet<Person>(new ComparaByAge());
class ComparaByAge implements Comparator<Person> {}

Iterable - Iterator

1、Iterable中封装了Iterator接口,只要实现了Iterable接口的类,就可以使用Iterator迭代器了。
2、实现了Iterable的类可以使用foreach遍历,集合Collection、List、Set都是Iterable的实现类,所以他们及其他们的子类都可以使用foreach进行迭代。
3、Iterator中和核心的方法next(),hasnext(),remove(),都是依赖当前位置,如果这些集合直接实现Iterator,则必须包括当前迭代位置的指针。
   当集合在方法间进行传递的时候,由于当前位置不可知,所以next()之后的值,也不可知。
   而当实现Iterable则不然,每次调用都返回一个从头开始的迭代器,各个迭代器之间互不影响。

总结

  • 集合小结
数组将数字与对象联系起来,它保存类型明确的对象,查询对象时,不需要对结构做类型转换。
它可以使多维的,可以保存基本数据类型的数据,但是,数组一旦生成,其容量就不能改变。
Collection保存单一的元素,而Map保存相关联的键值对。
容器不能持有基本类型,但是自动包装机制会仔细地执行基本类型到容器中所持有的包装器类型之间的双向转换。
List也建立数字索引与对象的关联,因此数组和List都是排好序的容器。List能够自动扩充容量。
如果要进行大量的随机访问,就使用ArrayList;如果要经常从表中间插入或删除元素,则应该使用LinkedList。
各种Queue以及栈的行为,由LinkedList提供支持。
Map是一种将对象(而非数字)与对象相关联的设计。
HashMap设计用来快速访问,而TreeMap保存“键”始终处于排序状态,所以没有HashMap快。
LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问的能力。
Set不接受重复元素,HashSet提供最快的查询速度,而TreeSet保持元素处于排序状态。
LinkedHashSet以插入顺序保持元素。
新程序中不应该使用过时的Ventor、Hashtable和Stack。
  • 集合的一些技巧
需要唯一吗?
  需要:Set
    需要指定顺序吗?
      需要:TreeSet
      不需要:HashSet
      但是想要一个和存储一致的顺序(有序):LinkedHashSet
  不需要:List
    需要频繁增删吗?
      需要:LinkedList
      不需要:ArrayList
  • 如何记住每一个容器的结构和所属体系呢?
后缀名就是该集合所属体系
前缀名就是该集合的数据结构

List
  |--ArrayList
  |--LinkedList
Set
  |--HashSet
  |--TreeSet
看到array:就要想到数组,就要想到查询快,有角标
看到link:就有想到链表,就要想到增删快,就要想到add get remove + first last的方法
看到hash:就要想到哈希表,就要想到唯一性,就要想到元素需要hashcode方法和equals方法
看到tree:就要想到二叉树,就要想到排序,就要想到两个接口Comparable,Comparator
通常这些常用的集合容器都是不同步的
  • 可变参数
其实就是一个数组,但是接收的是数组的元素。
字段将这些数组封装成数组,简化了调用者的书写。
注意:可变参数类型,必须定义在参数列表的结尾处
// int add(int... arr, int a) //错误的
 
import static java.lang.System.out;;
// 静态导入
public class Test {
    public static void main(String[] args) {
        out.println(add(1,2,3,4,5));
    }

    private static int add(int... arr) {
        int sum = 0;
        for (int i : arr) {
            sum += i;
        }
        return sum;
    }
}