JavaSE 进阶 - 第22章 集合(1)

1、集合概述

1.1、什么是集合?有什么用?
  • 数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它类型的数据。

  • 集合为什么说在开发中使用较多?
      集合是一个容器,是一个载体,可以一次容纳多个对象。
      在实际开发中,假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来。

1.2、集合不能直接存储基本数据类型,也不能直接存储java对象,
  • 集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)
      list.add(100); //自动装箱Integer
    注意:
      集合在java中本身是一个容器,是一个对象。
      集合中任何时候存储的都是“引用”。
    在这里插入图片描述
1.3、在java不同的集合,底层会对应不同的数据结构
  • 在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储元素,等于将数据放到了不同的数据结构当中。
  • 什么是数据结构
      数据存储的结构就是数据结构。
      不同的数据结构,数据存储方式不同。例如:
        数组、二叉树、链表、哈希表…
        以上这些都是常见的数据结构。

    往集合c1中放数据,可能是放到数组上了。
    往集合c2中放数据,可能是放到二叉树上了。
    …
    使用不同的集合等同于使用了不同的数据结构。

    在java集合这一章节,需要掌握的不是精通数据结构。java中已经将数据结构实现了,已经写好了这些常用的集合类,只需要掌握怎么用?在什么情况下选择哪一种合适的集合去使用即可。

    new ArrayList(); 创建一个集合,底层是数组。
    new LinkedList(); 创建一个集合对象,底层是链表。
    new TreeSet(); 创建一个集合对象,底层是二叉树。
    …

1.4、所有的集合类和集合接口都在java.util包下
1.5、在java中集合分为两大类:
  • 第一类:是单个方式存储元素:
    单个方式存储元素,这一类集合中超级父接口:java.util.Collection;

  • 第二类:是以键值对儿的方式存储元素
    以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;

1.6、【集合的继承结构图】——>(背会)
  • 集合整个这个体系是怎样的一个结构,需要有印象,为了掌握集合这块的内容,最好能将集合的继承结构图背会!
  • 注意:该结构图中只画了开发过程中主要用的几个接口和实现类,并不是说只有这几个!!
  • 另外,这两张表是一个最终的表,对于表中不懂的部分可以先放下,学完后面的内容就懂了。
    集合继承结构图1
    集合继承结构图2

2、java.util.Collection接口中常用方法

2.1、Collection中能存放什么元素?
  • 没有使用“泛型”之前,Collection中可以存储Object的所有子类型。
  • 使用了“泛型”之后,Collection中只能存储某个具体的类型。
    集合后期会学习“泛型”语法。目前先不用管。Collection中什么都能存,只要是Object的子类型就行。(集合中不能直接存储基本数据类型,也不能存java对象,只是存储java对象的内存地址。)
2.2、Collection中的常用方法
  • boolean add(Object e) ————向集合中添加元素
  • int size() ————获取集合中元素的个数
  • void clear() ————清空集合
  • boolean contains(Object o) ————判断当前集合中是否包含元素o,包含返回true,不包含返回false
  • boolean remove(Object o) ———— 删除集合中的某个元素。
  • boolean isEmpty() ————判断该集合中元素的个数是否为0
  • Object[] toArray() ————调用这个方法可以把集合转换成数组。【作为了解,使用不多。】
import java.util.ArrayList;
import java.util.Collection;

public class CollectionTest01 {
    public static void main(String[] args) {
        // 创建一个集合对象
        //编译器报错:接口是抽象的,无法实例化。
        //Collection c = new Collection();
        // 多态
        Collection c = new ArrayList();

        // 测试Collection接口中的常用方法
        c.add(1200); // 自动装箱(java5的新特性。),实际上是放进去了一个对象的内存地址。Integer x = new Integer(1200);
        c.add(3.14); // 自动装箱
        c.add(new Object());
        c.add(new Student());
        c.add(true); // 自动装箱

        // 获取集合中元素的个数
        System.out.println("集合中元素个数是:" + c.size()); // 5

        // 清空集合
        c.clear();
        System.out.println("集合中元素个数是:" + c.size()); // 0

        // 再向集合中添加元素
        c.add("hello"); // "hello"对象的内存地址放到了集合当中。
        c.add("world");
        c.add("浩克");
        c.add("绿巨人");
        c.add(1);

        // 判断集合中是否包含"绿巨人"
        boolean flag = c.contains("绿巨人");
        System.out.println(flag); // true
        boolean flag2 = c.contains("绿巨人2");
        System.out.println(flag2); // false
        System.out.println(c.contains(1)); // true

        System.out.println("集合中元素个数是:" + c.size()); // 5

        // 删除集合中某个元素
        c.remove(1);
        System.out.println("集合中元素个数是:" + c.size()); // 4

        // 判断集合是否为空(集合中是否存在元素)
        System.out.println(c.isEmpty()); // false
        // 清空
        c.clear();
        System.out.println(c.isEmpty()); // true(true表示集合中没有元素了!)

        c.add("abc");
        c.add("def");
        c.add(100);
        c.add("helloworld!");
        c.add(new Student());

        // 转换成数组(了解,使用不多。)
        Object[] objs = c.toArray();
        for(int i = 0; i < objs.length; i++){
            // 遍历数组
            Object o = objs[i];
            System.out.println(o);
        }
        /*
        abc
        def
        100
        helloworld!
        com.bjpowernode.javase.collection.Student@3e3abc88
         */
    }
}

