集合
为什么要使用集合框架?
假设一个班有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源码解析
概述
- ArrayList是可以动态增长和缩减的数组,它是基于数组实现的List类。
- 该类封装了一个动态再分配的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;
}
构造方法
- 无参构造器--------(没有传入,就没有他的事情,传入了,就10)
//如果没有传入初始容量,使用 默认空对象数组,此时容量为0
//但是在第一次添加第一个元素的时候,容量变成10
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 有参构造器①---------(传入值大于零就新建,等于零就用空对象)
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);
}
}
- 有参构造器②
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
- 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;
}
- 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)