集合
1.集合体系
Collection(集合的根接口) --> Iterable(接口)
Collection
-
List接口
有序 (记录元素的添加顺序) 可以重复
-
AbstractList(抽象类)
ArrayList [数组结构]
-
Vector [数组结构]
- Stack
LinkedList[链表结构]
-
-
Queue接口
- Deque接口
- LinkList[链表结构]
- Deque接口
-
Set接口
无序 (不记录元素的添加顺序) 不能重复
- AbstractSet抽象类
TreeSet[红黑树结构]
-
HashSet[哈希表结构]
- LinkHashSet[链表+哈希表]
- SortedSet接口
- AbstractSet抽象类
Map接口
-
AbstractMap抽象类
- HashMap
- TreeMap
-
HashTable
- Properties
在集合的接口规范中,我们不难发现,包含的是对数据的CRUD
添加: add() addAll()
查询: contains(Object o)
删除: remove(Object o)
注意: 集合只能存储对象!
2.List
特点:
有序 (记录元素的添加顺序) 可以重复
查询:get()方法, 根据索引查 indexOf()方法,查询对象的索引
修改:set()方法
2.1 Vector
Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
- 基于数组结构
- 实现可增长的对象数组,使用整数索引进行访问,大小可以根据需要增大或者缩小
无参构造默认内部数组长度为10.
线程安全,不效率
是Java1.0就有了,属于老古董
2.2 Stack
Stack<E> extends Vector<E>
表示后进先出, 继承于Vector类,Vector类的方法在Stack中都能使用
Stack() 创建一个空堆栈
push() 把一个对象压进堆栈
peek() 查看栈顶的对象
pop() 移除堆栈顶部的对象, 并返回该对象
empty() 堆栈是否为空
search() 在栈中查找对象, 并确定到栈顶的距离
- 线程安全,不效率
2.2 ArrayList
ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
基于数组结构
使用上大致是跟Vector一致的,允许所有元素(包括null)
-
默认无参构造创建对象时没有长度,在需要存储元素的时候才进行扩容
add() 添加一个元素 addAll() 添加另一个集合中的所有元素
ArrayList 不是线程安全的, 效率高
2.3 LinkedList
LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable
允许所有元素(包括null)
底层基于链表、双向队列数据结构集合
List接口的链表实现,支持List的通用方法
-
为首尾元素的操作提供了特定的方法, 允许作为堆栈,队列,双向队列
offerFirst() 添加头元素 offerLast() 添加尾元素 pollFirst() 移除头元素 pollLast() 移除尾元素 peekFirst() 查看头元素 peekLast() 查看尾元素
线程不安全,处理首尾元素效率高
2.4 集合的迭代
所谓迭代,就是访问集合中的每一个元素
-
for循环
使用for循环访问数组中的元素,依赖的是数组的索引
-
Iterator
不是所有集合都可以使用
-
面向对象的做法,把迭代集合的操作封装成一个对象
Iterator it = list.iterator(); while(it.hasNext()){ Object obj = it.next();//取出下一个元素 }
-
常用方法
hasNext() 是否有下一个元素, 判断当前索引是否等于集合长度,不等则返回true,表示还有元素可以迭代. next() 先返回当前索引的元素,然后索引+1 remove() 删除元素
在迭代的过程中只能使用迭代器操作源集合的元素
-
ListIterator
Iterator的子接口,并且功能更加的强大
-
包含了CRUD的方法
ListIterator it = list.listIterator(); //从头到尾迭代 while(it.hasNext()){ it.next();//获取下一元素 it.set("111");//替换和删除原理是一样的,必须先next()移位 } it.add("222");//往集合里添加元素 //从尾到头迭代 while(it.hasPrevious){ it.previous();//取出上一元素 }
只有List集合中才有
-
foreach
-
语法糖,底层是Iterator
for(Object obj : list){ .... }
只要实现了Iterable接口就可以用foreach迭代
-
迭代集合总学了3种方式:在迭代的过程中如果要操作集合,建议使用迭代器,仅仅是要访问元素就使用foreach会简单一些
2.5 泛型
类型的不确定,但是使用逻辑一样
-
集合使用泛型和没有使用泛型的区别
-
没有泛型
取出集合中的元素对象,要调用到元素对象子类特有的方法,必须强转(不安全) 到处都是警告
-
使用泛型
使用的时候限定了只能存储对应的类型,其他的类型不能存储进来 使用里面的对象时不需要强转 如果要存储多种类型的数据,建议分开存储 没有警告
-
泛型只是语法糖,当取出并使用集合里的对象时,底层是编译器帮我们强转,有编译器来强转保证安全
-
泛型的作用域
-
声明在类上,在整个类中有效
class test<E>{ ... }
-
声明在方法上,只在当前的方法中有效
/** * 这才是一个真正的泛型方法。 * 首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T * 这个T可以出现在这个泛型方法的任意位置. */ public <T> T showKeyName(Generic<T> container){ System.out.println("container key :" + container.getKey()); //当然这个例子举的不太合适,只是为了说明泛型方法的特性。 T test = container.getKey(); return test; } * 泛型的数量也可以为任意多个 如:public <T,K> K showKeyName(Generic<T> container){ ... }
-
-
问号的使用
泛型中使用问号的3种情况:
1.?:未知类型 2.? super BaseClass:必须是BaseClass类型的父类或者BaseClass类型 3.? extends BaseClass:必须是BaseClass类型的子类或者BaseClass类型
3.Set
特点:
无序不重复,不包含重复元素,最多包含一个null元素
3.1 HashSet
HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable
哈希表数据结构
无序,不能重复
无参构造创建一个HashMap,默认初始容量为16
-
add() 方法添加对象,需要判断两个点
1.调用需添加对象的的hashCode()方法,对比set中已存在对象的hash是否相等
2.调用添加对象的equals()方法,与set中已存在对象进行比较
只有以上两点都返回true时,set才会添加新对象.
HashCode集合判断是否重复的关键就在于 Object的hashCode和equals方法
线程不安全
3.2 LinkedHashSet
LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable
基于链表和哈希表的结构
使用链表来记录对象添加的顺序,使用哈希表来判定元素的唯一
底层是创建了一个初始容量为16的LinkedHashMap
没有自己的特定方法,使用上和set接口一致
3.3 TreeSet
TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
底层是红黑树数据结构,将集合中的对象进行比较,重复的则不添加
基于TreeMap实现
-
默认无参构造是基于自然顺序排序(从小到大), 自定义的对象添加到TreeSet里面,需要实现Comparable接口
当前对象实现Comparable接口的compareTo(A a)方法,返回值1表示比指定对象a大,0 表示相等, -1 表示比指定对象a小.
compareTo()方法是自然比较方法
-
如果不想按自然顺序排序,TreeSet构造器还可以传入Comparator进行自定义排序,比如从大到小
public TreeSet(Comparator<? super E> comparator) { throw new RuntimeException("Stub!"); }
Comparator
int compare(T var1, T var2); var1 > var2 返回1 var1 == var2 返回0 var < var2 返回-1 以上返回值会使集合按照从小到大排序
分析TreeSet中的TreeMap可以发现,优先使用Comparator的compare()进行排序,如果没有Comparator,则使用对象的compareTo()方法进行排序
4.Map
表示映射关系,以键值对key-value形式存在
-
特点:
key无序不重复,value可重复
一个key只能映射一个值
Map是存储了多个键值对 Map.Entry<k,v> 的集合
-
常用方法
put(k,v) 添加元素 get(k) 返回指定key的值 keySet() 以set集合返回所有的key values() 以Collection的形式返回所有的值 size() 获得键值对的个数 entrySet() 返回Entry<k,V>的set集合 HashMap<String,Object> map = new HashMap<>(); Set<Map.Entry<String, Object>> entries = map.entrySet(); for (Map.Entry<String, Object> entry : entries){ String key = entry.getKey(); //键 Object value = entry.getValue(); //值 }
4.1 HashMap
基于哈希表的Map接口的实现类
非同步,允许使用null键和null值,除此之外,与HashTable类大致相同
4.1 TreeMap
作为key的元素,需要实现hashCode()和equals()之外,还需要实现Comparable接口,重写compareTo()方法,compareTo()方法需要正确返回整数,负数以及0
treeMap 与 hashMap不同,hashMap需要根据equals方法来判断key是否相等,而treeMap是根据
compareTo() == 0 判断是否相等.
4.2 Map和set的关系
Set底层是用Map数据结构,xxxSet底层就用xxxMap数据结构,如HashSet --> HashMap
-
Set集合不会重复的关键:
Set集合的元素是底层Map用key来保存,用一个常量作为value,
所有的key都映射到这个常量,满足键值对的要求,key的不重复特性保证了Set的元素是不重复的
5.集合相关类
5.1 Collections
- 集合的工具类
-
常用方法:
shuffle() 打乱集合中元素的顺序
sort() 对集合中的元素进行排序
synchronizedCollection(Collection<T> c):返回线程安全(同步)的collection
synchronizedMap(Map<k,v> m):返回线程安全(同步)Map
-
使用线程安全的集合需要注意的地方:
进行迭代的时候,迭代的代码必须同步
List<String> list = new ArrayList<>(); Collection<String> collection = Collections.synchronizedCollection(list); synchronized (collection){ //迭代需要进行同步 Iterator<String> iterator = collection.iterator(); while (iterator.hasNext()){ iterator.next(); } }
5.2 Arrays
Arrays.asList(T... t) 目的是将数组转成集合,得到的集合不允许删除,增加,只能查询