JavaEE 学习笔记 第十一章 Java集合 23

第十一章 Java集合



11.1 Java集合框架概述

11.1.1 数组到集合的引申

        面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储。另一方面,使用Array存储对象方面具有一些弊端,而Java集合就像是一种容器,可以动态地多个对象的引用放入容器中,还可用于保存具有映射关系的关联数组。

数组在内存存储方面的特点:

        数组初始化以后,长度就确定了

        数组声明的类型,就决定了进行元素初始化时的类型

数组在存储数据方面的弊端:

        数组初始化以后,长度就不可改变了,不便于扩展

        数组中提供的属性和方法少,不便于进行添加,删除,插入等操作,且效率不高,同时无法直接获取存储元素的个数

        数组存储的数据是有序的,可以重复的,存储数据的特点比较单一 


11.1.2 Java集合的框架体系

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

                Collection接口:单列数据,定义了存取一组对象的方法的集合

                        List:元素有序,可重复的集合

                        Set:元素无序,不可重复的集合

                Map接口:双列数据,保存具有影射关系“key-value”键值对的集合

Collection接口继承树

Map接口继承树


11.2 Collection的接口方法

import java.util.*;

/**
 * Welcome to Idea Java
 *
 * @author Administrator
 * @date 2021/11/26 8:29
 **/
public class CollectionTest {
    public static void main(String[] args) {
        Collection collection1 = new ArrayList();

        //add(Object e):将元素e添加到集合collection中
        collection1.add(123);
        collection1.add("lisi");
        collection1.add(new Date());
        System.out.println(collection1);// [123, lisi, Fri Nov 26 08:36:35 CST 2021]

        //size():获取元素个数
        System.out.println(collection1.size());// 3

        //addAll():将集合a中的元素全部添加到集合b中
        Collection collection2 = new ArrayList();
        collection2.addAll(collection1);
        System.out.println(collection2);// [123, lisi, Fri Nov 26 08:39:39 CST 2021]

        //clear():将集合元素清空
        collection2.clear();

        //isEmpty():判断集合是否为空
        System.out.println(collection2.isEmpty());// true

        //contains(Object):判断集合是否包含某个元素
        System.out.println(collection1.contains("lisi"));// true

        //containsAll(Collection b):判断集合b中的元素是否都存在于集合a中
        collection2.add("zan");
        collection2.add("lisi");
        System.out.println(collection1.containsAll(collection2));// false

        //remove():移除集合中的某个元素
        System.out.println(collection1.remove("lisi"));// true
        System.out.println(collection1);// [123, Fri Nov 26 08:48:22 CST 2021]

        //removeAll():从当前集合a中移除与集合b中相同的所有元素
        collection2.add(123);
        System.out.println(collection2);// [zan, lisi, 123]
        System.out.println(collection2.removeAll(collection1));// true
        System.out.println(collection1);// [123, Fri Nov 26 08:55:48 CST 2021]
        System.out.println(collection2);// [zan, lisi]

        //retainAll():获取当前集合a与集合b中的交集,并返回给当前集合
        collection1.add("lisi");
        System.out.println(collection1);//[123, Fri Nov 26 08:58:37 CST 2021, lisi]
        System.out.println(collection1.retainAll(collection2));// true
        System.out.println(collection1);// [lisi]

        //equals():判断集合a与集合b是否相同,需要元素全部相同才能返回true
        System.out.println(collection1.equals(collection2)); // false
        Collection collection3 = new ArrayList();
        collection3.add("lisi");
        System.out.println(collection1.equals(collection3));// true

        //hashCode():返回当前集合的哈希值
        System.out.println(collection1.hashCode());

        //toArray():集合向数组的转型
        Object[] objects = collection2.toArray();
        System.out.println(Arrays.toString(objects)); // [zan, lisi]

        //toList():数组向集合的转型
        List<Object> objects1 = Arrays.stream(objects).toList();
        System.out.println(objects1);// [zan, lisi]
    }
}


11.3 Iterator迭代器遍历集合

11.3.1  Iterator迭代器的概述

        ①.Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素。

        ②.GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。

        ③.Collection接口继承了java.lang.Iterable接口,该接口有一个itreator()方法,那么所有实现了Collection接口的集合类都有一个treator()方法,用以返回一个实现了Iterator接口的对象。

        ④.Iterator仅用于遍历集合,Iterator本身并不提供承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。

        ⑤.集合对象每次调用itreator()方法都得到一个全新的迭代对象,默认游标都在集合的第一个元素之前。


11.3.1  Iterator迭代器的使用

import java.util.*;

