Java集合-Collection

概述

集合是Java用于处理数据的工具。集合中的数据存储在内存,不具有持久性
 Java中的集合分为 单列集合 与 双列集合单列集合 存储纯粹的目标对象,对应Collection接口;双列集合 存储key-value(键值对)数据,对应Map接口。

单列集合分为 有序集合 与 无序集合有序集合的典型为List接口的实现;无序集合的典型为Set接口的实现。Collection是泛型接口。

Collection中的常用方法

public interface Collection<E> extends Iterable<E> {
    
    /* 返回集合中元素个数 */
    int size();
    
    /* 如果集合中没有元素,返回true */
	boolean isEmpty();
    
    /* 如果集合中至少包含1个与指定对象相等的元素,返回true.
       注意contains()并非判断是否包含同一个对象,而是通过
       调用传入对象的equals()判断是否包含相等元素。
       因此目标对象类必须重写equals()。 */
	boolean contains(Object o);
    
    /* 返回集合的遍历。已返回遍历中的元素顺序不能保证,除非集合实例是有序的 */
	Iterator<E> iterator();
    
    Object[] toArray();
    
    <T> T[] toArray(t[] a);
    
    /* 向集合添加一个指定元素。如果集合由于本次调用添加而改变,返回true;
       如果集合不支持添加重复元素且已包含调用指定的元素,或者集合拒绝
       添加某些元素(例如有的集合拒绝添加null),返回false. */
    /* 由于需要判断是否包含指定元素,目标对象类必须重写equals(). */
    boolean add(E e);
    
    /* 从集合移除一个指定元素,若有多个元素与指定对象相等,仅仅移除第一个。
       如果集合由于本次调用移除而改变(即集合中存在一个或多个与指定对象相等的元素),返回true. */
    /* 由于需要判断是否包含指定元素,目标对象类必须重写equals(). */
    boolean remove(Object o);
    
    /* 如果集合中包含指定集合中的所有元素,返回true. */
    /* 由于需要判断是否包含指定元素,目标对象类必须重写equals(). */
    boolean containsAll(Collection<?> c);
    
    /* 将指定集合中的所有元素添加至集合。如果集合由于本次调用添加而改变,返回true. */
    /* 由于需要判断是否包含指定元素,目标对象类必须重写equals(). */
    boolean addAll(Collection<? extends E> c);
    
    /* 移除集合中所有与指定集合的交集元素,包括重复元素。
       如果集合由于本次调用移除而改变(集合与目标集合有交集),返回true. */
    /* 由于需要判断是否包含指定元素,目标对象类必须重写equals(). */
    boolean removeAll(Collection<?> c);
    
    /* 保留集合中所有与指定集合的交集元素(或删除集合中与指定集合的差集元素),包括重复元素。 
       如果集合由于本次调用移除而改变(集合与目标集合有差集),返回true.*/
    /* 由于需要判断是否包含指定元素,目标对象类必须重写equals(). */
    boolean retainAll(Collection<?> c);
    
    /* 清除集合中的所有元素 */
    void clear();
    
    /* 比较集合是否与指定集合相等。两个集合的 元素个数形同、对应元素相等(List集合的有序性),
       则两个几何相等。*/
    /* 由于需要判断是否包含指定元素,目标对象类必须重写equals(). */
    boolean equals(Object o);
    
    int hashCode();
    
}

扩展

Arrays.asList()

asList()Arrays类中的静态方法:

static <T> List<T> asList(T... a)

 将数组转换为List集合。例:

String[] strs = new String[]{"Tony","Tom","Jerry"};
Integer[] ints = new Integer[]{111,222,333};
List<?> list_1 = Arrays.asList(strs);
List<?> list_2 = Arrays.asList(ints);
List<?> list_3 = Arrays.asList("Tony","Tom","Jerry");
List<?> list_4 = Arrays.asList(111,222,333);

 注意:将数组int[]{...}转换为List时会出现预期之外的情况,asList()会将int[]{...}作为一个数组元素。floatdouble等类似,应当使用包装类代替。例:

@Test
public void test(){
    List<?> list = Arrays.asList(new int[]{111,222,333});
	System.out.println(list.size());
	System.out.println(list);
}

