黑马程序员—javaSE—Collection集合

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

一、集合框架
1. 对象数组的概述和使用
数组和集合存储引用数据类型,存的都是地址值。

数组特点:
    数组的长度固定。
    一个数组的元素类型一致。
    数组既可以存储基本数据类型,也可以存储引用数据类型。
  1. 集合的由来及集合继承体系图(掌握)

    集合的特点:
    长度可变
    集合可以存储任意引用数据类型 (Object – 泛型)
    集合只能存储引用数据类型

    单列结合的体系:
    Collection
    |– List : 元素有序(存储和取出的顺序一致),可重复
    |– ArrayList 底层数据结构:数组
    |– Vector 底层数据结构:数组
    |– LinkedList 底层数据结构:链表

    |-- Set : 元素无序(存储和取出的顺序不一致),唯一
        |-- HashSet     底层数据结构:哈希算法
        |-- TreeSet     底层数据结构:二叉树
    

    集合体系的学习方法:
    学习顶层:因为顶层定义的是体系的共性内容。
    使用底层:因为底层才是集合的具体实现。

  2. Collection集合的基本功能测试(掌握)

    添加:
    boolean add(Object obj)
    – 是否添加成功
    删除:
    boolean remove(Object obj)
    – 是否删除成功
    void clear()
    – 清空
    判断:
    boolean isEmpty()
    – 是否为空
    boolean contains(Object obj)
    – 是否包含指定元素

    长度:
    int size()
    – 长度

    转换:
    String toString()
    Object[] toArray()

    字符串长度: length()
    数组长度: length属性
    集合长度: size()

  3. 集合的遍历之集合转数组遍历(理解)

    注意:返回是Object数组。也就是说元素存入集合有一个向上提升数据类型的默认操作,提升为Object类型。
    那么转换成数组的时候就只能是转换成Object数组。

    Object[] objs = c.toArray();
    for (int x = 0; x < objs.length; x++) {
    Object obj = objs[x];
    }

  4. Collection集合带All的功能测试(理解)
    简单整理下:
    boolean addAll(Collection c)
    将指定Collection中的所有元素都添加到调用方法的Collection中,返回值表示调用方法的Collection是否发生改变。
    boolean removeAll(Collection c)
    移除调用方法的Collection中的那些也包含在指定Collection中的所有元素(删除交集),返回值表示调用方法的Collection是否发生改变。
    boolean containsAll(Collection c)
    判断调用方法的Collection中是否包含指定Collection中所有的元素,全部包含才返回true。
    boolean retainAll(Collection c)
    仅保留调用方法的 collection 中那些也包含在指定 collection 的元素(保留交集),返回值表示调用方法的Collection是否发生改变。
    例如:A对B做交集,A保留交集内容,B不变。返回值表示A是否发生改变。

  5. 集合的遍历之迭代器遍历(掌握)
    // 创建集合对象
    // 创建元素对象并添加

    // 迭代器遍历
    // 通过集合对象获取迭代器
    Iterator it = c.itertor();

    // 判断是否有下一个元素并获取
    while(it.hasNext()){
        Obejct obj = it.next();
    }
    
    练习:
        1:首先定义一个标准学生类(name,age属性)
        2:用集合存储3个学生,然后遍历集合。打印出每个学生的name和age。
    
  6. 迭代器的原理及源码分析
    不同集合的数据结构是不一样的,这就造成了不同的集合存取元素的方式是不一样的。那么直接将迭代器定义为普通实现类是不合适的。
    但是不管什么样的集合,又都需要提供遍历功能(也就是都要有判断是否包含下一个元素的功能,有获取下一个元素的功能),
    那么有相同的功能,但实现不一样,这时把功能提取出来定义到接口里面(规则的体现)。而在具体的集合类里面实现这个接口即可。

    而又由于集合存储数据的方式集合本身最清楚,也就是说迭代器里面的功能如何实现是要依赖于集合的数据结构。
    那么这时就把迭代器的具体实现定义在了集合的内部,以内部类的方式实现。

    原则:对修改关闭,对扩展开放

