Day 08集合

集合

为什么要使用集合框架?

假设一个班有30个人,存储信息可以直接使用数组

但是如果不知道这个班有多少人的情况下,还能使用数组嘛?----->自己做数组扩容

集合框架内容

在这里插入图片描述

  • Collection接口:单列集合,用来存储一个一个对象
    • List接口:存储有序的,可重复的数据。------>动态数组
      • ArrayList,LinkList,Vector
    • Set接口:存储的无序的,不可重复的数据
      • HashSet,LinkedHashSet,TreeSet
  • Map接口:双列集合,用来存储一对(key-value)数据
    • HashMap,LinkedHashMap,TreeMap,HashTable

Collection接口中的常用方法

  • 添加

    add(Object obj)

    addAll(Collection c)

  • 获取有效元素的个数

    int size();

  • 是否为空集合

    boolean isEmpty()

  • 是否包含某个元素

    boolean contains(Object o):通过元素的 equals 方法判断是否是同一个对象

    boolean containsAll(Collection c):也是调用 元素的equals 方法来比较。拿两个集合的元素一一比较

  • 删除

    boolean remove(Object o):通过元素的equals 方法判断是否是要删除的元素。而且只会删除第一个出现的元素

    boolean removeAll(Collection c):取当前集合的差集

  • 取两个集合的交集

    boolean retainAll(Collection c):把交集的结果存在当前集合中

  • 集合是否相等

    boolean equals(Object o);

  • 集合转数组

    Object[] toArray()

  • 获取集合对象hash值

    int hashCode();

  • 遍历

    iterator():返回迭代器对象,用于遍历集合

用法一:collection.add(xxx);

public static void main(String[] args) {
        Collection collection = new ArrayList();

        //添加
        collection.add("AA");
        collection.add("BB");
        collection.add(123);//装箱

        System.out.println("有:" + collection.size() + "个数据");

        Collection collection1 = new ArrayList();
        collection1.add(123);
        collection1.add("CC");
        collection1.addAll(collection);
        System.out.println("有:" + collection1.size() + "个数据");
        System.out.println(collection1);

        collection1.clear();

        System.out.println(collection1.isEmpty());
    }

用法二:

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

}
public class PersonTest {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(123);
        collection.add(456);
        collection.add(new Person("herb", 20));
        collection.add(new String("eagle"));
        collection.add(false);

        boolean contains = collection.contains(123);
        System.out.println(contains);
        System.out.println(collection.contains(new String("eagle")));

        System.out.println(collection.contains(new Person("herb", 20)));//需要重新 equals

        //
        Collection collection3 = Arrays.asList(123, 4567);
        System.out.println(collection.containsAll(collection3));
    }
}

用法三:

public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(123);
        collection.add(456);
        collection.add(new Person("herb", 18));
        collection.add(new String("eagle"));
        collection.add(false);

        collection.remove(1234);
        System.out.println(collection);

        collection.remove(new Person("herb", 18));
        System.out.println(collection);

        //交集
        Collection collection3 = Arrays.asList(123, 456);
        collection.retainAll(collection3);
        System.out.println(collection);
    }
public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(123);
        collection.add(456);
        collection.add(new Person("herb", 18));
        collection.add(new String("eagle"));
        collection.add(false);

        Collection collection1 = new ArrayList();
        collection1.add(123);
        collection1.add(456);
        collection1.add(new Person("herb", 18));
        collection1.add(new String("eagle"));
        collection1.add(false);

        System.out.println(collection.equals(collection1));
    }

用法四:

public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(123);
        collection.add(456);
        collection.add(new Person("herb", 18));
        collection.add(new String("eagle"));
        collection.add(false);

        System.out.println(collection.hashCode());

        //集合---->数组
        Object[] objects = collection.toArray();
        for (int i = 0; i < objects.length; i++) {
            System.out.println(objects[i]);
        }


        //数组 --- > 集合
        List<String> strings = Arrays.asList(new String[]{"AA", "BB", "CC"});
        System.out.println(strings);
    }

Iterator迭代器接口

概述

所以实现了 Collection 接口 的容器类都有一个 Iterator 方法用于返回一个实现Iterator接口的对象

Iterator 对象称为 迭代器对象,用来方便的对容器内元素进行变量

  • boolean hasNext(): 判断有没有元素遍历
  • Object next():返回游标当前位置的元素,并将游标移动到下一个位置
  • void remove():删除游标左边的元素,在执行完next之后该操作只能执行一次
public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(123);
        collection.add(456);
        collection.add(new Person("herb", 18));
        collection.add(new String("eagle"));
        collection.add(false);

        //TODO 方式一:
        /*for (int i = 0; i < collection.size(); i++) {
            System.out.println(collection);
        }*/

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

        System.out.println("===================");
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(123);
        collection.add(456);
        collection.add(new Person("herb", 18));
        collection.add(new String("eagle"));
        collection.add(false);

        //TODO 方式一:
        /*for (int i = 0; i < collection.size(); i++) {
            System.out.println(collection);
        }*/
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            if ("eagle".equals(next)) {
                iterator.remove();
                System.out.println("删除成功");
            }
        }


        System.out.println("===================");
        iterator = collection.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

子接口List

ArrayList 实践

public class Dog {
    private String name;

    public Dog() {
    }

