java 集合详解
如有错误好请指正(持续更新中)
下面是集合的关系图
目录
- Collection
- 集合与数组的比较
- Collection 接口中的方法
- Collection 方法实例
- List
- List 接口中的方法
- ArrayList
- ArrayList的常用方法实现
- ArrayList的源码解析链接
- LinkedList
- LinkedLsit的扩容方式
- Vector
- Vector的常用方法
- Vector的子类 Stack
- List的总结
- Set
- HashSet
- TreeSet
1. 关于对重复元素的去重 - LinkedHashSet
- Set子类的总结
- Map
- Map的中的常用方法
- HashMap
- Hashtable
- TreeMap
- Iterator迭代器的使用
1.Collection
Collection是集合框架下的一个单列集合类的根接口 用于储存符合一些数据结构的元素有两个主要子接口 list 和set 位于java.util包下 使用时需要导包
1.1集合与数组的比较
- 数组的长度是固定的。集合的长度是可变的。
- 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。
- 集合和数组都是容器 用来保存元素
1.2Collection 接口中的方法
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public boolean add(E e) | 普通 | 向集合中插入一个元素 |
2 | public boolean addAll(Collection<? extends E> c) | 普通 | 向集合中插入一组元素 |
3 | public void clear() | 普通 | 清空集合中的元素 |
4 | public boolean contains(Object o) | 普通 | 查找一个元素是否存在 |
5 | public boolean containsAll(Collection<?> c) | 普通 | 查找一组元素是否存在 |
6 | public boolean isEmpty() | 普通 | 判断集合是否为空 |
7 | public Iterator iterator() | 普通 | 为 Iterator 接口实例化 |
8 | public boolean remove(Object o) | 普通 | 从集合中删除一个对象 |
9 | boolean removeAll(Collection<?> c) | 普通 | 从集合中删除一组对象 |
10 | boolean retainAll(Collection<?> c) | 普通 | 判断是否没有指定的集合 |
11 | public int size() | 普通 | 求出集合中元素的个数 |
12 | public Object[] toArray() | 普通 | 以对象数组的形式返回集合中的全部内容 |
13 | T[] toArray(T[] a) | 普通 | 指定操作的泛型类型, 并把内容返回 |
14 | public boolean equals(Object o) | 普通 | 从 Object 类中覆写而来 |
15 | public int hashCode() | 普通 | 从 Object 类中覆写而来 |
本接口中一共定义了 15 个方法, 那么此接口的全部子类或子接口就将全部继承以上接口中的方法 我们一般不会直接使用Collection接口 一般使用其子接口 list set
上述中出现 <?> 等 被称为 泛型
2.List
List接口 是 Collection 的子接口, 也就意味着继承了Collection里所有的方法,list的所有内容都是允许重复的
public interface List<E> extends Collection<E>
2.1 List 接口中的方法
list相比于Collection增加了一些更适合list集合操作的方法
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public void add(int index,E element) | 普通 | 在指定位置处增加元素 |
2 | boolean addAll(int index,Collection<? extends E> c) | 普通 | 在指定位置处增加一组元素 |
3 | public E get(int index) | 普通 | 根据索引位置取出每一个元素 |
4 | public int indexOf(Object o) | 普通 | 根据对象查找指定的位置, 找不到返回-1 |
5 | public int lastIndexOf(Object o) | 普通 | 从后面向前查找位置, 找不到返回-1 |
6 | public ListIterator listIterator() | 普通 | 返回 ListIterator 接口的实例 |
7 | public ListIterator listIterator(int index) | 普通 | 返回从指定位置的 ListIterator 接口的实例 |
8 | public E remove(int index) | 普通 | 删除指定位置的内容 |
9 | public E set(int index,E element) | 普通 | 修改指定位置的内容 |
10 | List subList(int fromIndex,int toIndex) | 普通 | 返回子集合 |
2.2 ArrayList
我们知道接口是无法直接使用的,需要使用其的实现类来完成一系列操作 而ArrayList就是List接口下的一个实现类
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, Serializable
ArrayList有两种构造方法 一种是无参构造 1.8 之后是创建一个 长度为0 的容器 在第一次添加后扩容默认库容长度10 ,1.8之前创建时就创建10单位的空间 第二个构造方法是 传入一个储存空间的大小 ArrayList是异步的 线程不安全
ArrayList<Integer> arrayList =new java.util.ArrayList<>();
//创建一个默认大小为100的list
ArrayList<Integer> arrayList1 = new java.util.ArrayList<>(100);
2.2.1 ArrayList 的常用方法实现
public static void main(String[] args) {
List<String> all = new ArrayList<String>(); // 实例化List对象, 并指定泛型类型
all.add("hello "); // 增加内容, 此方法从Collection接口继承而来
all.add(0, "LAMP ");// 增加内容, 此方法是List接口单独定义的
all.add("world"); // 增加内容, 此方法从Collection接口继承而来
all.remove(1); // 根据索引删除内容, 此方法是List接口单独定义的
all.remove("world");// 删除指定的对象
System.out.print("集合中的内容是: ");
for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来
System.out.print(all.get(x) + "、 "); // 此方法是List接口单独定义的
}
}
/**
* ArrayList 常用方法
* void clear() 从此列表中删除所有元素。
* boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素按指定集合的Iterator返回的顺序附加到此列表的末尾。
* void forEach(Consumer<? super E> action) 对 Iterable每个元素执行给定操作,直到处理 Iterable所有元素或操作引发异常。
* E get(int index) 返回此列表中指定位置的元素。
* int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
* boolean isEmpty() 如果此列表不包含任何元素,则返回 true 。
* Iterator<E> iterator() 以适当的顺序返回此列表中元素的迭代器。
* int lastIndexOf(Object o) 返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
* ListIterator<E> listIterator() 返回此列表中元素的列表迭代器(按适当顺序)。
* ListIterator<E> listIterator(int index) 从列表中的指定位置开始,返回列表中元素的列表迭代器(按正确顺序)。
* E remove(int index) 删除此列表中指定位置的元素。
* boolean remove(Object o) 从该列表中删除指定元素的第一个匹配项(如果存在)。
* boolean removeAll(Collection<?> c) 从此列表中删除指定集合中包含的所有元素。
* boolean removeIf(Predicate<? super E> filter) 删除此集合中满足给定谓词的所有元素。
* protected void removeRange(int fromIndex, int toIndex) 从此列表中删除索引介于 fromIndex (含)和 toIndex (独占)之间的所有元素。
* boolean retainAll(Collection<?> c) 仅保留此列表中包含在指定集合中的元素。
* E set(int index, E element) 用指定的元素替换此列表中指定位置的元素。
* int size() 返回此列表中的元素数。
* Spliterator<E> spliterator() 在此列表中的元素上创建late-binding和故障快速 Spliterator 。
* List<E> subList(int fromIndex, int toIndex) 返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
* Object[] toArray() 以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
* <T> T[] toArray(T[] a) 以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
* void trimToSize() 将此 ArrayList实例的容量调整为列表的当前大小。
*
*/
2.2.2 ArrayList的源码解析
因为涉及代码太多所以单独描述 ArrayList的源码解析链接
2.3 LinkedList
public class LinkedList extends AbstractSequentialList
implements List, Deque, Cloneable, Serializable
LinkedList 使用双向链表结构 增删快 查找慢 并允许所有元素(包括null )此类继承了 AbstractList, 所以是 List 的子类。 但是此类也是 Queue 接口的子类 也就是说拥有了一些队列的操作方法 Queue 接口定义了如下的方法:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public boolean add(E e) | 普通 | 增加元素, 如果有容量限制, 并且已满, 则抛出异常 |
2 | public E element() | 普通 | 取得, 但是不删除当前元素, 如果对列为空则抛出异常 |
3 | boolean offer(E e) | 普通 | 添加, 如果有容量限制, 并且已满, 只是无法添加,但不抛出异常, 返回 false |
4 | E peek() | 普通 | 取得头元素, 但是不删除, 如果队列为空, 则返回null |
5 | E poll() | 普通 | 取得头元素, 但是删除, 如果队列为空, 则返回 null |
6 | E remove() | 普通 | 删除当前元素, 如果对列为空则抛出异常 |
2.3.1 LinkedLsit的常用方法
/**
* 变量和类型 方法 描述
* void add(int index, E element) 将指定元素插入此列表中的指定位置。
* boolean add(E e) 将指定的元素追加到此列表的末尾。
* boolean addAll(int index, Collection<? extends E> c) 从指定位置开始,将指定集合中的所有元素插入此列表。
* boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素按指定集合的迭代器返回的顺序附加到此列表的末尾。
* void addFirst(E e) 在此列表的开头插入指定的元素。
* void addLast(E e) 将指定的元素追加到此列表的末尾。
* void clear() 从此列表中删除所有元素。
* Object clone() 返回此 LinkedList的浅表副本。
* boolean contains(Object o) 如果此列表包含指定的元素,则返回 true 。
* Iterator<E> descendingIterator() 以相反的顺序返回此双端队列中元素的迭代器。
* E element() 检索但不删除此列表的头部(第一个元素)。
* E get(int index) 返回此列表中指定位置的元素。
* E getFirst() 返回此列表中的第一个元素。
* E getLast() 返回此列表中的最后一个元素。
* int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
* int lastIndexOf(Object o) 返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
* ListIterator<E> listIterator(int index) 从列表中的指定位置开始,返回此列表中元素的列表迭代器(按正确顺序)。
* boolean offer(E e) 将指定的元素添加为此列表的尾部(最后一个元素)。
* boolean offerFirst(E e) 在此列表的前面插入指定的元素。
* boolean offerLast(E e) 在此列表的末尾插入指定的元素。
* E peek() 检索但不删除此列表的头部(第一个元素)。
* E peekFirst() 检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。
* E peekLast() 检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null 。
* E poll() 检索并删除此列表的头部(第一个元素)。
* E pollFirst() 检索并删除此列表的第一个元素,如果此列表为空,则返回 null 。
* E pollLast() 检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 。
* E pop() 弹出此列表所代表的堆栈中的元素。
* void push(E e) 将元素推送到此列表所表示的堆栈上。
* E remove() 检索并删除此列表的头部(第一个元素)。
* E remove(int index) 删除此列表中指定位置的元素。
* boolean remove(Object o) 从该列表中删除指定元素的第一个匹配项(如果存在)。
* E removeFirst() 从此列表中删除并返回第一个元素。
* boolean removeFirstOccurrence(Object o) 删除此列表中第一次出现的指定元素(从头到尾遍历列表时)。
* E removeLast() 从此列表中删除并返回最后一个元素。
* boolean removeLastOccurrence(Object o) 删除此列表中最后一次出现的指定元素(从头到尾遍历列表时)。
* E set(int index, E element) 用指定的元素替换此列表中指定位置的元素。
* int size() 返回此列表中的元素数。
* Spliterator<E> spliterator() 在此列表中的元素上创建late-binding和故障快速 Spliterator 。
* Object[] toArray() 以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
* <T> T[] toArray(T[] a) 以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
*
*/
方法的实现
public static void main(String[] args) {
Queue<String> queue = new LinkedList<String>();
queue.add("A");
queue.add("B");
queue.add("C");
int len=queue.size();//把queue的大小先取出来, 否则每循环一次, 移除一个元素, 就少
一个元素, 那么queue.size()在变小, 就不能循环queue.size()次了。
for (int x = 0; x <len; x++) {
System.out.println(queue.poll());
}
System.out.println(queue);
}
@Test
public void test1(){
LinkedList<Integer> linkedList = new LinkedList<>();
//可以模拟栈 使用 push() pop();
linkedList.push(100);
linkedList.push(200);
Integer pop = linkedList.pop();
System.out.println(pop);// 200
Integer pop1 = linkedList.pop();
System.out.println(pop1);// 100
}
2.4 Vector
与 ArrayList 一样, Vector 本身也属于 List 接口的子类,Vector 是同步访问的线程是安全的 (本质还是数组) 此类的定义如下:
public class Vector<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, Serializable
此类与 ArrayList 类一样, 都是 AbstractList 的子类。 所以, 此时的操作只要是 List 接口的子类就都按照 List 进行操作 AbstractList介绍
public static void main(String[] args) {
List<String> all = new Vector<String>(); // 实例化List对象, 并指定泛型类型
/**
* 构造器 描述
* Vector() 构造一个空向量,使其内部数据数组的大小为 10 ,其标准容量增量为零。
* Vector(int initialCapacity) 构造一个具有指定初始容量且容量增量等于零的空向量。
* Vector(int initialCapacity, int capacityIncrement) 构造具有指定初始容量和容量增量的空向量。
* Vector(Collection<? extends E> c) 按照集合的迭代器返回的顺序构造一个包含指定集合元素的向量。
*/
all.add("hello "); // 增加内容, 此方法从Collection接口继承而来
all.add(0, "LAMP ");// 增加内容, 此方法是List接口单独定义的
all.add("world"); // 增加内容, 此方法从Collection接口继承而来
all.remove(1); // 根据索引删除内容, 此方法是List接口单独定义的
all.remove("world");// 删除指定的对象
System.out.print("集合中的内容是: ");
for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来
System.out.print(all.get(x) + "、 "); // 此方法是List接口单独定义的
}
}
2.4.1 Vector的LinkedLsit的扩容方式
-
通过构造方法指定每次增加多少
-
通过内置函数
//源码 private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); //如果capacityIncrement(增量大于0 就是给了初值 就按初值来增 没有给 就原数组的长度*2) if (newCapacity - minCapacity <= 0) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return minCapacity; } return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity); }
2.4.2 Vector的子类 Stack (栈)
栈是一种数据结构 后进先出
堆栈只定义了默认构造函数,用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。
Stack<Iterator> stack=new Stack<>();
除了由Vector定义的所有方法,自己也定义了一些方法:
序号 | 方法描述 |
---|---|
1 | boolean empty() 测试堆栈是否为空。 |
2 | Object peek( )查看堆栈顶部的对象,但不从堆栈中移除它。 |
3 | Object pop( )移除堆栈顶部的对象,并作为此函数的值返回该对象。 |
4 | Object push(Object element)把项压入堆栈顶部。 |
5 | int search(Object element)返回对象在堆栈中的位置,以 1 为基数。 |
2.6 List总结
- List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变
- List接口是一个有序的 可以有重复元素的
- 使用场景的选择:
- 对于需要快速插入、删除元素,则需使用LinkedList。
- 对于需要快速访问元素,则需使用ArrayList。
- List只能被一个线程操作,如果是多线程环境,List可能同时被多个线程操作,造成错误 考虑使用同步的类(如Vector)。
No. | 区别点 | ArrayList | Vector |
---|---|---|---|
1 | 时间 | 是新的类, 是在 JDK 1.2 之后推出的 | 是旧的类是在 JDK 1.0 的时候就定义的 |
2 | 性能 | 性能较高, 是采用了异步处理 | 性能较低, 是采用了同步处理 |
3 | 输出 | 支持 Iterator、 ListIterator 输出 | 除了支持 Iterator、 ListIterator 输出, 还支持Enumeration 输出 |
4 | 安全 | 异步的 线程不安全 | 同步的 线程安全 |
3. Set
Set 接口也是 Collection 的子接口, 与 List 接口最大的不同在于, Set 接口里面的内容是不允许重复的。
Set 接口并没有对 Collection 接口进行扩充, 基本上还是与 Collection 接口保持一致。 因为此接口没有 List 接口中定义的 get(int index)方法, 所以无法使用循环进行输出。
那么在此接口中有两个常用的子类: HashSet、 TreeSet
3.1 HashSet
因为Set没有实现get(int index)方法所以我们没法通过循环去输出他 那么我们可以通过什么方法去遍历呢?
@Test
public void test(){
Set<String> all = new HashSet<String>(); // 实例化Set接口对象
all.add("A");
all.add("B");
all.add("C");
all.add("D");
all.add("E");
Object obj[] = all.toArray(new String[] {}); // 将集合变为对象数组
for (int x = 0; x < obj.length; x++) {
System.out.print(obj[x] + "、 ");
}
}
也可以通过forEach
@Test
public void test1(){
Set<String> all = new HashSet<String>(); // 实例化Set接口对象
all.add("A");
all.add("B");
all.add("C");
all.add("D");
all.add("E");
for (String s: all) {
System.out.println(s);
}
}
通过虽然说Set是无序的 但是对针对我们存储的循序 其内部的排序有默认的! 比如上面我们add A B C D E 打印就是顺序打印的 但是如果我们输入的顺序是 A C D B E 输出顺序依然是 A B C D E 使用的是散列存放后面我们会详细说明
3.2 TreeSet
与 HashSet 不同的是, TreeSet 本身属于排序的子子类( NavigableSet继承与SortedSet接口 SortedSet是红黑树排序), 此类的定义如下:
public class TreeSet<E> extends AbstractSet<E>implements NavigableSet<E>, Cloneable, Serializable
NavigableSet继承与SortedSet 我们重点介绍对自定义类型排序的介绍
/**
* 必须实现 Comparable接口并且实现compareTo 要不然 无法排序 报java.lang.ClassCastException:
*
*/
class Person implements Comparable<Person>{
private String name;
private int age;
public int compareTo(Person per) {
if (this.age > per.age) {
return 1; //返回 1表示大 则排在被比较的元素后面 -1表示小 则排在被比较元素前面 0 表示相同需要在判断其他属性进行判断 如不判断会抵消之前相同的元素因为这样会被判断成相同元素 此时的排序规则以compareTo()规定
} else if (this.age < per.age) {
return -1;
}else return this.name.compareTo(per.name);
//else if (this.age == per.age) {
// if (this.name.charAt(0) > per.name.charAt(0)) {
// return 1;
// } else if (this.name.charAt(0) < per.name.charAt(0)) {
// return -1;
// }
}
return 0;
}
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;
}
public String toString() {
return "姓名: " + this.name + ", 年龄: " + this.age;
}
}
上面为什么可以对 String进行排序呢?因为String实现Comparable接口
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
测试类
/**
* 自定义类排序
*
*/
@Test
public void test1(){
Set<Person> all = new TreeSet<Person>();
all.add(new Person("张三", 10));
all.add(new Person("李四", 10));
all.add(new Person("王五", 11));
all.add(new Person("赵六", 12));
all.add(new Person("孙七", 13));
System.out.println(all);//[姓名: 张三, 年龄: 10, 姓名: 王五, 年龄: 11, 姓名: 赵六, 年龄: 12, 姓名: 孙七, 年龄: 13]
}
3.2.1 关于对重复元素的去重
上述我们说到实现Comparable 接口如果不对比较元素相同的情况下进行判断就会出现去重的现象 那么Set去重的原理是什么呢?我们知道HashSet 是不能有重复元素的那么使用HashSet能不能去重呢?
@Test
public void test(){
Set<Person> all = new HashSet<Person>();
all.add(new Person("张三", 10));
all.add(new Person("李四", 10));
all.add(new Person("李四", 10));
all.add(new Person("王五", 11));
System.out.println(all);//[姓名: 张三, 年龄: 10, 姓名: 李四, 年龄: 10, 姓名: 王五, 年龄: 11, 姓名: 李四, 年龄: 1
}
我们发现并没有去重 也就是说之前我们说 使用 Comparable接口 作为排序的依据是对的,那么Set集合究竟是如何去重的呢?我们知道判断一个对象相不相等 有两个条件
- 编码是否一致 即 hashCode 是否相等
- 每个属性是否相等, 需要通过 equals()完成
那么在之前的Person类中追加代码
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Person)) {
return false;
}
Person per = (Person) obj;
if (per.name.equals(this.name) && per.age == this.age) {
return true;
} else {
return false;
}
}
public int hashCode() {
return this.name.hashCode() * this.age;
}
这时候我们发现成功的去重了
小结:
关于 TreeSet 的排序实现, 如果是集合中对象是自定义的或者说其他系统定义的类没有实现
Comparable 接口, 则不能实现 TreeSet 的排序, 会报类型转换(转向 Comparable 接口) 错误。
换句话说要添加到 TreeSet 集合中的对象的类型必须实现了 Comparable 接口。
不过 TreeSet 的集合因为借用了 Comparable 接口, 同时可以去除重复值, 而 HashSet 虽然是
Set 接口子类, 但是对于没有复写 Object 的 equals 和 hashCode 方法的对象, 加入了 HashSet
集合中也是不能去掉重复值的
3.3 LinkedHashSet
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable
我们知道HashSet保证元素唯一,但是无序的我们如果想要保存一个唯一的集合而且有是按照添加顺序进行排序的集合怎么办呢?在HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结
构。 可以保证储存的数据是有序的
@Test
public void test(){
LinkedHashSet<Integer> set= new LinkedHashSet<>();
set.add(1);
set.add(3);
set.add(2);
System.out.println(set);//[1, 3, 2]
}
3.4 Set总结
- 不允许存储重复元素(根据重写hashCode()和equals()方法来判断是不是同一对象)。
- 没有索引,没有带索引的方法,所以也就不能使用普通for循环。
HashSet 在Set以上的基础上多了
- HashSet是一个无序集合,存的顺序和取的顺序不一样。
- 底层是哈希表现实的。
- 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变
TreeSet 在Set基础上多了
- 可以根据实现Comparable接口中的compareTo() 来进行排序 常用数据类型基本都实现了该接口
- 所有的数值型对应的包装类:按它们对应的数值大小进行比较
- Character:按字符的 unicode值来进行比较
- String:按字符串中字符的 unicode 值进行比较
- Date、Time:后边的时间、日期比前面的时间、日期大
- Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变
LinkedHashSet在Set的上多了:
- 是一个有序集合 按照添加的顺序排列
4 Map
public interface Map<K,V>
可以看出Map接口与Collection接口没有任何关系 是与Collection接口同等级的 是第二大集合操作接口
Map是键值对集合 以 key:value保存
比如 保存 人的手机号码时
张三 15214645455
李四 12345678911
使用Collection集合就不容易保存 但是使用键值对的方式就比较简单
4.1 Map接口中的方法
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | void clear() | 普通 | 清空 Map 集合中的内容 |
2 | boolean containsKey(Object key) | 普通 | 判断集合中是否存在指定的 key |
3 | boolean containsValue(Object value) | 普通 | 判断集合中是否存在指定的 value |
4 | Set<Map.Entry<K,V>> entrySet() | 普通 | 将 Map 接口变为 Set 集合 |
5 | V get(Object key) | 普通 | 根据 key 找到其对应的 value |
6 | boolean isEmpty() | 普通 | 判断是否为空 |
7 | Set keySet() | 普通 | 将全部的 key 变为 Set 集合 |
8 | Collection values() | 普通 | 将全部的 value 变为 Collection 集合 |
9 | V put(K key,V value) | 普通 | 向集合中增加内容 |
10 | void putAll(Map<? extends K,? extends V> m) | 普通 | 增加一组集合 |
11 | V remove(Object key) | 普通 | 根据 key 删除内容 |
4.2 HashMap
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
此类继承了 AbstractMap 类, 同时可以被克隆, 可以被序列化下来。HashMap本身是无序存放的
线程不安全但是可以通过同步包装器包装的HashMap(Collections.synchronizedMap(Map<K,V> m) )来实现同步
public class HashMapDemo01 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "张三A");
map.put(1, "张三B"); // 新的内容替换掉旧的内容
map.put(2, "李四");
map.put(3, "王五");
String val = map.get(6);
String s = map.get(1);
System.out.println(s);//张三B
System.out.println(val);//null
}
/**
* 其他方法
*
*/
@Test
public void test(){
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "张三A");
map.put(2, "李四");
map.put(3, "王五");
Set<Integer> set = map.keySet(); // 得到全部的key
Collection<String> value = map.values(); // 得到全部的value
Iterator<Integer> iter1 = set.iterator();
Iterator<String> iter2 = value.iterator();
System.out.print("全部的key: ");
while (iter1.hasNext()) {
System.out.print(iter1.next() + "、 ");
}
System.out.print("\n全部的value: ");
while (iter2.hasNext()) {
System.out.print(iter2.next() + "、 ");
}
}
}
4.3 Hashtable
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
Hashtable 是一个最早的 key->value 的操作类, 本身是在 JDK 1.0 的时候推出的。 其基本操作与 HashMap 是类似的。
public static void main(String[] args) {
Map<String, Integer> numbers = new Hashtable<String, Integer>();
numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);
Integer n = numbers.get("two");
if (n != null) {
System.out.println("two = " + n);
}
}
和HashMap的区别
No. | 区别点 | HashMap | Hastable |
---|---|---|---|
1 | 推出时间 | JDK 1.2 之后推出的, 新的操作类 | JDK 1.0 时推出的, 旧的操作类 |
2 | 性能 | 异步处理, 性能较高 | 同步处理, 性能较低 |
3 | null | 允许设置为 null | 不允许设置, 否则将出现空指向异常 |
4.4 TreeMap
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
TreeMap 子类是允许 key 进行排序的操作子类, 其本身在操作的时候将按照 key 进行排序, 另外, key 中的内容可以为任意的对象, 但是要求对象所在的类必须实现 Comparable 接口。
public static void main(String[] args) {
Map<String, String> map = new TreeMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
Set<String> set = map.keySet(); // 得到全部的key
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
String i = iter.next(); // 得到key
System.out.println(i + " --:> " + map.get(i));
}
}
Iterator迭代器的使用
Iterator迭代器用于遍历集合中的数据 其原理就像有一个指针在最初的时候指向-1 每调用next() 指针就加 1 并且返回改数据 有两个常用方法
public E next() :返回迭代的下一个元素。
public boolean hasNext() :如果仍有元素可以迭代,则返回 true。
public class RunoobTest {
public static void main(String[] args) {
// 创建集合
ArrayList<String> sites = new ArrayList<String>();
sites.add("1");
sites.add("2");
sites.add("3");
sites.add("4");
// 获取迭代器
Iterator<String> it = sites.iterator();
// 输出集合中的第一个元素
System.out.println(it.next()); //1
while(iterator.hasNext()){
Integer next = iterator.next();
System.out.println(next); // 2,3,4
}
}
}