class Student{
}

3、关于集合遍历/迭代

  • Iterator 接口,是对 collection 进行迭代的迭代器。Iterator 称为迭代接口,通过此接口可以遍历集合中的数据。
  • 迭代器对象Iterator中的方法:
    boolean hasNext()——如果仍有元素可以迭代,则返回 true。
    Object next() ——返回迭代的下一个元素。
    void remove() ——从基础集合中移除这个迭代器返回的最后一个元素(可选操作)。
  • 注意:以下讲解的遍历方式/迭代方式,是所有Collection通用的一种方式。
       在Map集合中不能用。只能在所有的Collection以及子类中使用。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionTest02 {
    public static void main(String[] args) {

        // 创建集合对象
        Collection c = new ArrayList(); // 后面的集合无所谓,主要是看前面的Collection接口,怎么遍历/迭代。
        // 添加元素
        c.add("abc");
        c.add("def");
        c.add(100);
        c.add(new Object());
        // 对集合Collection进行遍历/迭代
        // 第一步:获取集合对象的迭代器对象Iterator
        Iterator it  =c.iterator();
        // 第二步:通过以上获取的迭代器对象开始迭代/遍历集合。
        /*
            以下两个方法是迭代器对象Iterator中的方法:
                boolean hasNext()如果仍有元素可以迭代,则返回 true。
                Object next() 返回迭代的下一个元素。
         */
        while(it.hasNext()){
            Object obj = it.next();
            System.out.println(obj);
        }
    }
}
/*
abc
def
100
java.lang.Object@f6f4d33
 */
  • 迭代器是通用的
    Collection c1 = new ArrayList(); // ArrayList集合:有序可重复
    Collection c2 = new HashSet(); // HashSet集合:无序不可重复(迭代器取出的和存进去顺序不一定相同。)
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class CollectionTest03 {
    public static void main(String[] args) {
        // 创建集合对象
        Collection c1  = new ArrayList(); // ArrayList集合:有序可重复
        // 添加元素
        c1.add(1);
        c1.add(2);
        c1.add(3);
        c1.add(4);
        c1.add(1);

        // 迭代集合
        Iterator it = c1.iterator();
        while(it.hasNext()){
            // 存进去是什么类型,取出来还是什么类型。
            Object obj = it.next();
            /*if(obj instanceof Integer){
                System.out.println("Integer类型");
            }*/
            // 只不过在输出的时候会转换成字符串。因为这里println会调用toString()方法。
            System.out.println(obj);
        }
        /*有序可重复,存进去什么样,取出来还是什么样:
        1
        2
        3
        4
        1
         */

        // HashSet集合:无序不可重复
        Collection c2 = new HashSet();
        // 无序:存进去和取出的顺序不一定相同。
        // 不可重复:存储100,不能再存储100.
        c2.add(100);
        c2.add(200);
        c2.add(300);
        c2.add(90);
        c2.add(400);
        c2.add(50);
        c2.add(60);
        c2.add(100);
        Iterator it2 = c2.iterator();
        while(it2.hasNext()){
            System.out.println(it2.next());
        }
        /*存进去8个,输出来无序、不重复的7个:
        400
        50
        100
        200
        90
        300
        60
         */
    }
}
  • 迭代集合的原理:
    在这里插入图片描述

4、深入Collections的contains()方法与remove()方法

4.1 boolean contains(Object o)
  • 判断集合中是否包含某个对象o,如果包含返回true, 如果不包含返回false。

  • contains方法是用来判断集合中是否包含某个元素的方法,那么它在底层是怎么判断集合中是否包含某个元素的呢?
        调用了equals方法进行比对。(其中 String的equals方法sun公司已经重写了,比较的是内容,不是内存地址)
        equals方法返回true,就表示包含这个元素。

import java.util.ArrayList;
import java.util.Collection;

public class CollectionTest04 {
    public static void main(String[] args) {
        // 创建集合对象
        Collection c = new ArrayList();

        // 向集合中存储元素
        String s1 = new String("abc"); // s1 = 0x1111
        c.add(s1); // 放进去了一个"abc"

        String s2 = new String("def"); // s2 = 0x2222
        c.add(s2);

        // 集合中元素的个数
        System.out.println("元素的个数是:" + c.size()); // 2

        // 新建的对象String
        String x = new String("abc"); // x = 0x5555
        // c集合中是否包含x?结果猜测一下是true还是false?
        System.out.println(c.contains(x)); //判断集合中是否存在"abc" ——true
    }
}