二、List集合
1. List集合的特有功能概述和测试(掌握)
添加:
void add(int index, Object element)
– 在指定的位置添加元素
删除:
Object remove(int index)
– 根据索引删除,返回被删除掉的元素

修改:
    Obejct set(int index, Object element)
        -- 修改指定索引处的元素,返回被替换掉的
获取:
    Object get(int index)
        -- 返回指定索引处的元素

List体系的普通for循环遍历        
for(int x = 0; x < list.size(); x++) {
    Object obj = list.get(x);
}
  1. List集合存储学生对象并遍历(掌握)

    我有一个集合,然后往里边添加hello,world,java三个元素,
    我想判断里面有没有“world”这个元素。
    如果有,我就添加一个“javaee”元素,没有什么都不添加。

    注意:用迭代器来做。

  2. 并发修改异常产生的原因及解决方案(掌握)
    ConcurrentModificationException – 并发修改异常

    原因:
        用迭代器遍历集合,又使用集合改变了集合的结构,这样的修改就是并发修改,是不被允许。
    解决方案:
        a. 用普通for遍历集合,判断然后改变集合的元素。元素添加到最后面。
        b. 使用列表迭代器ListIterator。(用List的特有迭代器遍历,并使用它添加元素),这时元素添加到匹配的元素后面。
    

    开发原则:尽量不要在遍历集合的同时去改变集合的结构。(隐患)

  3. ListIterator

  4. Vector的特有功能(了解)
    Vector是线程安全的(同步的),效率低

    了解API的发展特点
    安全 – 效率
    简化书写

  5. 数据结构之数组和链表
    数组:查询快,增删慢
    链表:查询慢,增删快

    数组的长度固定的,增删一个元素必须新建数组

  6. List的三个子类的特点
    |– List : 元素有序(存储和取出的顺序一致),可重复
    |– ArrayList
    底层数据结构:数组 – 查询快,增删慢
    线程不安全的,效率高
    |– Vector
    底层数据结构:数组 – 查询快,增删慢
    线程安全的,效率低
    |– LinkedList
    底层数据结构:链表 – 查询慢,增删快
    线程不安全的,效率高

    如果查询多,选ArrayList
    如果增删多,选LinkedList

    – 如果什么都不知道(或者如果都多),选ArrayList

一、ArrayList
1、去除ArrayList中重复字符串元素方式

    定义新集合的方式:
        定义一个新的ArrayList集合;
        遍历旧集合,获取到每一个元素,将其添加到新集合,
        在添加之前做判断,判断新集合是否已经包含了该元素,如果不包含,才添加。


2、去除ArrayList中重复自定义对象元素
    思路与上面相同。
    注意事项:contains方法底层依赖元素所属类的equals方法,所以去重写equals方法,实现具体属性值的比较。


补充练习:
    去除ArrayList中所有的指定元素。
    ArrayList al = new ArrayList();
    al.add("aaa");
    al.add("aaa");
    al.add("aaa");
    al.add("bbb");
    al.add("ccc");
    al.add("aaa");
    al.add("aaa");
    al.add("ccc");

    需求:去除所有的字符串“aaa”

    实现方式1:
        列表迭代器遍历集合,并使用列表迭代器删除匹配的元素
    实现方式2:
        用普通for循环正向遍历集合,一旦删除元素,循环索引--,保证元素全部能遍历到。
    实现方式3:
        用普通for循环倒着遍历集合,删除匹配的元素。这样不会有遗漏。
    。。。(多种方式,欢迎思考)

二、LinkedList
1、LinkedList的特有功能
void addFirst(Object obj) – 添加到开头
void addLast(Object obj) – 添加到结尾

    Object removeFirst() -- 删除第一个元素,并返回
    Object removeLast() -- 删除最后一个元素,并返回

    Object getFirst() -- 获取第一个元素
    Object getLast() -- 获取最后一个元素

2、栈和队列数据结构
    栈:后进先出(LIFO表)
    队列:先进先出(FIFO表)