运行结果:

1
[[I@10f87f48]

使用包装类代替:

@Test
public void test(){
    List<?> list = Arrays.asList(new Integer[]{111,222,333});
	System.out.println(list.size());
	System.out.println(list);
}

运行结果:

3
[111, 222, 333]

Iterator

 概述:Iterator泛型接口,用于集合的遍历。Iterator构造出虚拟指针用于得到集合中的下一个元素。注意:Iterator并不会创造一个新的集合容器以实现集合的遍历,它只是可以读取或改变集合内容的迭代器。

E next():泛型方法,返回集合中的下一个元素。

注意:
 ①指针初始位于集合中第一个元素之前的空位,第一次调用next()将返回集合的第一个元素。
 ②每次调用next()都会导致指针向前移动。指针已经处于集合末尾时,调用next()会抛NoSuchElementException

boolean hasNext():判断是否有下一个元素。如果指针已经位于集合的末尾,hasNext()将返回false

**注意:**调用hasNext() 不会 导致指针移动。

ArrayList<String> list = new ArrayList<>();
list.add("Tony");
list.add("Tom");
list.add("Jerry");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()) {
    System.out.print(iterator.next()+" ");
}

void remove():移除集合中当前指针所在位置的元素。

注意:
 ①第一次调用next()之前不可使用remove(),否则会抛IllegalStateException。因为指针初始位于集合第一个元素之前的空位。
 ②不可在同一位置调用超过一次remove(),否则会抛IllegalStateException

ArrayList<String> list = new ArrayList<>();
list.add("Tony");
list.add("Tom");
list.add("Jerry");
list.add("Julia");
list.add("Marry");
list.add("Mophy");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
    String s = iterator.next();
    System.out.print(s+" ");
    if("Jerry".equals(s)){
        iterator.remove();
    }
}
System.out.print("\r\n");
Iterator<String> iter = list.iterator();
while(iter.hasNext()){
    System.out.print(iter.next()+" ");
}

List

 概述:List集合的特性是 有序性 可重复性List接口的常用实现有ArrayList<>LinkedListVector

List中的常用方法:

/* 将新的元素添加至List的index位置,原本index位置及其以后的元素都将后移。 */
void add(int index,E element)

/* 将新的集合添加至List的index位置,新的集合的第一个元素将占据List中原本index位置,
   List中原本index位置及其以后的元素都将后移。*/
/* 如果集合由于本次调用添加而改变,返回true. */
boolean addAll(int index,Collection<? extends E> c)
    
/* 返回List中 第一个 与指定对象相等的元素索引。
   如果List中不包含与指定对象相等的元素,返回 -1. */
/* 由于需要判断元素是否与指定对象相等,目标对象类必须重写equals(). */
int indexOf(Object o)
    
/* 返回List中 最后一个 与指定对象相等的元素索引。 
   如果List中不包含与指定对象相等的元素,返回 -1. */
/* 由于需要判断元素是否与指定对象相等,目标对象类必须重写equals(). */
int lastIndexOf(Object o)
    
/* 获得List中指定索引位置的元素。
   如果指定索引超出范围,抛 IndexOutOfBoundsException. */
E get(int index)
    
/* 设置List中指定索引位置的元素的值,并返回该位置元素的 原本值。 */
E set(int index,E element)
    
/* 移除List中指定索引位置的元素,并返回该位置 移除之前 元素的值。 */
E remove(int index)
    
/* 获得List中指定索引区间 [fromIndex,toIndex) 的子List集合. 
   包含fromIndex,不包含toIndex.*/
List<E> subList(int formIndex,int toIndex)

/* 返回指定集合的复制,该复制不可进行更改,否则会抛异常。
   本体的后续修改不会影响该复制。*/
static <E> List<E> copyOf(Collection<? extends E> coll)

/* 对List集合进行定制排序 */
default void sort(Comparator<? super E> c)

 注意:使用remove(Object o)remove(int index)时注意区分:对于int型的List而言,使用remove((int)n)时,系统会认为调用的是remove(int index)而不是remove(Object o).如果需要从intList中移除指定元素,可以采取封装类:remove(Integer.valueOf(n)).例如:

