Java教程

Day_19 【Java基础】集合Collection(List、Set)

本文主要是介绍Day_19 【Java基础】集合Collection(List、Set),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

对于数据的存储,我们已经介绍了数组,但是数组存储存在着很多的不足,如:
① 一旦初始化以后,其长度就不可修改
② 对于添加、删除、插入数据等操作非常不便,效率不高
③ 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足
④ 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用

Java集合分为Collection和Map两种体系

java集合超详解
在这里插入图片描述

一.Collection接口

Collection接口用于存储单列数据,
1)List接口:元素有序、可重复的集合
2)Set接口:元素无序、不可重复的集合
在这里插入图片描述
1.Collection接口中的主要方法

//Collection集合的主要方法说明
public class CollectionTest {
    public static void main(String[] args) {
        Collection arrayList = new ArrayList();
        Collection arrayList1 = new ArrayList();
        //1.add(object obj):向集合中添加元素
        arrayList.add("hello");
        arrayList.add(123);
        arrayList1.add('A');
        arrayList1.add(new String("中国"));
        //2.size():返回集合元素个数
        System.out.println(arrayList.size());
        //3.addAll(Collection c):将指定集合c中的元素添加到指定集合中
        arrayList.addAll(arrayList1);
        System.out.println(arrayList.size());
        //4.clear():删除集合中的所有元素
        //arrayList.clear();
        System.out.println(arrayList.size());
        //5.isEmpty():判断当前集合是否为空
        System.out.println(arrayList.isEmpty());
        //6.contains(object obj):判断当前集合是否包含指定元素
        //注意:此时实际调用的是实际对象obj重写后的equals()方法,若没有重写,则调用的是Object类中的equals()方法==
        System.out.println(arrayList1.contains(new String("中国")));//true
        //7.containsAll(collection c):判断该集合是否包含指定集合c中所有的元素
        System.out.println(arrayList.containsAll(arrayList1));
        System.out.println(arrayList);
        //8.equals(collection c):判断该集合是否和指定集合c相等(元素相同,注意集合有序时还要顺序相同)
        System.out.println(arrayList.equals(arrayList1));
        //9.remove(object o):删除该集合中指定的元素
        System.out.println(arrayList.remove(123));
        System.out.println(arrayList);
        //10.removeAll(collection c):删除包含指定集合c中所有的元素,返回boolean值
        System.out.println(arrayList.removeAll(arrayList1));//true
        //11.retainAll(Collection c):保留包含指定集合c中所有的元素
        System.out.println(arrayList);
        System.out.println(arrayList1);
        System.out.println(arrayList.retainAll(arrayList1));//true
        //12.hashCode();返回当前对象的哈希值
        System.out.println(arrayList.hashCode());
        //13.toArray():集合--->数组
        Object[] array = arrayList1.toArray();
        for(int i=0;i<array.length;i++){
            System.out.print(array[i]+"\t");
        }
        System.out.println();
        //扩展:数组--->集合
        List<String> strings = Arrays.asList(new String[]{"AA", "BB", "CC"});
        System.out.println(strings);
        List<int[]> ints = Arrays.asList(new int[]{1, 1, 3, 44});
        System.out.println(ints);//[[I@6d6f6e28]认为是一个元素,要写成对应的包装类就可以了
        List<Integer> integers = Arrays.asList(new Integer[]{11, 22, 33});
        System.out.println(integers);
    }
}

2.Collection集合中元素的遍历
迭代器模式:提供了一种方法访问一个容器对象中各个元素,而不需要暴露对象的内部细节。
(1)迭代器实现集合遍历

@Test//iterator迭代器,实现集合的遍历操作。
public void test01(){
    Collection arrayList = new ArrayList();
    arrayList.add("ABC");
    arrayList.add(new String("中国"));
    arrayList.add(123);
    //① next():迭代中的下一个元素 ② hasNext():判断下一个元素是否存在
    Iterator iterator = arrayList.iterator();
    while(iterator.hasNext()){
        System.out.println(iterator.next());
    }
}

集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前,此外,迭代器本身不存储数据,只是用于遍历集合。

(2)增强for循环实现集合遍历

@Test//增强for循环遍历集合、数组
public void test03(){
    Collection arrayList = new ArrayList();
    arrayList.add("ABC");
    arrayList.add(new String("中国"));
    arrayList.add(123);
    for(Object obj: arrayList){//实际就是将值赋值给obj后输出
        System.out.println(obj);
    }
}

3.使用迭代器删除指定的元素

@Test
public void test02(){
    Collection arrayList = new ArrayList();
    arrayList.add("ABC");
    arrayList.add(new String("中国"));
    arrayList.add(123);
    Iterator iterator = arrayList.iterator();
    while(iterator.hasNext()){
        //iterator.remove();
        Object next = iterator.next();//必须先next(),后remove(),否则会IllegalStateException
        if(next.equals("ABC")){
            iterator.remove();
        }
    }
}

