集合框架

集合概念:
    用于存储多个对象的单一对象(容器),存储的数据叫元素。
    元素必须是引用数据类型的数据,不能是基本数据类型,可以是包装类
    用于模拟现实生活中的存储容器,因此集合类型,不单单是一种,有很多很多种类型,

     设计成各种存储的数据结构,这些结构统称为集合框架。
    jdk1.5新特性:
        在1.5以前,容器可以存储Object的任何子类型,但是在对元素进行操作时
        比如,调用元素的方法等,我们必须知道元素的类型,将父类型的数据转成我们想要使用的类型

        因此,在编程中增加了大量代码来进行强制转换。增加了开发难度。
        因此1.5开始,支持了一个新特性,叫泛型机制,用来规定容器中存储的元素类型
        此机制可以在编译期间就进行判断元素的类型

集合中的类型都需要声明泛型,不然会出现警告:

集合框架

泛型机制:
    概念:
    1、jdk1.5版本开始使用的新特征,本质是进行“参数化类型”,将元素类型当成是形参,

    通过形参来更改元素的类型,在类,接口, 方法的定义上都可以使用,用来指定数据类型名的,

可以自己定义一种泛型

集合框架

像这种情况,我们可以根据构造器初始化时,给元素类型进行赋值,初始化后,这个类就只能使用我们定义的类型,

这样放在集合中的就是同一类型的了。测试一下自定义的类型

集合框架

集合框架

还用另外一种,在初始化时也可以直接将类型传禁区,所使用的方法也都是相应类型,保证了元素类型的一致性

集合框架

测试一下:

集合框架

集合框架

也可以是这种,
    2、集合在定义时,可以用泛型机制来指定元素的类型,这样编译器在编译期间
    就可进行检查元素类型是否匹配,避免了程序在运行时出现过多的错误
    3、集合框架中的所有类型(接口,抽象类,实现类)都是用了泛型机制
    4、泛型机制的参数只能传引用数据类型,基本数据类型使用包装类。
        要存储元素的类型集合框架

集合框架

Collection与Collections的区别
    Collection:是集合的父接口,定义了集合框架中常用的抽像方法
    Collections:合的工具类,定义了很多用于操作集合对象的工具/工厂方法

常用的方法:

       boolean add(E e)
            将对象e添加到集合中

集合框架

集合中重写了toString方法,可以直接输出。输出结果如下:

       集合框架
        boolean addAll(Collection c) 
            将里的元素地址添加到此集合里。

重新建立一个集合,将集合中元素添加到上面的集合c中

集合框架

输出结果为:

集合框架
        void clear()
            清空集合元素

        int size()
            返回集合元素的个数

集合框架

输出结果为:

集合框架
        boolean contains(Object obj)
            用于判断集合中是否存在与obj相同的元素

集合框架
        boolean containsAll(Collection c) 
            用于判断此集合中,是否包含集合c中所有元素

与上面的调用方法类似
        boolean isEmpty() 
            用于判断集合元素是否为空。

集合框架
        boolean remove(Object o)
            用于移除集合中的某一元素

集合框架
        boolean removeAll(Collection c) 
            用于移除此集合中与c*有元素

集合框架

        boolean retainAll(Collection c)
            用于保留此集合中和c*有元素

集合框架
        toArray() 
            返回一个包含此集合中所有元素的数组。  

想使用数组元素时,必须强制转换,相对来说麻烦

集合框架
        toArray(T[] a) 
            返回包含此集合中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型 

 为了避免强制转换这一步操作调用重载方法,传一个元素类型的数组对象即可,数组第项的长度任意。

只是传一个数组对象

集合框架

Collection子接口:List与Set,Queue

    集合框架

List为collection的子接口,有实现类3种,根据需求不同可以指向不同的实现类。

List指的是表类型,每个元素都有自己的索引,即下标。

集合框架

常用方法:

          void add(int index,E element)
            将某一元素,插入到此集合的下标index处,添加顺序就是集合中的顺序

集合框架
        E get(int index)
            返回指定下标上的元素

集合框架

输结果为:

   集合框架
        int indexOf(Object o)
            返回指定元素第一次出现的位置,如果没有返回-1;

集合框架

集合框架

输结果为:

第一个:集合框架