// 集合元素的遍历操作 使用迭代器Iterator接口
public class CollectionTest {
    public static void main(String[] args) {
        Collection collection1 = new ArrayList();
        collection1.add(123);
        collection1.add("lisi");
        collection1.add(new Date());

        //集合实现Iterator接口
        Iterator iterator = collection1.iterator();
        //使用迭代器Iterator接口对象循环遍历
        while(iterator.hasNext()){
            //hasNext():判断是否还有下一个元素
            //next():指针下移,将下移以后集合位置上的元素返回
            System.out.println(iterator.next());
        }
        
        //使用迭代器remove()方法对集合元素进行删除
        Iterator iterator1 = collection1.iterator();
        while(iterator1.hasNext()){
            Object next = iterator1.next();
            if ("lisi".equals(next)){
                iterator1.remove();
            }
        }
    }
}

        注意:Iterator可以删除集合的元素,但是遍历过程中通过迭代器对象的remove方法,不是集合对象的remove方法;若果还未调用next()或在上一次调用next方法之后已经调用了remove方法,再调用remove都会报异常。


11.3.2 集合遍历的另一种实现方式

        增强for循环:foreach()的使用:

import java.util.*;

// 增强for循环:foreach()的使用
public class CollectionTest {
    public static void main(String[] args) {
        Collection collection1 = new ArrayList();
        collection1.add(123);
        collection1.add("lisi");
        collection1.add(new Date());

        for (Object o:collection1) {
            System.out.println(o);
        }
    }
}

11.4 Collection子接口一:List

11.4.1 List接口概述

        ①.鉴于Java中数组用来存储数据的局限性,我们通常使用List替代数组

        ②.List集合类中元素有序,且可重复,集合中的每个元素都具有其对应的顺序索引。

        ③.List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。

        ④.JDK API中List接口的实现类常用的有:ArrayList,LinkedList和Vector。       


11.4.2 List接口的方法

        List除了从Collection集合继承的方法外,List集合还添加了一些根据索引来操作集合元素的方法:

        void add(int index,Object ele):在index位置插入ele元素

        boolean addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来

        Object get(int index):获取指定index位置的元素

        int indexOf(Object obj):返回obj在当前集合中首次出现的位置

        int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置

        Object remove(int index):移除指定index位置的元素,并返回此元素

        Object set(int index,Object obj):设置指定index位置的元素为ele

        List subList(int fromIndex,int toIndex):返回从fromIndex到toIndex位置的子集合

import java.util.*;
//List接口的方法
public class CollectionTest {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        ArrayList arrayList1 = new ArrayList();

        arrayList.add(1);
        arrayList.add(3);
        arrayList.add(5);
        arrayList.add(6);

        arrayList1.add(4);

        //void add(int index,Object ele):在index位置插入ele元素
        arrayList.add(1,2);
        System.out.println(arrayList);//[1, 2, 3, 5, 6]

        //boolean addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来
        arrayList.addAll(3,arrayList1);
        System.out.println(arrayList);//[1, 2, 3, 4, 5, 6]

        //Object get(int index):获取指定index位置的元素
        System.out.println(arrayList.get(1));//2

        //int indexOf(Object obj):返回obj在当前集合中首次出现的位置
        System.out.println(arrayList.indexOf(1));//0

        //int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
        System.out.println(arrayList.lastIndexOf(1));//0

        //Object remove(int index):移除指定index位置的元素,并返回此元素
        System.out.println(arrayList1);//[4]
        System.out.println(arrayList1.remove(0));//4
        System.out.println(arrayList1);//[]

        //Object set(int index,Object obj):设置指定index位置的元素为ele
        System.out.println(arrayList);//[1, 2, 3, 4, 5, 6]
        arrayList.set(0,0);
        System.out.println(arrayList);//[0, 2, 3, 4, 5, 6]

        //List subList(int fromIndex,int toIndex):返回从fromIndex到toIndex位置的子集合
        System.out.println(arrayList.subList(1,6));//[2, 3, 4, 5, 6]

    }
}


11.4.3 List实现类之一:ArrayList

        ①.ArrayList是List接口的典型实现类,主要实现类

        ②.本质上,ArrayList是对象引用的一个”变长“数组

        ③.ArrayList的JDK 1.8之前与之后的实现区别?

                JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组

                JDK1.8:ArrayList像懒汉式,一开始创建一个长度为0的数组,当添加一个元素时再创建一个容量为10的数组

        ④.ArrayList.asList()方法返回的List集合,既不是ArrayList实例,也不是Vector实例。ArrayList.asList()方法返回值是一个固定长度的List集合


11.4.4 List实现类之二:LinkedList

        LinkedList:双向链表,内部没有声明数组。而定义了Node类型的first和last,用于记录首末元素。同时,定义内部类Node,作为LinkedList中保存数据的基本结构,对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高。Ndoe除了保存数据,还定义了两个变量: prev:变量记录前一个元素的位置;next:变量记录下一个元素的位置。

        新增方法:void addFirst(Object obj)

                          void addLast(Object obj)

                          Object getFirst()

                          Object getLast()

                          Object removeFirst()            

                          Object removeLast()


11.4.5 List实现类之三:Vector

        Vector的内部实现类似于ArrayList,Vector也是基于一个容量能够动态增长的数组来实现的,该类是JDK1.0版本添加的类,它的很多实现方法都加入了同步语句,因此是线程安全的(但Vector其实也只是相对安全,有些时候还是要加入同步语句来保证线程的安全)。        

        Vector继承于AbstractList,实现了List接口,可以对它进行队列操作;实现了RandmoAccess接口,即提供了随机访问功能;实现了Cloneable接口,能被克隆;实现了Serializable接口,因此它支持序列化,能够通过序列化传输。