二.List接口

在这里插入图片描述
List集合元素有序、可重复,实现了动态”数组“,线性存储,可以用于替换原有的数组。
1.ArrayList(最常用)
JDK 7下:
在这里插入图片描述
源码分析:ArrayList list = new ArrayList();底层是创建了长度为10的Object[] elementData数组,执行list.add(数据)时,当添加的个数超过10个,就会扩容为原来容量的1.5倍,并将原来的数据复制到新的list中。
开发建议使用带参数的构造器,指定长度:ArrayList list = new ArrayList(int Capacity);
JDK 8以后
在这里插入图片描述
源码分析: ArrayList list = new ArrayList();底层Object[] elementData初始化为{},当执行第一次list.add()后,才创建了长度为10的数组,后续操作和上述一样实现扩容。
List常用方法
Lis接口t继承自Collection接口,允许出现重复的元素,元素有序,可以使用索引访问,不但继承了Collection的全部方法,还增加了一些特有方法:

public class ListTest {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        List list = Arrays.asList(1, 2, 3, 5);
        //1.boolean add(object obj):向集合中添加一个元素
        arrayList.add("Hello");
        arrayList.add(111);
        arrayList.add(true);
        arrayList.add(new String("设计模式"));
        System.out.println(arrayList);
        //2.boolean addAll(Collection c):将指定的集合添加到该集合中
        arrayList.addAll(list);
        System.out.println(arrayList);
        //3.Object set(int index,Object element):修改指定索引处的元素,返回修改后的结果
        System.out.println(arrayList.set(0,"小王"));
        //4.Object get(int index):返回索引位置处的元素
        System.out.println(arrayList.get(0));
        //5.Object remove(int index):删除指定位置的元素,返回删除的元素
        //Object remove(object obj):
        System.out.println(arrayList.remove(0));
        //6.void add(int index,Object obj):在指定的位置插入元素,返回插入后的集合
        arrayList.add(0,"小吕");
        System.out.println(arrayList);
        //7.int size():返回该集合的长度
        System.out.println(arrayList.size());
        //8.List subList(int fromIndex,int toIndex):返回索引之间的子集合(左闭右开),原集合不变
		System.out.println(arrayList.subList(1,5));
		System.out.println(arrayList);
    }
}

集合三种遍历操作:

@Test
public void test01(){
    ArrayList arrayList = new ArrayList();
    arrayList.add("Hello");
    arrayList.add(111);
    arrayList.add(true);
    arrayList.add(new String("设计模式"));
    //1.iterator迭代器
    Iterator iterator = arrayList.iterator();
    while (iterator.hasNext()){
        System.out.print(iterator.next()+"\t");
    }
    System.out.println();
    //2.增强for循环
    for(Object obj: arrayList){
        System.out.print(obj+"\t");
    }
    System.out.println();
    //3.普通for循环
    for(int i=0;i<arrayList.size();i++){
        System.out.println(arrayList.get(i)+"\t");//使用索引访问集合元素
    }
}

2.LinkedList
在这里插入图片描述
源码分析:LinkedList linkedList = new LinkedList();内部声明了Node类型的first和last属性维护一个双向循环链表,默认值为null;当执行linkedList .add(123);将123封装到Node中,创建了Node对象。
LinkedList中部分常见的特有方法

public class ListTest02 {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        //1.void add(Object obj):添加元素
        linkedList.add("Java");
        //2.void add(int index,E element):指定位置插入指定元素
        linkedList.add(0,"设计模式");
        //3.void addFirst(Object obj):将指定元素插入集合开头
        linkedList.addFirst(123);
        //4.boolean offer(Object obj):向集合尾部追加元素
        System.out.println(linkedList.offer("offer"));//true
        //5.void push(Object obj):向集合头部追加元素
        linkedList.push(true);
        System.out.println(linkedList);//[true, 123, 设计模式, Java, offer]
        //6.Object poll():移除并返回第一个元素
        System.out.println(linkedList.poll());//true
        //7.Object peek():获取集合中的第一个元素
        Object peek = linkedList.peek();
        System.out.println(peek);//123
        System.out.println(linkedList);//[123, 设计模式, Java, offer]
        //8.Object removeFirst():删除集合中第一个元素,返回删除的元素
        System.out.println(linkedList.removeFirst());//123
        //9.Object pollLast():删除集合最后一个元素,返回删除的元素
        System.out.println(linkedList.pollLast());//offer
        System.out.println(linkedList);//[设计模式, Java]
    }
}

3.Vector
Vector线程安全,在JDK 7和JDK 8使用Vector()构造器创建时创建的数组长度为10,扩容方面扩容为原来长度的2倍。