3、用LinkedList模拟栈数据结构的集合并测试
    要提供自定义的类,实现元素的添加和删除等功能,这些功能要符合栈的结构特点。
    而底层采用谁来实现,那是你自己的事了,我不关心。而这个案例恰好可以用LinkedList来实现。

    注意事项:不要把自定义的类起名字为Stack。API上有。

三、泛型
1、泛型(generic)概述和基本使用
泛型把明确数据类型的操作放到创建对象或者调用方法的时候再明确。

    JDK1.5之后的新特性。

    格式:
        <引用数据类型>

    好处:
        泛型保证集合中的数据类型一致,提高安全性。把运行期异常提前到编译期。


    那么在JDK1.5之前怎么实现参数的任意化呢?
        是通过接收Object类型的参数实现的。因为任意类直接或间接继承自Object。
        但这样实现的缺点就是,还是不能保证数据类型的安全一致。
        Object obj1 = new Student();
        Object obj2 = new Teacher();
        上面两个对象都声明为Object类型,那获取元素的时候到底该如何转型呢?还是存在问题。
    应用:
        泛型类
        泛型接口
        泛型方法

2、ArrayList存储字符串和自定义对象并遍历泛型版

3、泛型的由来

    补充:泛型擦除
    查看下述两个方法:
        public void show(ArrayList<String> list) {}

        public void show(ArrayList<Integer> list){}

    /*
     * 上述两个方法是不会形成方法的重载的,会报方法已存在的错误。 原因:泛型擦除
     * 泛型是1.5中引入的一个新的概念,由于不用进行强制转换类型了,所以具有较高的安全性和易用性。
     * 因为泛型其实只是在编译器中实现的而虚拟机并不认识泛型
     * ,所以要在虚拟机中将泛型类型进行擦除。也就是说,在编译阶段使用泛型,运行阶段取消泛型,即擦除。
     * 擦除是将泛型类型以其父类代替,如String变成了Object等。
     * 其实在使用的时候还是进行带强制类型的转化,只不过这是比较安全的转换,因为在编译阶段已经确保了数据的一致性。
     */

4、泛型类的概述及使用
    明确数据类型的工作放到了创建对象的时候

5、泛型方法的概述和使用
    明确数据类型的工作放到了调用方法的时候

    方法泛型 <> 加在返回值前面。

6、泛型接口的概述和使用
    一种是子类实现接口的时候明确数据类型
        interface Fu<T>{}

        class Zi implements Fu<String>{}

    一种是子类继续使用泛型:
        class Zi<T> implements Fu<T>{}

7、泛型高级之通配符

    <?> -- 泛型通配符
    <? extends E> -- 向下限定,接收E及其子类类型
    <? super E> -- 向上限定,接收E及其父类类型

四、集合加强
1、增强for的概述和使用(foreach)
格式:
for(数组或者Collection集合中元素类型 变量名 :数组或者Collection集合对象){
//直接使用变量名即可
}
注意:增强for底层是迭代器实现的,不要使用增强for的同时用集合改变结构,会报并发修改异常。

2、ArrayList存储自定义对象并遍历增强for版

3、三种迭代的能否删除
    a.普通for正向遍历,可以删除,但要注意,一旦删除了元素,索引要减1.
        for(int i = 0; i < list.size();){
            if("b".equals(s)){
                list.remove(i);
                continue;
            }
            i++;
        }

    b.迭代器遍历,也可删除,但是注意要使用迭代器的删除方法。

    c.增强for遍历时,不能删除元素。


4、静态导入的概述和使用
    对于静态方法,导入到方法的级别

    格式:
        import static 包名.类名.方法名;

5、可变参数的概述和使用
    适用于参数类型明确但个数不确定的情况。

    注意:方法里面有多个参数,那么可变参数必须放到最后。