@Test
public void test(){
    ArrayList<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.remove(Integer.valueOf(2));  //  public static Integer valueOf(int i)
    System.out.println(list);  //输出[1,3]
}

定制排序:

@Test
public void test(){
    LinkedList<String> list = new LinkedList<>();
    list.add("Tony");
    list.add("Jerry");
    list.add("Lucy");
    list.add("Steve");
    list.add("Tom");
    list.sort(new Comparator<String>(){
        @Override
        public int compare(String st1,String st2){
            //从小到大排序
            return st1.compareTo(st2);
        }
    });
    Iterator iterator_1 = list.iterator();
    while(iterator_1.hasNext()){
        System.out.print(iterator_1.next()+" ");
    }
    System.out.println();
    list.sort(new Comparator<String>(){
        @Override
        public int compare(String st1,String st2){
            //从大到小排序
            return -(st1.compareTo(st2));
        }
    });
    Iterator iterator_2 = list.iterator();
    while(iterator_2.hasNext()){
        System.out.print(iterator_2.next()+" ");
    }
}

运行结果:

Jerry Lucy Steve Tom Tony 
Tony Tom Steve Lucy Jerry 

ArrayList

 概述:ArrayList底层由Object[]实现。线程不安全,执行效率高。

ArrayList中常用的新方法:

/* 返回ArrayList实例的 浅拷贝,元素本身不会被复制。*/
Object clone()
@Test
public void test(){
    ArrayList<String> list = new ArrayList<>();
    list.add("Tony");
    list.add("Jerry");
    list.add("Mophy");
    ArrayList<String> cloneList = (ArrayList<String>)list.clone();
    cloneList.remove(1);
    System.out.println(list);         //["Tony","Jerry","Mophy"]
    System.out.println(cloneList);    //["Tony","Mophy"]
}

注意:浅拷贝数值层面的拷贝,本体和副本指向不同对象;深拷贝对象层面的拷贝,本体和副本指向相同对象。

/* 将ArrayList实例的容量调整为当前列表的大小。
   通过此操作可最小化ArrayList实例的存储,以优化应用程序。 */
void trimToSize()

LinkedList

 概述:LinkedList底层由双向链表实现。用于需要频繁插入、删除数据的场合。执行效率比ArrayList高。

LinkedList中常用的新方法:

/* 在List的开头插入指定元素 */
void addFirst(E e)
    
/* 在List的末尾追加指定元素,等同于 add() */
void addLast(E e)
    
/* 获得List的第一个元素 */
E getFirst()
    
/* 获得List的最后一个元素 */
E getLast()
@Test
public void test(){
    LinkedList<String> list = new LinkedList<>();
    list.add("Tony");
    list.add("Jerry");
    list.add("Mike");
    list.add("Tony");
    list.add("Sandy");
    System.out.println(list.size());
    Iterator<String> iterator = list.iterator();
    while(iterator.hasNext()){System.out.print(iterator.next()+" ");}
}

运行结果:

5
Tony Jerry Mike Tony Sandy

Vector

 概述:Vector底层由Object[]实现。线程安全,执行效率低。

@Test
public void test(){
    Vector<String> v = new Vector<>();
    v.add("Tony");
    v.add("Jerry");
    v.add("Mike");
    v.add("Tony");
    v.add("Sandy");
    System.out.println(v.size());
    Iterator<String> iterator = v.iterator();
    while(iterator.hasNext()){System.out.print(iterator.next()+" ");}
}

运行结果:

5
Tony Jerry Mike Tony Sandy 

Set

 概述:Set的特性是:无序性不重复性
无序性:存储的数据在底层数组中并非按照数组的索引顺序添加,而是由数据的hashCode决定。
不重复性Set集合中的数局在数值层面没有重复元素。向Set集合中添加已经存在的数据不会改变Set集合。

Set集合添加数据的过程

