3Java加强----集合

1.认识集合

public class CollectionDemo2 {
    public static void main(String[] args) {
        // 目标:搞清楚Collection提供的通用集合功能。
        Collection<String> list = new ArrayList<>();

        // 添加元素
        list.add("张三");
        list.add("李四");
        list.add("王五");
        System.out.println(list); // [张三, 李四, 王五]

        // 获取集合的元素个数
        System.out.println(list.size());

        // 删除集合元素
        list.remove("李四");
        System.out.println(list);

        // 判断集合是否为空
        System.out.println(list.isEmpty()); // false

        // 清空集合
        // list.clear();
        // System.out.println(list);

        // 判断集合中是否存在某个数据
        System.out.println(list.contains("张三"));

        // 把集合转换成数组
        Object[] arr = list.toArray();
        System.out.println(Arrays.toString(arr));

        // 把集合转换成字符串数组(拓展)
        String[] arr2 = list.toArray(String[]::new);
    }
}

2.集合遍历方式

2.1迭代器遍历

public class CollectionTraversalDemo3 {
    public static void main(String[] args) {
        // 目标:掌握Collection的遍历方式一:迭代器遍历
        ArrayList<String> names = new ArrayList<>();
        names.add("张无忌");
        names.add("玄冥二老");
        names.add("宋青书");
//        names.add("殷素素");
        System.out.println(names); // [张无忌, 玄冥二老, 宋青书]
        //                                                      it

        // 1、得到这个集合的迭代器对象
        Iterator<String> it = names.iterator();
//        System.out.println(it.next());
//        System.out.println(it.next());
//        System.out.println(it.next());
//        System.out.println(it.next());
//        System.out.println(it.next()); // NoSuchElementException

        // 2、使用一个while循环来遍历
        while (it.hasNext()) {
            String name = it.next();
            System.out.println(name);
        }
    }
}

2.2增强for循环

public class CollectionTraversalDemo4 {
    public static void main(String[] args) {
        // 目标:掌握Collection的遍历方式二:增强for
        Collection<String> names = new ArrayList<>();
        names.add("张无忌");
        names.add("玄冥二老");
        names.add("宋青书");
        names.add("殷素素");

        for (String name : names) {
            System.out.println(name);
        }

        String[] users = {"张无忌", "玄冥二老", "宋青书", "殷素素"};

        for (String user : users) {
            System.out.println(user);
        }
    }
}

2.3Lambda表达式

public class CollectionTraversalDemo5 {
    public static void main(String[] args) {
        // 目标:掌握Collection的遍历方式三:lambda
        Collection<String> names = new ArrayList<>();
        names.add("张无忌");
        names.add("玄冥二老");
        names.add("宋青书");
        names.add("殷素素");


//        names.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });

//        names.forEach(s -> System.out.println(s));

        names.forEach(System.out::println);
    }
}

2.4三种遍历方式的区别(重点)

首先观察下面这段代码,会出现并发修改问题,当把宁夏枸杞删掉时,黑枸杞会补上来,这样就删不到黑枸杞了

后面的数据补上来会存在跨位问题

 // 目标:认识并发修改异常问题,搞清楚每种遍历的区别
        ArrayList<String> list = new ArrayList<>();
        list.add("Java入门");
        list.add("宁夏枸杞");
        list.add("黑枸杞");
        list.add("人字拖");
        list.add("特级枸杞");
        list.add("枸杞子");
        list.add("西洋参");
        System.out.println(list);

        // 需求1:删除全部枸杞
        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i);
            if(name.contains("枸杞")){
                list.remove(name);
            }
        }
        System.out.println(list);   //出现并发修改异常问题。
        // [Java入门, 宁夏枸杞, 黑枸杞, 人字拖, 特级枸杞, 枸杞子, 西洋参]
        // [Java入门, 黑枸杞, 人字拖, 枸杞子, 西洋参]
        //           i
        // [Java入门, 黑枸杞, 人字拖, 枸杞子, 西洋参]

解决方案一

删除完,做一个i--操作

ArrayList<String> list2 = new ArrayList<>();
        list2.add("Java入门");
        list2.add("宁夏枸杞");
        list2.add("黑枸杞");
        list2.add("人字拖");
        list2.add("特级枸杞");
        list2.add("枸杞子");
        list2.add("西洋参");
        System.out.println(list2);

        // 需求1:删除全部枸杞
        for (int i = 0; i < list2.size(); i++) {
            String name = list2.get(i);
            if(name.contains("枸杞")){
                list2.remove(name);
                i--; // 解决方案1:删除数据后做一步i--操作 (前提是支持索引)
            }
        }

解决方案二

倒着遍历并删除(前提是支持索引)

 ArrayList<String> list3 = new ArrayList<>();
        list3.add("Java入门");
        list3.add("宁夏枸杞");
        list3.add("黑枸杞");
        list3.add("人字拖");
        list3.add("特级枸杞");
        list3.add("枸杞子");
        list3.add("西洋参");
        System.out.println(list3);

        // 需求1:删除全部枸杞
        // 解决方案2:倒着遍历并删除(前提是支持索引)
        for (int i = list3.size() - 1; i >= 0; i--) {
            String name = list3.get(i);
            if(name.contains("枸杞")){
                list3.remove(name);
            }
        }
        // [Java入门, 人字拖, 西洋参]
        //     i
        System.out.println(list3);

