15.Java集合类
来源:互联网 发布:mac压缩软件 编辑:程序博客网 时间:2024/05/17 06:35
转载请保留原文链接: http://dashidan.com/article/java/basic/Java集合类.html
Java集合类是java提供的工具包,包含了常用的数据结构:集合、链表、队列、栈、映射等.Java集合类主要可以划分为4个部分:List列表、Set集合、Map映射、工具类(Iterator迭代器、Enumeration枚举类、Arrays和Collections).
必须小心操作可变对象(Mutable Object)
如果一个`Set`中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题.
`Map`没有继承`Collection`接口.
`LinkedList`没有同步方法
如果多个线程同时访问一个List, 则必须自己实现访问同步.
一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(…));.
/** ArrayList添加对象*/ArrayList<Integer> intList = new ArrayList<>();System.out.println("ArrayList 长度: " + intList.size());for (int i = 0; i < 10; i++) { intList.add(i);}System.out.println("ArrayList 长度: " + intList.size());/** ArrayList删除对象*/intList.remove(5);System.out.println("ArrayList 长度: " + intList.size());
`ArrayList`遍历:* ArrayList 遍历方式 1 增强for循环, 获得值, 无法获得索引for (Integer intNum : arrayList) { System.out.println(intNum);}
* ArrayList 遍历方式 2普通for循环, 索引和值都能获得for (int i = 0; i < arrayList.size(); i++) { int num = arrayList.get(i); System.out.println(num);}
* ArrayList 遍历方式 3 迭代器 Itertor, 无法获得索引Iterator<Integer> it = arrayList.iterator();while (it.hasNext()) { int num = it.next(); System.out.println(num);}
###3.`Vector`类`Vector`非常类似`ArrayList`,但`Vector`是线程同步的.由`Vector`创建的`Iterator`,虽然和`ArrayList`创建的`Iterator`是同一接口,但由于`Vector`是线程同步的,当一个`Iterator`被创建而且正在被使用,另一个线程改变了`Vector`的状态(例如,添加或删除了一些元素),这时调用`Iterator`的方法时将抛出`ConcurrentModificationException`,因此必须捕获该异常.代码示例:/** Vector*/Vector<Integer> vector = new Vector<>();System.out.println("Vector 长度: " + vector.size());for (int i = 0; i < 5; i++) { vector.add(i);}System.out.println("Vector 长度: " + vector.size());/** Vectort 删除对象*/vector.remove(3);System.out.println("Vector 长度: " + vector.size());/** Vectort 遍历方式 1 增强for循环*/for (Integer intNum : vector) { System.out.println(intNum);}
Vector添加删除对象和遍历方式和ArrayList类似, 参考ArrayList的代码实现.
/** Stack*/Stack<Integer> stack = new Stack<>();System.out.println("Stack 长度: " + stack.size());for (int i = 0; i < 5; i++) { /** 入栈*/ stack.push(i);}System.out.println("Stack 长度: " + stack.size());/** Stack pop 出栈*/stack.pop();System.out.println("Stack 长度: " + stack.size());/** Stack peek 得到栈顶的元素*/int peekNum = stack.peek();System.out.println("Stack peekNum: " + peekNum);/** Stack search 检测一个元素在堆栈中的位置*/int pos = stack.search(3);System.out.println("Stack search pos: " + pos);/** Stack 遍历方式 1 增强for循环*/for (Integer anIntList : stack) { int num = anIntList; System.out.println(num);}
`Stack`遍历方式和`ArrayList`类似, 参考`ArrayList`的代码实现.
`hashCode`和`equals`方法继承自根类`Object`.
用自定义的类当作key
按照`散列函数`的定义,如果两个对象相同,即`obj1.equals(obj2)=true`,则它们的`hashCode`必须相同,但如果两个对象不同,则它们的`hashCode“不一定不同`.
如果两个不同对象的hashCode相同,这种现象称为`冲突`. 冲突会导致操作哈希表的时间开销增大.
所以尽量定义好的`hashCode()`方法,能加快哈希表的操作.如果相同的对象有不同的`hashCode`,对哈希表的操作会出现意想不到的结果(`期待的get方法返回null`).
要避免这种问题,只需要牢记一条:要同时覆写`equals`方法和`hashCode`方法, 而不要只写其中一个.
代码示例: HashMap
添加和删除对象:
HashMap<Integer, Integer> hashMap = new HashMap<>();System.out.println("HashMap 长度: " + hashMap.size());for (int i = 0; i < 5; i++) { /** HashMap 添加对象*/ hashMap.put(i, 100 + i);}System.out.println("HashMap 长度: " + hashMap.size());/** HashMap 删除对象*/hashMap.remove(2);System.out.println("HashMap 长度: " + hashMap.size());
`HashMap`遍历:* HashMap 遍历方式 1 增强for循环遍历 Entry推荐使用
直接拿到了key和value的对象, 省去了`get`数据的操作,效率最高.
System.out.println("HashMap 遍历方式 1 增强for循环遍历 Entry ");for (Map.Entry<Integer, Integer> entry : hashMap.entrySet()) { System.out.println("hashMap key: " + entry.getKey() + " hashMap value: " + entry.getValue());}
* HashMap 遍历方式 2 通过迭代器遍历 keyIterator<Integer> it0 = hashMap.keySet().iterator();while (it0.hasNext()) { int key = it0.next(); int value = hashMap.get(key); System.out.println("key: " + key + " value: " + value);}
* HashMap 遍历方式 3 通过 增强for循环遍历 keyfor (Integer key : hashMap.keySet()) { int value = hashMap.get(key); System.out.println("key: " + key + " value: " + value);}
* HashMap 遍历方式 4 通过迭代器遍历 values, 无法得到 key值 Iterator<Integer> it1 = hashMap.values().iterator();while (it1.hasNext()) { int value = it1.next(); System.out.println("value: " + value);}
* HashMap 遍历方式 5 通过 增强for循环遍历 values, 无法得到 key值for (Integer value : hashMap.values()) { System.out.println("value: " + value);}
###6.`Hashtable`类`Hashtable`继承`Map`接口,实现一个`key-value`映射的哈希表. 任何`非空`(non-null)的对象都可作为`key`或者`value`. `Hashtable`与`HashMap`类似,是`HashMap`的线程安全版,是线程同步的,即任一时刻只有一个线程能写`Hashtable`,因此也导致了Hashtale在写入时会比较慢.它继承自`Dictionary`类,不同的是它不允许记录的键或者值为`null`,同时效率较低.建议使用ConcurrentHashMap替代
如果需要线程同步的map, 建议使用线程同步的ConcurrentHashMap类. 不建议使用这个类, 并没有示例代码.
使用方式同`HashMap`.
使用HashSet类时如果发生冲突,就会出现遍历整个数组的情况,这样就使得效率非常的低.
/** 循环两次,放入重复的1-5*/for (int i = 0; i < 5; i++) { hashSet.add(i);}for (int i = 0; i < 5; i++) { hashSet.add(i);}System.out.println("HashSet 长度: " + hashSet.size());/** HashSet 遍历方式 1 增强for循环*/for (Integer intNum : hashSet) { System.out.println(intNum);}
由于HashSet去重功能, 第二次循环插入重复数据时, HashSet中并没有加入新的数据, 长度依然是5. HashSet的遍历方式同ArrayList,参考ArrayList的遍历.###9.`ConcurrentHashMap`类线程同步的`HashMap`,线程安全并且锁分离. `ConcurrentHashMap`内部使用段(`Segment`)来表示这些不同的部分,每个段其实就是一个小的`hash table`,它们有自己的锁. 只要多个修改操作发生在不同的段上,它们就可以并发进行.使用方式同`HashMap`.
使用方式同`HashMap`.
使用方式同`HashMap`.
// 获得一个迭代器Iterator it = collection.iterator();while(it.hasNext()) { //获取下一个元素 Object obj = it.next();}
###2. foreach增强for循环, JDK1.5之后提供的新功能, 可以输出数组或集合.###3. for循环普通for循环遍历示例代码:package com.dashidan.lesson13;import java.util.*;/** * 大屎蛋教程网-dashidan.com * <p> * Java教程基础篇: 13.Java集合类 */public class Demo1 { public static void main(String[] args) { testArrayList(); testVector(); testStack(); testHashMap(); testHashSet(); } /** * ArrayList基本操作 */ public static void testArrayList() { System.out.println("---ArrayList---"); /** ArrayList添加对象*/ ArrayList<Integer> arrayList = new ArrayList<>(); System.out.println("ArrayList 长度: " + arrayList.size()); for (int i = 0; i < 5; i++) { arrayList.add(i); } System.out.println("ArrayList 长度: " + arrayList.size()); /** ArrayList删除对象*/ arrayList.remove(3); System.out.println("ArrayList 长度: " + arrayList.size()); /** ArrayList 遍历方式 1 增强for循环, 获得值, 无法获得索引*/ for (Integer intNum : arrayList) { System.out.println(intNum); } /** ArrayList 遍历方式 2普通for循环, 值和索引都能得到*/ for (int i = 0; i < arrayList.size(); i++) { int num = arrayList.get(i); System.out.println(num); } /** ArrayList 遍历方式 3 迭代器 Itertor, 获得值, 无法获得索引*/ Iterator<Integer> it = arrayList.iterator(); while (it.hasNext()) { int num = it.next(); System.out.println(num); } } /** * Vector基本操作 */ public static void testVector() { System.out.println("---Vector---"); /** Vector*/ Vector<Integer> vector = new Vector<>(); System.out.println("Vector 长度: " + vector.size()); for (int i = 0; i < 5; i++) { vector.add(i); } System.out.println("Vector 长度: " + vector.size()); /** Vectort 删除对象*/ vector.remove(3); System.out.println("Vector 长度: " + vector.size()); /** Vectort 遍历方式 1 增强for循环, 获得值, 无法获得索引*/ for (Integer intNum : vector) { System.out.println(intNum); } /** Vectort 遍历方式 2普通for循环, 值和索引都能得到*/ for (int i = 0; i < vector.size(); i++) { int num = vector.get(i); System.out.println(num); } /** Vectort 遍历方式 3 迭代器 Itertor, 获得值, 无法获得索引*/ Iterator<Integer> it = vector.iterator(); while (it.hasNext()) { int num = it.next(); System.out.println(num); } } /** * Stack基本操作 */ public static void testStack() { System.out.println("---Stack---"); /** Stack*/ Stack<Integer> stack = new Stack<>(); System.out.println("Stack 长度: " + stack.size()); for (int i = 0; i < 5; i++) { /** 入栈*/ stack.push(i); } System.out.println("Stack 长度: " + stack.size()); /** Stack pop 出栈*/ stack.pop(); System.out.println("Stack 长度: " + stack.size()); /** Stack peek 得到栈顶的元素*/ int peekNum = stack.peek(); System.out.println("Stack peekNum: " + peekNum); /** Stack search 检测一个元素在堆栈中的位置*/ int pos = stack.search(3); System.out.println("Stack search pos: " + pos); /** Stack 遍历方式 1 增强for循环*/ for (Integer intNum : stack) { System.out.println(intNum); } } /** * HashMap基本操作 */ public static void testHashMap() { System.out.println("---HashMap---"); HashMap<Integer, Integer> hashMap = new HashMap<>(); System.out.println("HashMap 长度: " + hashMap.size()); for (int i = 0; i < 5; i++) { /** HashMap 添加对象*/ hashMap.put(i, 100 + i); } System.out.println("HashMap 长度: " + hashMap.size()); /** HashMap 删除对象*/ hashMap.remove(2); System.out.println("HashMap 长度: " + hashMap.size()); /** HashMap 遍历方式 1 增强for循环遍历 Entry */ System.out.println("HashMap 遍历方式 1 增强for循环遍历 Entry "); for (Map.Entry<Integer, Integer> entry : hashMap.entrySet()) { System.out.println("hashMap key: " + entry.getKey() + " hashMap value: " + entry.getValue()); } /** HashMap 遍历方式 2 通过迭代器遍历 key */ System.out.println("HashMap 遍历方式 2 通过迭代器遍历 key *"); Iterator<Integer> it0 = hashMap.keySet().iterator(); while (it0.hasNext()) { int key = it0.next(); int value = hashMap.get(key); System.out.println("key: " + key + " value: " + value); } /** HashMap 遍历方式 3 通过 增强for循环遍历 key*/ System.out.println("HashMap 遍历方式 3 通过 增强for循环遍历 key"); for (Integer key : hashMap.keySet()) { int value = hashMap.get(key); System.out.println("key: " + key + " value: " + value); } /** HashMap 遍历方式 4 通过迭代器遍历 values, 无法得到 key值 */ System.out.println("HashMap 遍历方式 4 通过迭代器遍历 values, 无法得到 key值 "); Iterator<Integer> it1 = hashMap.values().iterator(); while (it1.hasNext()) { int value = it1.next(); System.out.println("value: " + value); } /** HashMap 遍历方式 5 通过 增强for循环遍历 values, 无法得到 key值 */ System.out.println("HashMap 遍历方式 5 通过 增强for循环遍历 values, 无法得到 key值 "); for (Integer value : hashMap.values()) { System.out.println("value: " + value); } } /** * HashSet基本操作 */ public static void testHashSet() { System.out.println("---HashSet---"); HashSet<Integer> hashSet = new HashSet<>(); System.out.println("HashSet 长度: " + hashSet.size()); /** 循环两次,放入重复的1-5*/ for (int i = 0; i < 5; i++) { hashSet.add(i); } for (int i = 0; i < 5; i++) { hashSet.add(i); } System.out.println("HashSet 长度: " + hashSet.size()); /** HashSet 遍历方式 1 增强for循环*/ for (Integer intNum : hashSet) { System.out.println(intNum); } }}
输出: —ArrayList— ArrayList 长度: 0 ArrayList 长度: 5 ArrayList 长度: 4 0 1 2 4 0 1 2 4 0 1 2 4 —Vector— Vector 长度: 0 Vector 长度: 5 Vector 长度: 4 0 1 2 4 0 1 2 4 0 1 2 4 —Stack— Stack 长度: 0 Stack 长度: 5 Stack 长度: 4 Stack peekNum: 3 Stack search pos: 1 0 1 2 3 —HashMap— HashMap 长度: 0 HashMap 长度: 5 HashMap 长度: 4 HashMap 遍历方式 1 增强for循环遍历 Entry hashMap key: 0 hashMap value: 100 hashMap key: 1 hashMap value: 101 hashMap key: 3 hashMap value: 103 hashMap key: 4 hashMap value: 104 HashMap 遍历方式 2 通过迭代器遍历 key * key: 0 value: 100 key: 1 value: 101 key: 3 value: 103 key: 4 value: 104 HashMap 遍历方式 3 通过 增强for循环遍历 key key: 0 value: 100 key: 1 value: 101 key: 3 value: 103 key: 4 value: 104 HashMap 遍历方式 4 通过迭代器遍历 values, 无法得到 key值 value: 100 value: 101 value: 103 value: 104 HashMap 遍历方式 5 通过 增强for循环遍历 values, 无法得到 key值 value: 100 value: 101 value: 103 value: 104 —HashSet— HashSet 长度: 0 HashSet 长度: 5 0 1 2 3 4④ FAQ—集合类相关常见问题###1.集合类和数组的区别* 数组(可以存储基本数据类型)是用来存现对象的一种容器, 数组的长度固定, 适合在对象数量固定时使用.* 集合(只能存储对象,对象类型可以不一样)的长度可变,可在对象数量不固定时使用.###2.`ArrayList`和`LinkedList`区别* `ArrayList`和`LinkedList`在用法上没有区别,但是在功能上还是有区别的. `LinkedList`经常用在增删操作较多而查询操作很少的情况下, 比如队列和堆栈. `ArrayList`则相反.* ArrayList底层是Object数组,所以ArrayList具有数组的查询速度快的优点以及增删速度慢的缺点.而在LinkedList的底层是一种双向循环链表.在此链表上每一个数据节点都由三部分组成:前指针(指向前面的节点的位置),数据,后指针(指向后面的节点的位置).最后一个节点的后指针指向第一个节点的前指针,形成一个循环.双向循环链表的查询效率低但是增删效率高.* 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针.* 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据.ArrayList和LinkedList应用场景
若只对单条数据插入或删除,ArrayList的速度优于LinkedList. 但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据.
队列和栈
队列:先进先出的数据结构.
栈:后进先出的数据结构.
使用栈的时候, 不能提供非末尾元素出栈的方法.
3.HashTable
与HashMap
区别
Hashtable
是基于陈旧的Dictionary
类的,HashMap
是Java 1.2引入的Map
接口的一个实现Hashtable
是线程安全的,也就是说是同步的, 而HashMap
是线程序不安全的,不是同步的HashMap·允许存在一个为空(null)的
key,多个为空(null)的
value`.Hashtable
的key
和value
都不允许为空(null).
4.ArrayList
和Vector
区别
Vector
是线程同步的,所以它也是线程安全的. 而Arraylist
不是线程同步的. 如果不考虑到线程的安全因素,一般用Arraylist
效率比较高.- 如果集合中的元素的数目大于目前集合数组的长度时,
Vector
增长率为目前数组长度的100%
, 而Arraylist
增长率为目前数组长度的50%
. 在集合中使用数据量比较大的数据,用Vector
有一定的优势. - 如果查找一个指定位置的数据,
Vector
和Arraylist
使用的时间是相同的,都是O(1)
, 这个时候使用Vector
和Arraylist
都可以.
5.ArrayList
和Linklist
区别
ArrayList
和Vector
是采用数组方式存储数据, 此数组元素数大于实际存储的数据以便增加和插入元素, 都允许直接序号索引元素, 但是插入数据要设计到数组元素移动等内存操作, 所以索引数据快插入数据慢.Vector
由于使用了synchronized
方法(线程安全)所以性能上比ArrayList
要差.LinkedList
使用双向链表实现存储, 按序号索引数据需要进行向前或向后遍历, 但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!- 如果移动一个指定位置的数据花费的时间为
O(n-i)
,n
为总长度,
这个时候就应该考虑到使用Linklist
, 因为它移动一个指定位置的数据所花费的时间为O(1)
, 而查询一个指定位置的数据时花费的时间为O(i)
.
6.HashMap
与TreeMap
区别
TreeMap
实现SortedMap
, 元素顺序固定.HashMap
没有实现该接口.HashMap
通过hashcode
对其内容进行快速查找,HashMap
中元素的排列顺序是不固定的, 而TreeMap
中所有的元素都保持着某种固定的顺序. 如果需要得到一个有序的结果应该使用TreeMap
.- 在
Map
中插入、删除和定位元素,HashMap
是最好的选择. 但如果要按自然顺序或自定义顺序遍历键, 那么TreeMap
会更好. - 使用
HashMap
要求添加的键类明确定义了hashCode()
和equals()
的实现. 这个TreeMap
没有调优选项, 因为该树总处于平衡状态.
⑤ 相关文章
Java集成开发环境
- 15.Java集合类
- Java集合:集合类详解
- Java集合-常用集合类
- JAVA【集合一】集合类
- JAVA中的集合类
- JAVA中的集合类
- JAVA中的集合类
- Java集合类(整理)
- java集合类
- JAVA中的集合类
- Java集合类笔记
- JAVA中的集合类
- java集合类
- java集合类总结
- JAVA中的集合类 - -
- JAVA中的集合类
- java集合类
- java 集合类
- es6 箭头函数学习笔记
- Tomcat JDBCPool的使用
- linux-查看当前登录的用户
- Matlab 定义函数
- [FAQ04300]如何预置APK (KK及以前)
- 15.Java集合类
- 飞在Drone、AR的风口,却死在硬件创业的浪尖
- 在mapper的帮助类中怎么获取service
- 数据大小写的转换
- JVM读书笔记之性能监控与故障处理工具
- 字符串搜索算法kmp与Boyer-Moore,java实现
- iOS 不规则形状选择 svg方案,原生方案。
- 面试_技术问题_sevrlet与jsp
- 请输入一个大写字母用来转化为小写字母