Set集合根据数据的哈希值使用某种算法确定数据的存放位置Set存放数据的步骤为:

 ①.调用将要添加数据对象的hashCode()方法确定存放位置,该位置为空则添加成功。该位置不为空则进行第②步。
 ②.比较该位置已存在数据和将要添加数据的哈希值,不相同则添加成功,将新数据在该位置与原本的数据以链表形式保存(已存在的数据指向新添加的数据)。相同则进行第③步。
 ③.调用将要添加数据对象的equals()方法比较是否与该位置已存在数据的值相等。不相等则添加成功,相等则添加失败。

HashSet

 概述:HashSet集合遍历结果中的元素顺序与添加顺序不同,遍历顺序由元素的哈希值决定。HashSet线程不安全的。

@Test
public void test(){
	HashSet<String> set = new HashSet<>();
    set.add("Tony");
    set.add("Jerry");
    set.add("Mike");
    //重复数据将添加失败
    set.add("Tony");
    set.add("Sandy");
    System.out.println(set.size());
    Iterator<String> iterator = set.iterator();
    while(iterator.hasNext()){System.out.print(iterator.next()+" ");}
}

运行结果:

4
Tony Mike Sandy Jerry 

LinkedHashSet

 概述:LinkedHashSetHashSet的子类。LinkedHashSetHashSet的基础上在元素之间按照添加顺序增加了双向链表地址链接,因此LinkedHashSet集合遍历结果的元素顺序与添加顺序一致。对于频繁的遍历操作,LinkedHashSet效率高于HashSet

@Test
public void test(){
	LinkedHashSet<String> set = new LinkedHashSet<>();
    set.add("Tony");
    set.add("Jerry");
    set.add("Mike");
    //重复数据将添加失败
    set.add("Tony");
    set.add("Sandy");
    System.out.println(set.size());
    Iterator<String> iterator = set.iterator();
    while(iterator.hasNext()){System.out.print(iterator.next()+" ");}
}

运行结果:

4
Tony Jerry Mike Sandy 

TreeSet

概述

TreeSet的底层是 红黑树 结构,可对集合中的元素进行自然排序定制排序
TreeSet集合中添加的数据必须是可比较的,必须为该数据类型制定比较规则(ComparableComparator)
 与HashSetLinkedHashSet不同,TreeSet不使用equals()方法判断两个数据是否相等,而是通过为数据类型制定的比较规则判断compareTo()compare()返回0则认为两个数据相等,数据添加失败;compareTo()compare()返回1-1则认为两个数据不相等,数据添加成功。

TreeSet的自然比较

Person.java

public class Person implements Comparable<Person> {
    private String name;
    private float height;
    private int weight;
    public Person(String name,float height,int weight){
        this.name = name;
        this.height = height;
        this.weight = weight;
    }
    public void setName(String name){this.name = name;}
    public String getName(){return this.name;}
    public void setHeight(float height){this.height = height;}
    public float getHeight(){return this.height;}
    public void setWeight(int weight){this.weight = weight;}
    public int getWeight(){return this.weight;}
    
    @Override
    public int compareTo(Person p){
        //name相同直接认为数据相等
        if(this.getName().equals(p.getName())) return 0;
        else {
            //一级比较:height
            if(this.getHeight() > p.getHeight()) return 1;
            else if(this.getHeight() < p.getHeight()) return -1;
            else {
                //二级比较:weight
                if(this.getWeight() > p.getWeight()) return 1;
                else if(this.getWeight() < p.getWeight()) return -1;
                //三级比较:name
                return this.getName().compareTo(p.getName());
            }
        }
    }   
}

Main.java

public class Main {
    public static void main(String[] args){
        TreeSet<Person> set = new TreeSet<>();
        
        set.add(new Person("Tony",1.75f,130));
        set.add(new Person("Steve",1.80f,140));
        set.add(new Person("Jerry",1.75f,120));
        //new Person("Tony",1.70f,125)不会成功添加,因为比较规则认为name相同,数据相同
        set.add(new Person("Tony",1.70f,125));
        set.add(new Person("Mike",1.72f,130));
        
        Iterator<Person> iterator = set.iterator();
        while(iterator.hasNext()){
            Person p = iterator.next();
            System.out.println(p.getName()+" "
                               +p.getHeight()+"m "
                               +p.getWeight()+"(1/2Kg).");
        }
    }
}