解决方案三

当用set集合时,是没有索引的,就要想一下这三种方式能不能解决这个问题了

当使用迭代器时

 System.out.println("=====================================================");
        ArrayList<String> list4 = new ArrayList<>();
        list4.add("Java入门");
        list4.add("宁夏枸杞");
        list4.add("黑枸杞");
        list4.add("人字拖");
        list4.add("特级枸杞");
        list4.add("枸杞子");
        list4.add("西洋参");
        System.out.println(list4);

        // 需求1:删除全部枸杞
        // 方案一:迭代器遍历并删除默认也存在并发修改异常问题。
        // 可以解决,解决方案3:使用迭代器自己的方法来删除
        Iterator<String> it = list4.iterator();
        while(it.hasNext()){
            String name = it.next();
            if(name.contains("枸杞")){
                list4.remove(name);
            }
        }
        System.out.println(list4);

此时运行,会报错,但是可以解决,只需

使用迭代器自己的方法来删除当前数据(底层是可以记索引的)

 if(name.contains("枸杞")){
                it.remove();   // 可以解决 解决方案3:使用迭代器自己的方法来删除当前数据
            }


先说结论,
增强for循环和lambda表达式都无法解决这个问题

首先,增强for循环无法拿到迭代器对象,lambda表达式底层也是增强for循环,同理也拿不到迭代器对象.

2.4.1总结

如果又要遍历又要操作数据,且集合没有索引,只能用迭代器了

增强for和Lambda只适合做遍历,不适合做遍历并修改操作

3.List集合

小试牛刀

public class ListDemo1 {
    public static void main(String[] args) {
        // 目标:掌握List系列集合独有的功能。
        List<String> names = new ArrayList<>(); //实现类对象给到父接口

        // 添加数据
        names.add("张三");
        names.add("李四");
        names.add("王五");
        names.add("赵六");
        System.out.println(names); // [张三, 李四, 王五, 赵六]

        // 给第三个位置插入一个数据:赵敏
        names.add(2, "赵敏");
        System.out.println(names);

        // 删除李四
        System.out.println(names.remove(1)); // 根据下标删除,返回删除的数据
        System.out.println(names);

        // 把王五修改成:金毛
        System.out.println(names.set(2, "金毛")); // 根据下标修改,返回修改前的数据
        System.out.println(names);

        // 获取张三
        System.out.println(names.get(0));

        System.out.println("-----------四种遍历演示---------------");

        // 1、for循环
        for (int i = 0; i < names.size(); i++) {
            System.out.println(names.get(i));
        }

        // 2、迭代器
        Iterator<String> it = names.iterator();
        while (it.hasNext()) {
            String name = it.next();
            System.out.println(name);
        }

        // 3、增强for
        for (String name : names) {
            System.out.println(name);
        }

        // 4、lambda表达式
        names.forEach(name ->  System.out.println(name) );


        System.out.println(15 >> 1);
    }
}

3.1ArrayList底层原理

第一次加数据的时候才创建数组(扩容),扩容成10,加满之后,会扩容成原来的1.5倍

3.2LinkedList底层原理

而我们的LinkedList是基于双链表实现的

对收尾元素查询基本是O(0)

可以用来设计队列,因为只是在首尾增删元素

也可以用来设计栈

小试牛刀

public class ListDemo2 {
    public static void main(String[] args) {
        // 目标:用LinkedList做一个队列对象。
        LinkedList<String> queue = new LinkedList<>();
        // 入队
        queue.addLast("赵敏");
        queue.addLast("西门吹雪");
        queue.addLast("陆小凤");
        queue.addLast("石观音");
        System.out.println(queue); // [赵敏, 西门吹雪, 陆小凤, 石观音]

        // 出队
        System.out.println(queue.removeFirst());
        System.out.println(queue.removeFirst());
        System.out.println(queue);

        System.out.println("-------------------------------------------------");

        // 做一个栈
        LinkedList<String> stack = new LinkedList<>();
        // 压栈
        stack.push("第1颗子弹");
        stack.push("第2颗子弹");
        stack.push("第3颗子弹");
        stack.push("第4颗子弹");
        System.out.println(stack);  // [第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]

        // 出栈
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack);
    }
}

简答题

1.ArrayList的大小是如何自动增加的?

当有人试图在arraylist中增加一个对象的时候,Java会去检查arraylist,以确保已存在的数组中有足够的容量来存储这个新的对象。如果没有足够容量的话,那么就会新建一个长度更长的数组,旧的数组就会使用Arrays.copyOf方法被复制到新的数组中去,现有的数组引用指向了新的数组。

2.ArrayList和LinkedList的区别?

   a.List是接口类,ArrayList和LinkedList是List的实现类。

    b.ArrayList是动态数组(顺序表)的数据结构。顺序表的存储地址是连续的,所以在查找比较快,但是在插入和删除时,由于需要把其它的元素顺序向后移动(或向前移动),所以比较熬时。

    c.LinkedList是链表的数据结构。链表的存储地址是不连续的,每个存储地址通过指针指向,在查找时需要进行通过指针遍历元素,所以在查找时比较慢。由于链表插入时不需移动其它元素,所以在插入和删除时比较快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值