注意:这里放进去的元素都是String类型,而String的equals方法sun公司已经重写了,比较的是内容,不是内存地址
在这里插入图片描述

4.2 boolean remove(Object o)
  • 删除集合中的某个元素。
  • remove()方法里面也调用了equals方法进行比对。
import java.util.ArrayList;
import java.util.Collection;

/*
测试contains方法
测试remove方法。
结论:存放在一个集合中的类型,一定要重写equals方法。
 */
public class CollectionTest05 {
    public static void main(String[] args) {
        // 创建集合对象
        Collection c = new ArrayList();
        // 创建用户对象
        User u1 = new User("jack");
        // 加入集合
        c.add(u1);

        User u2 = new User("jack");

        // 判断集合中是否包含u2

        // 没有重写equals之前:这个结果是false
        //System.out.println(c.contains(u2)); // false
        // 重写equals方法之后,比较的时候会比较name。
        System.out.println(c.contains(u2)); // true

        c.remove(u2); //移除c2,实际上也就是移除c1
        System.out.println(c.size()); // 0

        /*Integer x = new Integer(10000);
        c.add(x);

        Integer y = new Integer(10000);
        System.out.println(c.contains(y)); // true*/

        // 创建集合对象
        Collection cc = new ArrayList();
        // 创建字符串对象
        String s1 = new String("hello");
        // 加进去。
        cc.add(s1);

        // 创建了一个新的字符串对象
        String s2 = new String("hello");
        // 删除s2
        cc.remove(s2); // s1.equals(s2) java认为s1和s2是一样的。删除s2就是删除s1。
        // 集合中元素个数是?
        System.out.println(cc.size()); // 0
    }
}

class User{
    private String name;
    public User(){}
    public User(String name){
        this.name = name;
    }

    // 重写equals方法
    // 将来调用equals方法的时候,一定是调用这个重写的equals方法。
    // 这个equals方法的比较原理是:只要姓名一样就表示同一个用户。
    public boolean equals(Object o) {
        if(o == null || !(o instanceof User)) return false;
        if(o == this) return true;
        User u = (User)o;
        // 如果名字一样表示同一个人。(不再比较对象的内存地址了。比较内容。)
        return u.name.equals(this.name);
    }

}

【结论】:Collection接口中的remove方法和contains方法底层都会调用equals,存放在一个集合中的类型,一定要重写equals方法。

5、关于集合元素的remove

  • 重点:当集合的结构发生改变时,迭代器必须重新获取,如果还是用以前老的迭代器,
        会出现异常:java.util.ConcurrentModificationException

  • 重点:在迭代集合元素的过程中,不能调用集合对象的remove方法,删除元素:c.remove(o);
        迭代过程中不能这样。会出现:java.util.ConcurrentModificationException

  • 重点:在迭代元素的过程当中,一定要使用迭代器Iterator的remove方法,删除元素: it.remove();
        迭代器去删除时,会自动更新迭代器,并且更新集合(删除集合中的元素)。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionTest06 {
    public static void main(String[] args) {
        // 创建集合
        Collection c = new ArrayList();
        c.add("abc");
        c.add("def");
        c.add("xyz");

        // 注意:此时获取的迭代器,指向的是那是集合中没有元素状态下的迭代器。
        // 一定要注意:集合结构只要发生改变,迭代器必须重新获取。
        // 当集合结构发生了改变,迭代器没有重新获取时,调用next()方法时:java.util.ConcurrentModificationException
        Iterator it = c.iterator();
        while(it.hasNext()){
            Object o = it.next();
            // 删除元素

            // 删除元素之后,集合的结构发生了变化,应该重新去获取迭代器
            // 但是,循环下一次的时候并没有重新获取迭代器,所以会出现异常:java.util.ConcurrentModificationException
            // 出异常根本原因是:集合中元素删除了,但是没有更新迭代器(迭代器不知道集合变化了)
            //c.remove(o); // 直接通过集合去删除元素,没有通知迭代器。(导致迭代器的快照和原集合状态不同。)

            // 使用迭代器来删除可以吗?
            // 迭代器去删除时,会自动更新迭代器,并且更新集合(删除集合中的元素)。
            it.remove(); // 删除的一定是迭代器指向的当前元素。
            System.out.println(o);
        }
        System.out.println(c.size()); //0
    }
}
/*
abc
def
xyz
0
 */

传送门

上一章:JavaSE 进阶 - 第21章 异常
下一章:JavaSE 进阶 - 第22章 集合(2)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值