    public Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class DogTest {
    public static void main(String[] args) {
        List arrayList = new ArrayList();

        arrayList.add(new Dog("1"));
        arrayList.add(new Dog("2"));
        arrayList.add(new Dog("3"));
        arrayList.add(2, new Dog("4"));//添加到指定的位置

        System.out.println(arrayList.size());

        for (int i = 0; i < arrayList.size(); i++) {
            Dog o = (Dog) arrayList.get(i);
            System.out.println(o);
        }
    }
}
boolean add(Object e)在列表的尾部添加元素
void add(int index, Object element)在指定的索引位置添加元素
int size()
Object get(int index)返回指定位置的元素
boolean contains(Object o)判断集合中是否存在指定元素
remove(int index)
remove(Object index)

ArrayList源码解析

概述
  1. ArrayList是可以动态增长和缩减的数组,它是基于数组实现的List类。
  2. 该类封装了一个动态再分配的Object[]数组,每一个类对象都有一个 capacity【容量】属性,表示 它们所封装的Object[]数组的长度,当向ArrayList中添加元素时,该属性值会自动增加。

ArrayList和Vector的区别是:ArrayList是线程不安全的,当多条线程访问同一个ArrayList集合 时,程序需要手动保证该集合的同步性,而Vector则是线程安全的。

源码分析

在这里插入图片描述

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {

}
类的属性
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    //版本号
    private static final long serialVersionUID = 8683452581122892189L;
    
    //默认容量
    private static final int DEFAULT_CAPACITY = 10;
    
    //空对象数组
    private static final Object[] EMPTY_ELEMENTDATA = {};
    
    //默认空对象数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
    //元素数组
    transient Object[] elementData;
    
    //实际元素大小,默认为0
    private int size;
    
    //最大数组容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}
构造方法

在这里插入图片描述

  1. 无参构造器--------(没有传入,就没有他的事情,传入了,就10)
//如果没有传入初始容量,使用 默认空对象数组,此时容量为0
//但是在第一次添加第一个元素的时候,容量变成10
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  1. 有参构造器①---------(传入值大于零就新建,等于零就用空对象)
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //如果传入的初始容量 > 0,就新建数组存储元素
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //如果传入的初始容量 = 0,使用空对象数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
  1. 有参构造器②
public ArrayList(Collection<? extends E> c) {
    	//集合转数组
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            //检查c.toArray()返回的是不是Object[],如果不是,重新拷贝成Object[].class
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            //c是空集合,初始化为空对象数组
            elementData = EMPTY_ELEMENTDATA;
        }
    }
核心方法—>add
  1. boolean add(E e)
public boolean add(E e) {
    //检查是否需要扩容
    ensureCapacityInternal(size + 1); 
    //把元素插入到最后一位
    elementData[size++] = e;
    return true;
}

内部方法分析(ctrl + alt + <-)

private void ensureCapacityInternal(int minCapacity) {//1
    //ensureExplicitCapacity(calculateCapacity(elementData, 1));
    //ensureExplicitCapacity(10)
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

private static int calculateCapacity(Object[] elementData, int minCapacity) {//elementData, 1
    //判断初始化的elementData 是不是空数组,也就是没有长度
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //因为此时 elementData 为空,而 minCapacity = 1,空数组能不能存放东西--》不能
            //传进来的容量大小和默认的容量大小比,取最大的一个
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    // 确认实际的容量,判断elementData够不够用
        return minCapacity;
    }

private void ensureExplicitCapacity(int minCapacity) {//10
    modCount++;
    
    // minCapacity 如果大于 实际的elementData的长度,
    //说明 elementData数组的长度 数组不够用了,要扩容
    if (minCapacity - elementData.length > 0)//10 - 0 > 0
        grow(minCapacity);
}

private void grow(int minCapacity) {//10
    //记录 旧的数组长度
    int oldCapacity = elementData.length;
    //新数组长度 = 旧的数组长度 + 旧的数组长度/2
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果 新容量 < 需要的容量,就以 需要的容量 为准
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
  	
    //如果新容量 大于  最大容量,使用 Integer的最大容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    
    //以新容量 拷贝出一个新数组
    elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) 
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
  1. void add(int index, E element)
public void add(int index, E element) {
        //检查 插入位置index是否合理 
        rangeCheckForAdd(index);
    	//检查是否需要扩容
        ensureCapacityInternal(size + 1); 
    	
    	//System.arraycopy(int[] arr, int start, int[] arr,int start2, int length);
    	//第一个参数是要被复制的数组
    	//第二个参数 是被复制的数组 开始的 索引
    	// 第三个参数 目标数组,也就是要把数据放进来的数组
    	// 第4个参数 从目标数组的指定索引开始放入数组
    	// 第五个参数  从被复制参数的数组中拿几个值 放到目标数组
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
    	//把元素插入到最后一位
        elementData[index] = element;
        size++;
    }

nt index, E element) {
//检查 插入位置index是否合理
rangeCheckForAdd(index);
//检查是否需要扩容
ensureCapacityInternal(size + 1);

	//System.arraycopy(int[] arr, int start, int[] arr,int start2, int length);
	//第一个参数是要被复制的数组
	//第二个参数 是被复制的数组 开始的 索引
	// 第三个参数 目标数组,也就是要把数据放进来的数组
	// 第4个参数 从目标数组的指定索引开始放入数组
	// 第五个参数  从被复制参数的数组中拿几个值 放到目标数组
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
	//把元素插入到最后一位
    elementData[index] = element;
    size++;
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/691dae6a67974498b0c59266ba7b1c74.png#pic_center)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值