Collection接口
- Collection集合框架的层次结构
graph TD
A[Collection接口] --> B(List接口)
A --> C(Set接口)
A --> D(Iterator接口)
B --> E(ListIterator接口)
D --> E
B --> F(ArrayList)
B --> G(LinkedList)
B --> H(Vector)
C --> I(HashSet)
C --> J(TreeSet)
H --> K(Stack)
在这里无法显示,补图
- List 有序集合,允许相同元素和null
- LinkedList 非同步,允许相同元素和null,遍历效率低插入和删除效率高
- ArrayList 非同步,允许相同元素和null,实现了动态大小的数组,遍历效率高,用的多
- Vector 同步,允许相同元素和null,效率低
- Stack 继承自Vetor,实现一个后进先出的堆栈
- Set 无序集合,不允许相同元素,最多有一个null元素
- HashSet 无序集合,不允许相同元素,最多有一个null元素
- TreeSet 有序集合,不允许相同元素,最多有一个null元素
Map接口
graph TD
A[Map接口] --> B(HashMap)
A --> C(HashTable)
A --> D(TreeMap)
- Map 没有实现Collection接口,key不能重复,value可以重复,一个key映射一个value
- Hashtable 实现Map接口,同步,不允许null作为key和value,用自定义的类当做key的话要重写hashCode和equals
- HashMap 实现Map接口,非同步,允许null作为key和value,用的多
- TreeMap 实现Map接口,非同步
- WeakHashMap 实现Map接口
Collection接口
-
Collection是最基本的集合接口,一个Collection代表一组Object即Collection元素(Elements)
-
由Collection接口派生的两个接口是List和Set
-
List接口
- List是有序的Collection,使用此接口能够精确的控制每个元素的插入位置,用户能够使用索引来访问List中的元素,类似于Java的数组
-
LinkeList类
- LinkedList实现了List接口,允许null元素,LinkenList底层才用了双向链表来存储数据,每个存储着上一个节点和下一个节点的地址以及本节点的数据。
- LinkedList没有同步方法。如果多线程同时访问一个List,则必须自己实现访问同步,解决方法是在创建List时构造一个同步的List
- 查询效率低,删除新增效率高
- 双向链表存储
List<Object> list1 = Collections.synchronizedList(new LinkedList<>());
-
ArrayList类
- ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList底层采用动态数组的存储方式,便利效率非常高,ArrayList是线程不安全的。
- 线性存储
- 查询效率高,新删效率低
-
Vector类
- Vector非常类似ArrayList,但是Vector是同步的
-
Stack类
- Stack继承自Vector,实现一个后进后出的堆栈
- Stack刚创建后是空栈
-
Set接口
- Set是一种无序的并且不包含重复的元素的Collection,用equals判断是否相同
- Set最多有一个null元素
-
HashSet类
- HashSet是哈希表实现的,HashSet中的数据是无序的,可以放入null,当只能放入一个null
- HashSet存的数据不能重复
- HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例 。
- 哈希值散列存储
-
TreeSet
- 自然循序排序,二叉树结构存储
-
ArrayList和LindedList的区别:
- ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
- 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
- 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
Map接口
-
Map没有继承Collection接口,Map提供key到value的映射
-
一个Map中不能包含相同的key,每个key只能映射value
-
Map接口提供3种集合的视图,Map的内容可以被当做一组key集合,一组value集合,或者一组key映射
-
Hashtable类
- Hashtable继承Map接口,实现一个key-value映射的哈希表
- 任何非空(non-null)的对象都可作为key或者value
- Hashtable是同步的
-
HashMap类
- HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key
-
WeakHashMap类
- WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
集合操作工具类
- jdk提供了一个集合操作工具类,包含了一组静态的方法,实现了对集合进行查询,排序,拷贝等操作
//创建一个集合保存20个随机整数
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
list.add(new Random().nextInt(100));
}
System.out.print("排序前的数据:");
for (Integer i : list) {
System.out.print(i+"\t");
}
Collections.sort(list);//使用工具类进行排序 --是升序排序
Collections.reverse(list);//使用工具类对集合进行反向存储
System.out.println();
System.out.print("排序后的数据:");
for (Integer i : list) {
System.out.print(i+"\t");
}
System.out.println();
System.out.println("集合中最大值为:"+Collections.max(list));
System.out.println("集合中最小值为:"+Collections.min(list));
List集合
- List集合保存的数据有顺序的
- List集合保存的数据可能有重复保存,有重复
- ArrayList类实现的集合是一个数组列表,在内存存储时是连续存放的,具有很高的查询性能Vector类的功能与ArrayList一致,在内存存储时是连续存放的,具有很高的查询性能
- ArrayList是线程不安全的,Vector是线程安全的,ArrayList的效率高于Vector,Vector的安全性高于ArrayList
- List集合默认保存Object类型的数据
- 新增集合中的数据:存放数据,保存数据没有做数据类型的检查
- 同一对象可以保存两次
Set散列结合
- Set集合保存的数据是唯一的,不会重复的
- Set集合保存的数据是无序的(不会根据添加数据的先后顺序进行保存,取数据也不会按照添加的先后顺序进行获取)
- HashSet类在新增数据时效率很高,查询效率没有List集合高
TreeSet类实现了一个SortedSet接口,使用树形结构实现了可排序的集合 - HashSet具有较高的新增性能,TreeSet具有较高的查询性能
//使用Set集合,生成1-25之内,不重复的7个随机整数
//Set<Integer>泛型编程,泛型集合
//泛型集合在定义变量时,使用尖括号声明要保存的数据的具体类型(泛型)
Set<Integer> set = new HashSet<>();
while(true) {
//集合不能保存基本数据类型,当保存基本数据类型到集合中时,会进行自动装箱成Interger对象
set.add(new Random().nextInt(25)+1);//随机生成的数据可能有重复,相同的数据不会重复添加到set集合中
if (set.size()>6) break;
}
for (Integer i : set) {//定义集合时使用了泛型集合,即声明了要保存的数据类型,取数据时可以直接获取目标类型的数据
System.out.print(i+"\t");
}
链表集合
- 链表集合的元素有三个信息构成:它会保存前后数据的信息(地址),具有很高的修改性能
- 链表结构在存储信息时不一定是连续存放的,查询效率没有ArrayList高
- LinkeList类实现了链表结构
队列集合
- 队列结构具有先进先出,后进后出的特点
- Queue接口和Deque接口决定了队列的操作
- LinkedList类实现了队列接口,可以按照队列的操作进行保存
- addFirst,addLast
//队列结构
Deque<String> deque = new LinkedList<>();
//数据新增
deque.add("第一条数据");//添加一条数据到队列的尾部
deque.addLast("第二条数据");//添加一条数据到队列的尾部
deque.addFirst("第三条数据");//双端队列可以添加数据到队列的头部
//查询数据
System.out.println("队列集合的长度为:"+deque.size());//输出的结果为3
System.out.println(deque.getLast());//双端队列可以从尾部读取数据,输出结果为第二条数据
System.out.println(deque.element());//从头部取出数据不删除,输出的结果为第三条数据
System.out.println(deque.removeLast());//从尾部取出数据并删除,输出结果为第二条数据
System.out.println("队列集合的长度为:"+deque.size());//输出的结果为2
栈集合
- 栈结构具有先进后出,后进先出的特点
- Stack类实现了栈结构
- push压栈,pop去除栈顶数据并将其移出,peek取出数据并移出
//栈结构
Stack<String> stack = new Stack<>();
//新增-压栈
stack.push("第一条数据");//压栈是存储一个数据到当前数据栈的栈顶(坑的最上面)
stack.push("第二条数据");
stack.push("第三条数据");
//取数据-弹栈
System.out.println("栈集合的长度为:"+stack.size());//输出的结果为3
System.out.println(stack.peek());//返回栈顶的数据,不移出数据,输出结果为第三条数据
System.out.println(stack.pop());//返回栈顶的数据并移出,输出结果为第三条数据
System.out.println("栈集合的长度为:"+stack.size());//输出的结果为2
stack.remove(stack.pop());//remove方法不是栈的操作方法,而是Collection集合的方法
System.out.println("栈集合的长度为:"+stack.size());//输出的结果为1
Map映射结构集合
- 当有两个数据需要管理才有具体意义时,可以使用Map集合
即Map集合用于存放有关联关系的两个数据,两个数据合成一个Map元素 - Map接口有两个常用的:HashMap和HashTable
- HashMap线程不安全,效率更高,HashTable线程安全,效率较低
- HashMap可以用null作key和value,HashTable不允许
Map<String, Double> map = new HashMap<>();
map.put("No1", 88.0);//自动装箱,需要数据类型匹配才能装箱
map.put("No2", 66.0);
//集合的遍历
//map结合的遍历一般包含两个步骤
//1. 是对key的遍历,通过对key进行遍历找出所有的key
//2. 遍历后,根据每一个可以获取key对应的值
Set<String> keys = map.keySet();//keySet方法获取所有的key
Iterator<String> iterator = keys.iterator();//本例使用迭代接口进行迭代
while(iterator.hasNext()) {
String key = iterator.next();//循环迭代每一个key
Double score = map.get(key);//Map集合有个get方法,可以根据key根据key获取相应的value值
System.out.println(key+"\t"+score.doubleValue());//遍历输出所有数据
}
//删除数据,根据key就可以删除
map.remove("No1");
//修改数据,根据key调用Map类的put进行替换修改
map.put("No2", 100.0);
集合类的选择
- Set内存放的元素不允许重复,List存放的元素有一定的顺序
- Map的应用主要在利用键/值进行快速查询
- ArrayList和LinkedList的区别在于随机查询性能上ArrayList要好,但LinkedList的中间元素的插入与删除性能好
- HashSet和TreeSet的区别在于集合内元素是否排序
集合中的异常
- ClassCastException 在集合中取得元素对象在进行类型转换的时候类型不匹配
- UnsupportedOperationException 当底层实现没有实现上层的相关方法的时候由Collection抛出该异常
- ConcurrentModificationException 当采用Iterator遍历集合时,如果此时集合中的元素被改变则Iterator遍历抛出此异常
- IndexOutOfBoundsException 集合中元素引用的索引值超出界限(<0或>size())
- NoSuchElementException LinkedList中getLast,getFirst等方法取元素的时候List为空
泛型
- 泛型的语法:Collection coll = new ArrayList(); jdk6
- Collection coll = new ArrayList(); jdk7
为什么要使用泛型?
- 为了实现在保存数据时,进行类型的检查,获取数据时不用进行类型的检查。
- 在保存数据时由编译器进行语法检查,如果类型不匹配则无法通过编译
- 一个集合一般只保存一种数据类型
- 定义一个集合,用于保存一组小鸟的信息
- 泛型集合可以在保存时做类型检查,避免集合中出现无效的数据
- 使用了泛型集合后,取数据时可以不做类型的检查
2. 请介绍一下List和ArrayList的区别,ArrayList和HashSet的区别
- List是接口,ArrayList是实现该接口的类
- ArrayList底层是动态数组,有序且可重复
- 而HashSet是实现了Set接口底层是HashMap不能重复且无序
- ArrayList初始大小为10,增长算法为1.
- 简单的说ArrayList是有序可重复,HashSet是无序不可重复