第二个: 集合框架

  int  lastIndexOf(Object o)

           最后一次出现的下标,如果此列表不包含元素,  则返回-1

集合框架

结果为:

集合框架

  E remove(int index)

           移除索引元素,返回移除元素

集合框架

结果:

集合框架

  E set(int index , Object obj)

           将下标index的元素替换成obj,返回被替换元

集合框架

结果为:

集合框架

  sublist(fromindex, endIndex

           截取操作,截取的是父类的一部分,对截取的更改,父类也一起变化

首先新建集合存入1~10,在新建一个集合接收集合1截取的部分,分别输出,之后将截取的部分元素都*10,

再输出,会发现之前集合元素的数据也发生了改变

集合框架

结果为

集合框架

sublist()方法所截取的是集合一部分,不会产生另外一个对象,截取的集合使用的是原集合中元素

集合框架
    2、数组转集合
        List Arrays.asList(数组参数);
        注意:数组转成的集合,不能进行增删操作,
        否则会出现运行时异常java.lang.UnsupportedOperationException
        可以进行替换操作,但是会对数组变量有影响
        如果想要成功进行增删操作,可以将元素存到新的集合中。

集合框架

对集合元素进行增删,会出现非检查性异常

集合框架

集合框架

对集合元素进行替换,会影响到原数组

集合框架

LinkedList:双链表结构,双链表的每一个元素都存有上一个元素和下一个元素的下标,这样在遍历或者查找元素时

效率没有Array List的高,在增删操作时,双链表断开链子将元素插入到相应的下标,再将链子连接上

而ArrayList插入元素时,相应下标后的元素都需要移动,效率要低

Vector:是一个比较古老的集合类型,线程安全,但是效率特别低,虽然安全,但是不建议使用

集合框架

有时候我们想要查看数组的元素,一个一个元素的取出来查看太麻烦,所以也就有了迭代器的概念

数组遍历有三种方式:

       1、经典for循环,也就是正常使用的for循环,循环输出数组中的每一个元素

       2、增强for循环,底层使用迭代器原理,也叫for-each循环

        格式为:

                for(数组元素类型 变量:要遍历的集合或者数组){
                        输出操作
                 }

集合框架

                 与经典for循环的区别:    
                            1、增强for循环中,无法使用下标,
                            2、经典for循环可以使用下标,跟下标有关的逻辑

      3、Iterator迭代器接口;
            1、迭代器的作用是用来遍历集合元素。是一个接口,Collection
                  提供一个方法Iterator iterator()
            2、Collection的实现类使用内部类定义了迭代器子类
            3、迭代器提供了统一的方法,用于遍历集合子类
     常用方法:
        boolean hasNext():
            判断集合中是否有下一个元素
        E next()
            取出集合中的下一个元素
            java.util.NoSuchElementException

在使用迭代器时,一般都先询问有没有下一个元素,如果有再进行不取操作,

如果不询问直接取,可能会出现异常集合框架,找不到元素
        remove(Object obj)
            注意:在使用迭代器对集合进行遍历时,不能使用集合的方法移除集合的元素
            必须使用迭代器自己提供的方法才行,

            如果使用集合的remove方法,会出现非检查性异常:集合框架

集合框架

接口Queue

集合框架

接口Queue:因为经常有增删操作,所以实现类为LinkedList,效率高一些
    Queue也是Collection的子接口,是队列的一种数据结构
    队列:通常都是一端进(offer),另一端出(poll)
     进出原则:FIFO  类似于排队先结束的先出去
    因为队列要经常进行增删操作,所以使用LinkedList来实现了Queue接口

集合框架
    常用的方法:
        boolean offer(E e)
            元素从队尾进入队列
        E poll()
            从队首移除元素,返回被移除的元素
            当队列没有元素时,返回null
        E peek()
            查看队首元素,不移除,队列中没有元素时,返回null
            注意:为了避免移除队列的队首时出现null,我们最好先查看队首是不是null

集合框架

接口Deque:是Queue的子接口,实现的是双端队列的数据结构

实现类也是LinkedList,  栈的数据结构:先进后出:FILO,类似于羽毛球桶,先放进去的最后取出来
    双端队列:两端都可以进也都可以出
        E offerFirst()
        E offerLast()
        E pollFirst()
        E pollLast()
        E peekFirst()
        E peekLast()

集合框架
        我们可以将双端队列的一端进行进制操作,另一端进或出,即Stack,是双端队列的一种特殊形式
        push(E e)
            将元素e推进栈中
        pop()
            将栈中的最后进来的元素移出。

集合框架

运行结果:

集合框架

在集合中,有时会需要比较大小的操作,而集合中都是引用类型的,我们无法正常的比较大小,

所以设计了比较接口,比较方法有三种

一、Compareble接口:
    定义类时实现Compareable接口,实现接口内的方法compareTo(E e),实现此接口的类型的对象之间可以进行比较

集合框架
之后重写方法int compareTo(E e):
     集合框架
    比较规则:
        (1)this与e比较,this-e 升序
        (2)    e-this,降序排序
二、工具类Collections
    提供了一个sort(Collection c)方法,
    对集合里的元素进行排序
    集合框架
   运行结果:

集合框架
三、Comparator比较器接口
    如果元素类型已经实现了Comparable接口,定义了默认的比较
    之后,在想换其他的比较规则时,不能改源码,可以利用比较器
    来重新定义比较规则
    实现一个比较器对象,重写方法: int compare(E o1,E o2);,

    因为比较器对象只需要使用一次,或者说只需要定义一次,所以一般都会使用匿名内部类来定义

集合框架
        比较规则:
        升序:o1-o2
        降序:o2-o1

Set接口:底层使用的是Map,只存储key部分,value不存

       特点
        1、无序,存储的元素与添加顺序无关
        2、不可重复,一个对象不可以放两次,长的一样的不能放进来
            使用元素的equals方法来判定是否重复
        3、能存储null元素,只能存一次
    Set集合添加或存储元素时,当集合中的元素过多时,就会进行多次的比较,效率变低
    在设计元素时,提供hash算法,用于返回对象的一个int值。
    在内存中开辟很多小的区间,用于存储一定范围返回值的对象当我们想添加元素或查看元素,

    先计算此元素的返回值,然后去相应区域中查找遍历。如果在这个区域没有找到对象,说明集合中可以存
    这个对象,如果有,然后查看两个对象的equals的返回值
            如果为true,不能添加
             如果为false,可以添加,可以添加,添加至对应的链表结构中(尽可能的避免发生)

几个例子:将set集合所占的空间比喻成一个广场,将去广场的人比喻成我们要存储的对象,

        将jvm比喻成管理广场的人,当广场上来了一个人,告诉管理人员说我要去跳广场舞,管理人员就会告诉

       你去广场的哪个区域,也就是对象通过jvm计算一个hash值,将对象分配了区域,

       有个孩子过来说,我要跳皮筋,也会有一块区域去跳皮筋。这时,有个男人找来找这个孩子,

       管理的人就会告诉他孩子在跳皮筋那块区域,也就是通过计算hash值,可以很快的找到对象存储的区域,

       之后男的来到了这片区域,看看哪个是要找孩子,怎么看谁是?肯定是长得像的,用到了equals方法,

       比较出来是不是要找的孩子,没有就是不在,有就找到了。还有一种情况,假设有一个一模一样的孩子来了说要跳皮筋

       管理人一看,这不是刚才进去的么,就不会让他去了,也就是说,两个相同的对象不能存入set集合中。

集合框架

重写HashCode方法:
    重写规则:尽可能的让所有的成员变量都参与运算,
        尽可能的避免值重复,自动生成的方法,其中使用了素数,是碰撞的可能性降到很低

集合框架
    注意:
        重写的必要性:
            1、如果重写了equals方法,有必要重写HashCode方法
            2、如果equals方法返回true,HashCode的返回值有必要一样
            3、如果equals方法返回false,HashCode的返回值,不一定相同
                如果返回值不同,可以提高检索的效率
        反过来说:
            1、HashCode值相同的时候,equals方法可能不同
            2、Hashcode值不同的时候,equals方法一定不同

Set接口派生出的子类
    HashSet:通过实现hash算法的一种数据结构
        无序,不重复

集合框架

结果:元素随机存放,不一定与存入的顺序一致

集合框架
    LinkedHashSet:通过实现Hash算法的一种数据结构,
            但是,通过链表来维持顺序,顺序与添加顺序一致
    TreeSet:使用了二叉树的一种数据结构,顺序与添加顺序一致。
            顺序与自然排序有关系,支持定制排序

集合框架

结果为:输出的结果是排列好顺序的,底层二叉树就是一种排序结构,

集合框架

Set集合的遍历:
    因为Set集合是无续的,无下标可言,因此不能使用经典for循环
    我们可以使用迭代器
        1、调用集合的Iterator方法获取迭代器

集合框架
        2、使用foreach循环

集合框架
    Set集合的元素:
        不能轻易修改参与hashCode运算的成员变量,否则容易引起内存溢出
        原因:成员变量修改后,会出现新的hash值,但是存储位置
        还是在原hash值的位置上,因此操作时,找不到具体的存储位置,

        过多的这样的元素会占用内存,最后堆满内存,如果更改的想要再删除

       需要将修改的改回原来的

先定义数组并存入元素

集合框架

之后修改c2的值

集合框架

进行删除操作:

集合框架

结果为:并没有删除

集合框架

之后将修改改回来,再做删除:

集合框架

集合框架

Map集合:集合框架中的另一个父接口
    Map集合:用于存储,一一对应的元素数据,第一个对象可以作为索引
    第二个对象作为值,我们称之为key-value,键值对。
    存储数据的特点:
        1、以key-value的形式进行存储
        2、key与value都必须是引用类型
        3、key可以为null
        4、key与value是单向一对一映射,一个key对应一个value,一个value可以对应多个key
        5、key不能重复
    存储机制:
        Map是基于数组和链表的数据结构,进行存储数据的
        作为key的元素采用了hash算法计算在数组(即散列数组,散列桶)的位置上;
        如果数组计算出来的位置,数组中此位置没有元素,就可以添加到散列桶内
        如果有元素,key的equals方法返回值为false时,就会存储在散列桶元素对应的单项链表中
        key的equals方法返回值为true时,就进行替换(覆盖)
        PS:使用Map集合,作为key的数据类型应该重写equals和HashCode
    常用方法:
        value put(K key,V value)
            用于存储一对key-value,返回被替换的value值
            如果不是替换,就返回null。

集合框架

    如果再存一个数学和分数,

集合框架

之前的数学分数就会被替换掉

集合框架
        V get(K k)
            作用:通过key对象,获取相应的value对象,如果集合中没有此key
            返回null。

集合框架
    map集合的遍历
        Set<K> keySet()
            用于获取map中所有的key对象,返回是一个set集合

集合框架
        Set<Entry<k,y> entrySet();
            将key-value封装成内部类对象,返回对象的set集合

集合框架
        Collection<V> values();
            将map集合中的所有value封装到Collection集合中

集合框架
    装载因子(扩容的时机)和HashMap的优化
        装载因子:DEFAULT_LOAD_FACTOR = 0.75f
        默认容量:DEFAULT_INITIAL_CAPACITY
                  16,就是数组的容量
        元素个数:size
        当我们创建一个HashMap对象时,底层数组的初始容量为16,当存
        个数size/DEFAULT_INITIAL_CAPACITY等于DEFAULT_LOAD_FACTOR
        数组开始扩容,此时最佳
        如果小于0.75扩容,比较占内存
        如果大于0.75扩容,操作的元素比较多
Map接口的子类:
    HashMap与HashTable的区别:
        1、hashTable是一个古老的类,不建议使用
        2、HashTable是一个线程安全的类,HashMap线程不安全
        3、HashTable的key不能是null,HashMap可以是null
    LinkedHashMap:是HashMap子类,使用链表来维护key-value的顺序
            在迭代时顺序与添加顺序一致。
    TreeMap:
        是SortedMap子接口的实现类,使用了二叉树的数据结构维护
        填入集合的顺序,将比较器实现类传入TreeMap的构造器即可更改
            1、自然排序:往TreeMap里添加的key对象,可以实现comparable接口
                compareTo方法。
            2、定制排序:作为key对象的数据类型可以不实现Comparable接口
                需要创建一个比较器对象Comparator,实现compare方法

集合框架
    Properties:
        是HashTable的子类型,用于封装属性文件的key-value信息
        因为在文件里写的都是字符串,因此Properties的key与value
        都是字符串类型

通过key-value来文件中的数据

集合框架

集合框架

结果

集合框架