运行结果:

Mike 1.72m 130(1/2Kg).
Jerry 1.75m 120(1/2Kg).
Tony 1.75m 130(1/2Kg).
Steve 1.8m 140(1/2Kg).

TreeSet的定制比较

Person.java

public class Person {
    private String name;
    private float height;
    private int weight;
    public Person(String name,float height,int weight){
        this.name = name;
        this.height = height;
        this.weight = weight;
    }
    public void setName(String name){this.name = name;}
    public String getName(){return this.name;}
    public void setHeight(float height){this.height = height;}
    public float getHeight(){return this.height;}
    public void setWeight(int weight){this.weight = weight;}
    public int getWeight(){return this.weight;}  
}

Main.java

public class Main {
    public static void main(String[] args){
        
        //set_1元素从小到大排序
        TreeSet<Person> set_1 = new TreeSet<>(new Comparator<Person>(){
            @Override
            public int compare(Person p1,Person p2){
                //name相同直接认为数据相等
                if(p1.getName().equals(p2.getName())) return 0;
                else {
                    //一级比较:height
                    if(p1.getHeight() > p2.getHeight()) return 1;
                    else if(p1.getHeight() < p2.getHeight()) return -1;
                    else {
                        //二级比较:weight
                        if(p1.getWeight() > p2.getWeight()) return 1;
                        else if(p1.getWeight() < p2.getWeight()) return -1;
                        //三级比较:name
                        return p1.getName().compareTo(p2.getName());
                    }
                }
            }
        });
        
        set_1.add(new Person("Tony",1.75f,130));
        set_1.add(new Person("Steve",1.80f,140));
        set_1.add(new Person("Jerry",1.75f,120));
        //new Person("Tony",1.70f,125)不会成功添加,因为比较规则认为name相同,数据相同
        set_1.add(new Person("Tony",1.70f,125));
        set_1.add(new Person("Mike",1.72f,130));
        
        //set_2元素从大到小排序
        TreeSet<Person> set_2 = new TreeSet<>(new Comparator<Person>(){
            @Override
            public int compare(Person p1,Person p2){
                //name相同直接认为数据相等
                if(p1.getName().equals(p2.getName())) return 0;
                else {
                    //一级比较:height
                    if(p1.getHeight() > p2.getHeight()) return -1;
                    else if(p1.getHeight() < p2.getHeight()) return 1;
                    else {
                        //二级比较:weight
                        if(p1.getWeight() > p2.getWeight()) return -1;
                        else if(p1.getWeight() < p2.getWeight()) return 1;
                        //三级比较:name
                        return -(p1.getName().compareTo(p2.getName()));
                    }
                }
            }
        });
        
        set_2.add(new Person("Tony",1.75f,130));
        set_2.add(new Person("Steve",1.80f,140));
        set_2.add(new Person("Jerry",1.75f,120));
        //new Person("Tony",1.70f,125)不会成功添加,因为比较规则认为name相同,数据相同
        set_2.add(new Person("Tony",1.70f,125));
        set_2.add(new Person("Mike",1.72f,130));
        
        Iterator<Person> iterator_1 = set_1.iterator();
        while(iterator_1.hasNext()){
            Person p = iterator_1.next();
            System.out.println(p.getName()+" "
                               +p.getHeight()+"m "
                               +p.getWeight()+"(1/2Kg).");
        }
        System.out.println();
        Iterator<Person> iterator_2 = set_2.iterator();
        while(iterator_2.hasNext()){
            Person p = iterator_2.next();
            System.out.println(p.getName()+" "
                               +p.getHeight()+"m "
                               +p.getWeight()+"(1/2Kg).");
        }
    }
}

运行结果:

Mike 1.72m 130(1/2Kg).
Jerry 1.75m 120(1/2Kg).
Tony 1.75m 130(1/2Kg).
Steve 1.8m 140(1/2Kg).

Steve 1.8m 140(1/2Kg).
Tony 1.75m 130(1/2Kg).
Jerry 1.75m 120(1/2Kg).
Mike 1.72m 130(1/2Kg).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值