三.Set接口

在这里插入图片描述
Set接口也继承自Collection接口,底层数组长度为16,但未对Collection接口中的方法进行扩充,Set接口中的元素无序,不可重复,添加对象时该对象所在的类必须重写hashCode()和equals()方法,判断两个对象相同使用equals()方法。
无序性:不等于随机性,存储的元素不是连续存储,而是根据hash值存储。
不可重复性:当向HashSet集合中添加元素时,首先会调用该元素的hashCode()方法来确定该元素的存储位置,然后再调用元素的equals()方法来确保该位置没有重复元素。
在这里插入图片描述
1.HashSet
作为Set的主要实现类,线程不安全,底层是数组加链表,可以存储null值。

public class HashSetTest {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(123);
        hashSet.add(true);
        hashSet.add(new String("Java"));
        hashSet.add(new User("小王", 18));
        hashSet.add(new User("小王", 18));
        Iterator iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
class User{
    private String name;
    private int age;
    public User() {
    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        System.out.println("User类的equals方法调用了...");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age &&
                Objects.equals(name, user.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在这里插入图片描述
1.1LinkedHashSet:
作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序输出,对于频繁的遍历操作,LinkedHashset效率高于HashSet。

public class LinkedHashSetTest {
    public static void main(String[] args) {
        LinkedHashSet linkedHashSet = new LinkedHashSet();
        linkedHashSet.add("Java");
        linkedHashSet.add(1234);
        linkedHashSet.add(new String("设计模式"));
        linkedHashSet.add(true);
        Iterator iterator = linkedHashSet.iterator();
        while (iterator.hasNext()){
            System.out.print(iterator.next()+"\t");
        }
    }
}

在这里插入图片描述
2.TreeSet
TreeSet是Set接口的一个实现类,底层采用平衡二叉树存储元素,使得TreeSet集合中不存在相同的元素,并且可以对元素加进行排序。要求向TreeSet中添加的元素必须是相同类的对象。
自然排序:比较两个对象是否相同的标准为: compareTo()返回0,不再是equals().

public class TreeSetTest {//TreeSet自然排序实现
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Person(18,"ALi"));
        treeSet.add(new Person(18,"Jhon"));
        treeSet.add(new Person(17,"Jack"));
        treeSet.add(new Person(19,"Tom"));
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
class Person implements Comparable{
    private int age;
    private String name;
    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 String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    @Override
    public int compareTo(Object o) {//按age排序,年龄相同时按name排序
        if(o instanceof Person){
            Person p = (Person)o;
            int num = Integer.compare(this.age,p.age);
            if(num!=0){
                return num;
            }else{
                return this.name.compareTo(p.name);
            }
        }else
            throw new RuntimeException("输入的类型不匹配...");
    }
}

在这里插入图片描述
定制排序:比较两个对象是否相同的标准为: compare()返回0,不再是equals().

public class TreeSetTest01 {
    public static void main(String[] args) {
        Comparator comparator = new Comparator(){
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof Animal && o2 instanceof Animal){
                    Animal o11 = (Animal) o1;
                    Animal o21 = (Animal) o2;
                    return Integer.compare(o11.getAge(),o21.getAge());//比较age,如果age相同,不再存储
                }
                throw new RuntimeException("传入的类型不匹配...");
            }
        };
        TreeSet treeSet = new TreeSet(comparator);//指定是定制排序
        treeSet.add(new Animal(18,"ALi"));
        treeSet.add(new Animal(18,"Jhon"));
        treeSet.add(new Animal(17,"Jack"));
        treeSet.add(new Animal(19,"Tom"));
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
class Animal {
    private int age;
    private String name;
    public Animal(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 String toString() {
        return "Animal{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

在这里插入图片描述

面试题:

1.ArrayList、LinkedList、Vector三者有何异同?
相同:三者都实现了List接口,存储有序、可重复的元素,动态存储
不同:
ArrayList:List主要实现方式,底层使用Object[] elementData存储,线程不安全,效率高
LinkedList:底层使用双向链表存储,对于频繁的插入、删除操作效率高
Vector:底层使用Object[] elementData存储,线程安全、效率低
2.输出下列程序的运行结果

@Test
public void test02(){
    ArrayList arrayList = new ArrayList();
    arrayList.add(1);
    arrayList.add(2);
    arrayList.add(3);
    updateList(arrayList);
    System.out.println(arrayList);
}
public void updateList(List list){
    //list.remove(2);//输出[1, 2]
	list.remove(new Integer(2));//输出[1, 3]
}

方式1是索引,删除的是索引位置的元素
方式2是元素,删除的是元素

这篇关于Day_19 【Java基础】集合Collection(List、Set)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!