11.4.6 ArrayList,LinkedList,Vector三者的异同

        ArrayList:作为List接口的主要实现类,线程不安全,效率高,底层使用Object[] elementData存储。

        LinkedList:对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率比

ArrayList高,底层使用双向链表。

        Vector:作为List接口的古老实现类,线程安全,效率低,底层使用Object[] elementData存储。


11.5 Collection子接口二:Set

11.5.1 Set接口概述

Set:存储无序的,不可重复的数据

        ①.无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的。

        ②.不可重复性:保证添加的元素按照equals()判断时,不能返回true。即相同的元素只能添加一个。

        ③.Set接口是Collection的子接口,set接口没有提供额外的方法

        ④.Set集合不允许包含相同的元素,如果试着把两个相同的元素加入同一个Set集合中,则添加操作失败。

        ⑤.Set判断两个对象是否相同不是使用 == 运算符,而是根据equals()方法


11.5.2 Set实现类之一:HashSet

        ①.HashSet 是Set 接口的典型实现,大多数时候使用Set集合时都使用这个实现类。

        ②.HashSet 按 Hash算法来存储集合中的元素,因此具有很好的存取,查找,删除性能。

        ③.HashSet 具有以下特点:不能保证元素的排列顺序;HashSet不是线程安全;集合元素可以说null

        ④.HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode()方法比较相等,并且两个对象的 equals()方法返回值也相等。

        ⑤.对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等原则。即:“相等的对象必须具有相等的散列码”。


11.5.3 Set实现类之二:LinkedHashSet

        ①.LinkedHashSet是HashSet的子类

        ②.LinkedHashSet根据元素的hashCode值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

        ③.LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能。

        ④.LinkedHashSet不允许集合元素重复。


11.5.4 Set实现类之二:TreeSet

        ①.TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。

        ②.TreeSet底层使用红黑树结构存储数据

        ③.新增的方法如下:(了解)

                Comparator comparator()

                Object first()

                Object last()

                Object lower(Object e)

                Object higher(Object e)  

                SortedSet subSet(fromElement,toElement)

                SortedSet headSet(toElement)

                SortedSet tailSet(fromElement)              

        ④.TreeSet 两种排序方法:自然排序和定制排序。默认情况下,ThreeSet采用自然排序。


11.5.5 TreeSet的练习实例

import java.util.Comparator;
import java.util.TreeSet;

/**
 * Welcome to Idea Java
 *
 * @author Administrator
 * @date 2021/11/27 9:55
 **/
public class SetTest {
    public static void main(String[] args) {

        //为treeSet设置定制排排序,安装生日进行排序,每次创建都进行对比排序
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Employee && o2 instanceof Employee) {
                    Employee employee1 = (Employee) o1;
                    Employee employee2 = (Employee) o2;

                    MyData data1 = employee1.getBirthday();
                    MyData data2 = employee2.getBirthday();

                    int minYear = data1.getYear() - data2.getYear();
                    if (minYear != 0) return minYear;
                    int minMouth = data1.getMonth() - data2.getMonth();
                    if (minMouth != 0) return minMouth;
                    return data1.getDay() - data2.getDay();
                }
                return 0;
            }
        });

        Employee employee1 = new Employee("阿哥", 12, new MyData(1998, 03, 25));
        Employee employee2 = new Employee("曹哥", 45, new MyData(1991, 02, 03));
        Employee employee3 = new Employee("一哥", 25, new MyData(1988, 05, 22));
        Employee employee4 = new Employee("帝哥", 50, new MyData(1988, 05, 13));
        Employee employee5 = new Employee("逼哥", 30, new MyData(1977, 12, 18));

        treeSet.add(employee1);
        treeSet.add(employee2);
        treeSet.add(employee3);
        treeSet.add(employee4);
        treeSet.add(employee5);

        for (Object O : treeSet) {
            System.out.println(O);
        }

    }
}

//Employee类
class Employee implements Comparable {
    private String name;
    private int age;
    private MyData birthday;

    public Employee() {
    }

    public Employee(String name, int age, MyData birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public MyData getBirthday() {
        return birthday;
    }

    public void setBirthday(MyData birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }

    //Employee实现Comparable接口,按照name排序,自然排序
    @Override
    public int compareTo(Object o) {
        if (o instanceof Employee) {
            Employee e = (Employee) o;
            return e.name.compareTo(this.name);
        }
        return 0;
    }
}

//MyData类
class MyData {
    private int year;
    private int month;
    private int day;

    public MyData() {
    }

    public MyData(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    @Override
    public String toString() {
        return "MyData{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }
}

点击进入:下一节:JavaEE 学习笔记 第十二章 Java集合 24

Guess you like

Origin blog.csdn.net/woailuo8214/article/details/121530061