6、Arrays工具类的asList()方法的使用

    数组转换成集合;
        public static <T> List<T> asList(T... a)
        转成集合后大小固定,不支持增加或者删除操作。

        引用数据类型数组 -- 把数组中的元素作为集合中的元素。
        基本数据类型数组 -- 把数组对象作为一个元素添加到了集合中。

    集合转数组:
        Object[] toArray() -- 把集合转换成Object[]

        <T> T[] toArray(T[] a) -- 把集合转换成了指定数据类型的数组
            -- 如果数组长度小于等于集合,那么返回数组的长度是集合的长度
            -- 如果数组长度大于集合,那么返回的数组长度是指定的长度,前面保存集合中的元素,后面存储的是null。

7、集合嵌套之ArrayList嵌套ArrayList

    // 创建学科集合对象

        // 创建班级1集合对象

            // 创建几个学生对象放进班级1

        // 创建班级2集合对象

            // 创建几个学生对象放进班级2

    // 把班级1和2放进学科集合对象

    // 遍历
        // 遍历学科对象得到的是每一个班级集合

            // 遍历每一个班级集合得到的是每一个学生

一、HashSet集合
1、HashSet存储字符串并遍历
Set体系无序无索引,可以使用迭代器或者增强for遍历。

2、HashSet存储自定义对象保证元素唯一性

    HashSet存储自定义对象保证元素唯一依赖于元素所属类的hashCode() 和 equals() 方法。

3、HashSet存储自定义对象保证唯一性图解及优化  
    如何重写hashCode()
        自己写的话:一般情况下是返回所有属性的hashCode值相加(引用数据用hashCode(),基本数据直接用值)。
        例如:name.hashCode() * 117 + age * 19;

4、HashSet如何保证元素唯一性的原理

    整体理解:
        元素存入HashSet集合时,会先走hashCode()方法,判断元素与集合中已经存在的元素的hash值。
        如果不同,元素不重复,添加。不再执行equals方法。
        如果相同,再去执行equals方法,如果equals返回true,认为元素重复,不添加。
        如果equals返回false,元素不重复,添加。

5、LinkedHashSet的概述和使用
    LinkedHashSet 存取有序,且元素唯一。

6、产生10个1-20之间的随机数要求随机数不能重复

7、练习 - 使用Scanner从键盘读取一行输入,去掉其中重复字符

    // 遍历字符串
    char charAt(int index)

    for(int x = 0; x < str.length(); x++){
        char ch = str.charAt(x);
    }


8、练习 - 去除ArrayList集合中的重复字符串元素
    使用LinkedHashSet

二、TreeSet集合
1、TreeSet存储Integer类型的元素并遍历
TreeSet 保证元素唯一,并且可以实现排序。 – 自然顺序

2、TreeSet存储自定义对象
    TreeSet存储自定义对象实现排序的方式1:
        自然排序 -- 让元素具备比较性:
            元素所属类实现Comparable接口,重写compareTo()方法。
        根据compareTo()返回值:
            返回0,元素重复,不添加。
            返回正数,元素往后放。
            返回负数,元素往前放。

        元素取出的时候是按照左中右的原则取出的。

3、TreeSet保证元素唯一和自然排序的原理和图解

    底层源码是建立在二叉树的基础上,但不是最简单的二叉树。自平衡二叉树。

4、TreeSet存储自定义对象并遍历练习1 -- 按姓名排序

5、TreeSet存储自定义对象并遍历练习2 -- 按照姓名的长度排序

6、TreeSet保证元素唯一和比较器排序的原理

    TreeSet存储自定义对象实现排序的方式2:
        比较器排序 -- 让集合具备比较性:
            定义个一个类实现Comparator,重写compare() 方法
            使用的是TreeSet的带参数(带比较器参数的)构造

7、TreeSet原理 - 两种排序方式总结

8、练习 - 对ArrayList集合中的元素排序且不能去除重复元素

9、练习 - 键盘录入字符串,实现对字符进行排序

10、练习 - 键盘录入整数,实现倒序打印
    注意 :键盘录入要自定义结束标记

11、练习 - 键盘录入学生信息,按照总分排序后输出在控制台
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值