集合
- 一个容器可以容纳其他类型的数据
- 是一个容器一个载体,可以一次性容纳多个对象
- 实例:用于数据库传输数据,一次性传输多个对象)
- 集合不能直接储存基本数据类型(自动装箱,转换成引用数据类型),也不能直接储存java对象,集合中储存的是引用。
- 在java中 不用的集合底层对应着不同的数据结构 (数组、二叉树、链表、哈希表、图·······)
- 集合在java.util包下。
- 集合的分类:
Collection
以单个方式储存元素,超级接口为java.util.Collection
Map
以键值对的方式储存元素,超级接口为java.util.Map
- Collection 继承关系:
- Map 继承结构
Collection常用方法:
boolean add(Object obj)
向集合中加元素int size()
获取集合中元素的个数void clear()
清空集合boolean contains(Object obj)
判断当前集合是否包含该obj元素boolean remove(Object obj)
删除某个obj元素boolean isEmpty()
判断集合是否为空Object[] toArray()
转换成数组
-
集合迭代:(方式适用于所有Collection的子类,不适用于Map)
Iterator<E> iterator()
方法- 第一步:获取集合对象的迭代器对象 Iterator
Iterator it = c.iterator();
- 第二步:通过获取的迭代器对象开始迭代
- 方法一:boolean hasnext()
若有元素可迭代,则返回true
- 方法二:Object next()
让迭代器前进一位并将指向的元素返回,迭代器指向两个对象中间,返回跨过的对象
- 第一步:获取集合对象的迭代器对象 Iterator
-
集合存进去是什么类型取出来也是什么类型
-
Contains 方法 -
boolean Contains(Object obj)
---------底层调用对象的equals()
方法判断是否存在该对象
例如: 判断Collection中String对象,Contains 底层调用equals() 方法,底层判断是否包含该String对象的值。
Collection c = new ArrayList();
c.add(new String("abc");
String x = new String("abc");
c.contains(x);//返回true
(自己写的类重写equals()方法
的意义)若比较其他类型的对象,若没重写equals()方法,则返回false;存放在集合中的对象,一定要重写equals()方法。
remove(Object obj) 方法
同样底层也调用equals方法 判断是否存在等于该值的对象,再删除。
- 重点:关于集合元素的remove:
- 当集合的结构发生改变时,必须重新获取迭代器
- 当删除一个元素时,可以使用collection中的remove()方法;但当遍历时删除元素时,必须使用Iterator中的remove()方法。
Collection c = new ArrayList();
Iterator it = c.iterator();
//此时获取的是没有对象的迭代器,当集合元素发生改变时必须重新获取迭代器,否则会报异常。
c.add("abc");
c.add("xyz");
while(it.hasNext()){
System.out.println(it.next());
}
/*
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at CollectionTest01.main(CollectionTest01.java:44)
*/
- 牵扯到源码,可以看看加深理解:关于Collection和Iterator中的remove()方法
List接口特有方法:
- List下的子类特点:有序可重复,每个元素有下标,元素可重复
常用方法:
void add(int index,Object element)// 向集合的指定位置插入元素,方法使用频率较低,对于ArrayList效率较低
Object get(int index) //根据下标取出元素,Set接口下的子类就没有这个方法(无序不可重复)
int indexOf(Object obj)//获取指定对象第一次出现的索引
int lastIndexOf(Object obj) // 获取指定对象最后一次出现的索引
Object remove(int index) //删除指定索引处的元素
Object set(int index,Object element) // 更改指定位置的元素
ArrayList:
- 底层是一个Object[]数组
- 默认初始化容量为10(源码里初始构造一个长度为零的Object数组,当添加第一个元素时,默认长度变为10)。
- 非线程安全的集合
- 初始化:
List array1 = new ArrayList();
默认容量为10
List array2 = new ArrayList(10);
指定容量
List array2 = new ArrayList(Object[] objs);
可以将一个其他类型的集合转化为ArrayList集合 - 自动扩容时扩容为原容量的1.5倍,源码里增长量为
oldCapacity >> 1 (oldCapacity / 2)
LinkedList
链表
- 对于链表数据结构来说:基本的单元是节点node
- 对于单向链表来说,任何一个节点Node中都有两个属性:
- 储存的数据
- 下一个节点的内存地址
- 链表优点:由于链表上的元素在空间储存上内存地址不连续,随机增删元素效率较高(增删元素不涉及大量元素的位移),在业务上遇到随机增删集合中元素的业务比较多时,使用LinkedList
- 链表缺点:不能通过数学表达式计算被查找元素的内存地址,查询效率较低,每次查找只能从头节点开始往下遍历。
- 由于我们往往是往末尾加元素,所以ArrayList使用频率较高。
LinkedList
- 底层为双向链表结构
- 没有初始容量,初始化链表没有任何元素。
Vector
-
底层为数组
-
初始容量为10
-
自动扩容时扩容为原容量的2倍
-
Vector中的方法都是线程同步的,都带有synchronized关键字,是线程安全的,但效率比较低,使用较少
-
重点将线程不安全的ArrayList转化为线程安全的Vector
利用java.util.Collections(集合工具类)中的synchronize
List myList = new ArrayList();
//变成线程安全的
Collections.synchronizedList(myList);
//这时候myList就是线程安全的了