1.集合框架的优点
传统的容器(数组)在进行增、删等破坏性操作时,需要移动元素,可能导致性能问题;同时添加、删除等算法和具体业务耦合在一起,增加了程序开发的复杂度。
Java集合框架提供了一套性能优良、使用方便的接口和类,它们位于java.util包中。
2.Collection
Collection是java集合框架(collection-frame)中的顶层接口。
Collection接口是一个容器,容器中只能存储引用数据类型,建议存同一类型的引用类型,方便后续遍历等操作。
容器中的元素可以是有序的、可重复的,称为List接口;也可能是无序的、唯一的,称为Set接口。
1).集合常用方法
1 public static void main(String[] args) { 2 3 /** 4 * 增:add/addAll 5 * 删:clear/remove/removeAll/retainAll 6 * 改: 7 * 查:contains/containsAll/isEmpty/size 8 */ 9 10 Collectionc1 = newArrayList(); 11 12 // 追加 13 c1.add("apple"); // Object object = new String("apple"); 14 // c1.add(1); // Object object = new Integer(1); 15 c1.add("banana"); 16 System.out.println(c1); 17 18 // 追加一个集合 19 Collectionc2 = newArrayList(); 20 c2.add("java"); 21 c2.add("c++"); 22 c1.addAll(c2); 23 System.out.println(c1); 24 25 // clear 26 //c1.clear(); 27 28 // c1.remove("apple"); 29 // c1.removeAll(c2); 30 //c1.retainAll(c2); 31 //System.out.println(c1); 32 33 System.out.println(c1.contains("apple")); 34 c2.add("js"); 35 System.out.println(c1.containsAll(c2)); 36 // c1.clear(); 37 System.out.println(c1.isEmpty()); 38 // 返回集合元素的个数 39 System.out.println(c1.size()); 40 41 System.out.println(c1.equals(c2)); 42 43 }
2).集合的遍历
Iterable可遍历的接口,集合接口继承于它,集合支持快速遍历。
1 // 快速遍历 2 // for-each 3 // Object 表示元素类型 4 // item表示迭代变量 5 // c1表示集合 6 for (Object item : c1) { 7 System.out.println(item.toString()); 8 }
快速遍历的本质:
Collection继承Iterable接口,表示集合支持快速遍历。Iterable接口定义了一个方法iterator()用于获取集合的迭代器,是一个Iterator接口类型,iterator()内部返回一个实现类实现类Iterator接口。这个实现类一定具有hasNext和next方法用于判断是否有下一个元素和获取下一个元素。快速遍历就是基于迭代器工作的。
迭代器遍历如下:
1 public static void main(String[] args) { 2 3 4 Collectionc1 = newArrayList(); 5 c1.add("apple"); 6 c1.add("banana"); 7 c1.add("coco"); 8 9 10 // 快速遍历 11 // for-each 12 // Object 表示元素类型 13 // item表示迭代变量 14 // c1表示集合 15 for (Object item : c1) { 16 System.out.println(item.toString()); 17 } 18 19 // 迭代器遍历(国内) 20 Iteratorit = c1.iterator(); 21 while(it.hasNext()) { 22 Object item = it.next(); 23 System.out.println(item.toString()); 24 } 25 26 // 国外 27 for(Iteratorit2=c1.iterator();it2.hasNext();) { 28 Object item = it2.next(); 29 System.out.println(item.toString()); 30 } 31 }
3.List接口
List 接口中的元素时有序的、可重复的。List接口中的元素通过索引(index)来确定元素的顺序。
有序的 collection(也称为序列)。可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素
1).List常用方法
1 public static void main(String[] args) { 2 3 /** 4 * 增:add/addAll/add(index,el)/addAll(index,collection) 5 * 删:clear/remove/removeAll/remove(index) 6 * 改:set(index,el) 7 * 查:get(index)/indexOf/lastIndexOf() 8 * 其他:contains/containsAll/isEmpty/size 9 */ 10 Listlist1 = newArrayList(); 11 // 添加元素 12 list1.add("apple"); 13 list1.add("banana"); 14 // 在指定位置添加元素 15 list1.add(0, "coco"); 16 17 System.out.println(list1); 18 19 Listlist2 = newArrayList(); 20 list2.add("java"); 21 list2.add("c++"); 22 23 list1.addAll(1, list2); 24 System.out.println(list1); 25 26 // 删除 27 list1.remove(0); 28 System.out.println(list1); 29 30 // 修改 31 list1.set(0, "javax"); 32 System.out.println(list1); 33 34 // 查 35 System.out.println(list1.get(0)); 36 list1.add("apple"); 37 list1.add("apple"); 38 System.out.println(list1); 39 System.out.println(list1.indexOf("apple")); 40 System.out.println(list1.lastIndexOf("apple")); 41 }
2).List接口遍历
定义: ListIterator 继承于Iterator,在Iterator的基础上提供了以正向遍历集合,也可以以逆序遍历集合合。
——hasNext/next 以正向遍历
——hasPrevious/previous 以逆序遍历
1 public static void main(String[] args) { 2 3 4 List list1 = new ArrayList(); 5 list1.add("apple"); 6 list1.add("banana"); 7 list1.add("coco"); 8 9 // 【1】快速遍历 10 System.out.println("--for each--"); 11 for (Object item : list1) { 12 System.out.println(item.toString()); 13 } 14 15 // 【2】普通for 16 System.out.println("--for--"); 17 for(inti=0;i<list1.size();i++) { 18 System.out.println(list1.get(i)); 19 } 20 21 // 【3】集合迭代器 22 System.out.println("--iterator--"); 23 Iterator it = list1.iterator(); 24 while(it.hasNext()) { 25 System.out.println(it.next()); 26 } 27 28 System.out.println("--list iterator--"); 29 // 正向遍历 30 ListIterator it2 = list1.listIterator(); 31 while(it2.hasNext()) { 32 System.out.println(it2.next()); 33 } 34 35 // 逆序遍历 36 while(it2.hasPrevious()) { 37 System.out.println(it2.previous()); 38 } 39 40 System.out.println("--list iterator with index--"); 41 ListIteratorit3 = list1.listIterator(1); 42 while(it3.hasNext()) { 43 System.out.println(it3.next()); 44 } 45 }
4.数据结构
定义:数据结构就是数据在内存中存储结构。根据存储的方式不同,分为线性表、二叉树、图、栈、队列等
1).线性表
线性表数据按照一定的逻辑顺序存储在内存中。线性表是有序的。
线性表根据内存的物理结构分为两种:数组和链表
[1].数组是一种逻辑上有序的线性表,物理上也连续。
[2].链表是一种逻辑上有序的线性表,但物理上不连续。
数组和链表的区别:
相同点:都是按照一定的逻辑顺序
不同点:数组在物理上是连续的,所以数组在查询时效率高,在添加、删除元素时效率低(涉及移素);
而链表在物理上是不连续的,所以链表在查询时效率低(每次从头开始,不能跳跃访问),在添 加、删除元素时效率高(不涉及移动元素)
2).栈
元素进出本质:先进后出,后进先出
3).队列
元素进出本质:先进先出,后进后出
5.ArrayList /Vector
——ArrayList 是List接口的实现类,底层数据结构是数组,实现大小可变的数组。
ArrayList线程不安全,jdk1.2
——ArrayList底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,ArrayList会自动拓容,拓容原则:newCapacity = oldCapacity+oldCapacity/2;如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。
——ArrayList作为List接口的实现类,常用方法和遍历方法参考List接口。
——Vector是List接口的实现类,底层数据结构也是数组,也是大小可变的数组。
Vector是线程安全的,jdk1.0
——Vector底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,Vector会自动拓容,拓容原则:newCapacity = oldCapacity +capacityIncrement(增长因子);如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。
——注:Vector 在实现List接口的同时,同添加了自身特有的方法xxxElement,未来使用时为了程序的可拓展性,一定要按照接口来操作Vector。
6.LinkedList
LinkedList是List接口的实现类,底层数据结构是链表。
LinekList常用方法和遍历方法参照List接口。
LinkedList 线程不安全,没有相对应的线程安全的接口,有以下方法:
线程安全语法:List list = Collections.synchronizedList(new LinkedList(...));
除了实现List接口,还实现栈接口,队列接口,双向队列接口
1).栈接口
push入栈操作/pop出栈操作
1 public class Test01 { 2 public static void main(String[] args) { 3 LinkedList list = new LinkedList(); 4 list.push("apple"); 5 list.push("banana"); 6 list.push("coco"); 7 8 9 System.out.println(list.pop()); 10 System.out.println(list.pop()); 11 System.out.println(list.pop()); 12 13 // java.util.NoSuchElementException 14 System.out.println(list.pop()); 15 } 16 }
2).队列(Queue)接口
add/remove/element() 可能会出现NoSuchElementException异常
1 public static void main(String[] args) { 2 3 LinkedListqueue = newLinkedList(); 4 // 入队 5 /** 6 * 队列头 队列尾 7 *<----- <----- 8 * [apple, banana, coco] 9 */ 10 queue.add("apple"); 11 queue.add("banana"); 12 queue.add("coco"); 13 System.out.println(queue); 14 15 // 出队 16 System.out.println(queue.remove()); 17 System.out.println(queue.remove()); 18 System.out.println(queue.remove()); 19 System.out.println(queue); 20 21 // java.util.NoSuchElementException 22 System.out.println(queue.remove()); 23 24 25 // 获取表头元素 26 System.out.println(queue.element()); 27 }
offer/poll/peek 可能会返回特殊值(null)
1 public static void main(String[] args) { 2 3 LinkedListqueue = newLinkedList(); 4 // 入队 5 /** 6 * 队列头 队列尾 7 *<----- <----- 8 * [apple, banana, coco] 9 */ 10 queue.offer("apple"); 11 queue.offer("banana"); 12 queue.offer("coco"); 13 14 // 出队列 15 //System.out.println(queue.poll()); 16 //System.out.println(queue.poll()); 17 //System.out.println(queue.poll()); 18 System.out.println(queue); 19 20 //System.out.println(queue.poll()); 21 22 // 获取表头元素 23 System.out.println(queue.peek()); 24 25 }
3).双向队列(Deque)接口
1 /** 2 * 以双向队列形式操作LinkedList 3 */ 4 public class Test04 { 5 publicstaticvoid main(String[] args) { 6 7 LinkedListqueue = newLinkedList(); 8 // 入队 9 /** 10 *<----- <----- 11 * [apple, banana, coco] 12 * ----> -----> 13 */ 14 15 queue.addFirst("apple"); 16 queue.addFirst("banana"); 17 queue.addFirst("coco"); 18 System.out.println(queue); 19 20 System.out.println(queue.removeLast()); 21 System.out.println(queue.removeFirst()); 22 System.out.println(queue.removeFirst()); 23 System.out.println(queue); 24 25 // 获取头元素 26 System.out.println(queue.getFirst()); 27 28 } 29 }
7.Iterator和ListIterator
1).Iterator在迭代过程中不允许向集合中添加元素
1 public static void main(String[] args) { 2 ArrayList list = new ArrayList(); 3 list.add("apple"); 4 list.add("banana"); 5 list.add("coco"); 6 7 Iteratorit = list.iterator(); 8 while(it.hasNext()) { 9 String item = (String) it.next(); 10 if(item.equals("banana")) { 11 list.add("test"); 12 } 13 } 14 15 System.out.println(list); 16 }
当通过Iterator集合迭代器遍历集合过程中,不能再向集合汇总添加元素,否则出现ConcurrentModificationException并发修改异常。
2).ListIterator允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置
1 publicclass Test01 { 2 public static void main(String[] args) { 3 ArrayListlist = newArrayList(); 4 list.add("apple"); 5 list.add("banana"); 6 list.add("coco"); 7 8 ListIteratorit = list.listIterator(); 9 while(it.hasNext()) { 10 String item = (String) it.next(); 11 if(item.equals("banana")) { 12 it.add("test"); 13 } 14 } 15 16 System.out.println(list); 17 } 18 }
注:为了更加了解以上可以去熟悉Iterator实现类的源码hasNext/next
8.泛型(generic)
1).泛型的概念
泛型允许开发者在强类型程序设计语言(java)编写代码时定义一些可变部分,这些部分在使用前必须作出指明。
泛型本质就是将类型参数化
——ArrayList<E> list表示声明了一个列表list,列表的元素是E类型
——ArrayList<String> list = new ArrayList<String>();
声明了一个列表list,列表的元素只能是String类型。
2).泛型的擦除
注意:泛型在编译器起作用,运行时jvm察觉不到泛型的存在。(泛型在运行过程中被擦除了)
1 public static void main(String[] args) { 2 ArrayList<String>list = new ArrayList<String>(); 3 list.add("apple"); 4 System.out.println(listinstanceof ArrayList); 5 System.out.println(listinstanceof ArrayList<String>);//抛出异常
System.out.println(listinstanceof ArrayList<?>);//正确 6 }
会抛出异常:Cannot perform instanceof check against parameterized type ArrayList<String>. Use the form ArrayList<?> instead since further generic type information will be erased at runtime
3).泛型的应用
[1].泛型类
当一个类中属性的数据类型不确定时,具体是什么类型由使用者来确定时,使用泛型。
泛型类的形式
public class 类名<T>{ }
定义一个泛型类
1 public class FanClass<T> { 2 private T t; 3 4 public T getT() { 5 returnt; 6 } 7 8 publicvoid setT(T t) { 9 this.t = t; 10 } 11 12 public FanClass(T t) { 13 super(); 14 this.t = t; 15 } 16 17 public FanClass() { 18 super(); 19 } 20 }
1 public class Test01 { 2 publicstaticvoid main(String[] args) { 3 FanClass<String>fan = new FanClass<String>(); 4 fan.setT("apple"); 5 6 FanClass<Integer>fan2 = new FanClass<Integer>(); 7 fan2.setT(1); 8 } 9 }
[2].泛型方法
当一个方法的参数类型不确定时,具体是什么类型由使用者来确定,可以考虑使用泛型方法。
形式如下:
public<T> void xxx(T a) { System.out.println(a); }
定义一个泛型的方法:
1 public class Student { 2 3 4 /*public void showInfo(int a) { 5 System.out.println(a); 6 } 7 8 public void showInfo(float a) { 9 System.out.println(a); 10 } 11 12 public void showInfo(String a) { 13 System.out.println(a); 14 }*/ 15 16 public<T>void showInfo(Ta) { 17 System.out.println(a); 18 } 19 }
public static void main(String[] args) { Student stu = new Student(); stu.showInfo(1); stu.showInfo("apple"); stu.showInfo(1.0f); }
注:泛型方法在调用时确定(指明)类型。
——泛型方法在一定程度上优化了方法重载。
泛型方法可以定义多个泛型类型
// 可以定义多个泛型的类型 public<A,B>void showInfo(Aa,B b) { System.out.println(a); System.out.println(b); }
注:多个泛型类型进一步优化了方法重载。
多个同类型的泛型
1 // 多个同类型的泛型 2 /*public <A> void print(A a) { 3 System.out.println(a); 4 } 5 public <A> void print(A a,A b) { 6 System.out.println(a); 7 System.out.println(b); 8 }*/ 9 10 public<A>void print(A...a) { 11 System.out.println(a); 12 }
A… a 表示方法可以接受多个参数。当调用方法传递多个参数时,多个参数被放到a数组中,a是什么类型的数组由开发者调用处传参决定。
stu.print(1); stu.print(1,2); stu.print("apple"); stu.print("apple","banana");
print(A...a)方法称为可变参数的泛型形式。
4) 泛型接口
如果接口中的方法的参数(形参、返回值)不确定时,可以考虑使用泛型接口。形式
public interface FanInterface<T> { public void showInfo(T t); }
[1]实现类能确定泛型接口的类型
publicclass ImplClass implements FanInterface<String>{ @Override publicvoid showInfo(Stringt) { // TODO Auto-generated method stub } }
[2]实现类不能确定泛型接口的类型->继续泛。
public class ImplClass2<T>implements FanInterface<T>{ @Override publicvoid showInfo(T t) { } }
5) 泛型的上限和下限
public static void print(ArrayList<? extendsPet>list) { for (Petpet : list) { pet.showInfo(); } }
泛型的上限ArrayList(? extends Pet) list 声明了一个容器,容器中的元素类型一定要继承于Pet,我们称这种形式叫做泛型的上限。
泛型的下限ArrayList(? super Pet) list 声明了一个容器,容器中的元素类型一定要是Pet的父类,我们称这个形式为泛型的下限。
9. Set接口
Set接口表示一个唯一、无序的容器(和添加顺序无关)
1).Set接口提供的方法
1 public static void main(String[] args) { 2 3 /** 4 5 * 增:add/addAll 6 7 * 删:clear/remove/removeAll/retainAll 8 9 * 改: 10 11 * 查:contains/containsAll 12 13 * 遍历:iterator 14 15 * 其他:size/isEmpty 16 17 */ 18 19 20 21 Set<Integer>set = new HashSet<Integer>(); 22 23 // [1]添加 24 25 // 无序 26 27 set.add(10); 28 29 set.add(3); 30 31 set.add(20); 32 33 set.add(0); 34 35 // 不能添加重复元素 36 37 booleanr = set.add(1); 38 39 System.out.println(set); 40 41 42 43 // 【2】删除 44 45 // set.remove(1); 46 47 // set.clear(); 48 49 // System.out.println(set); 50 51 52 53 // 【3】查看是否包含 54 55 System.out.println(set.contains(1)); 56 57 58 59 // 【4】其他 60 61 System.out.println(set.size()); 62 63 System.out.println(set.isEmpty()); 64 65 }
2)Set接口的遍历
public static void main(String[] args) { Set<String>set = new HashSet<String>(); set.add("banana"); set.add("apple"); set.add("coco"); // 快速遍历 for (String item : set) { System.out.println(item); } // 迭代器 Iterator<String>it = set.iterator(); while(it.hasNext()) { String item = it.next(); System.out.println(item); } }
Set接口的实现类常见的有HashSet、LinkedHashSet、TreeSet
10. HashSet
HashSet是Set接口的实现类,底层数据结构是哈希表。
HashSet是线程不安全的(不保证同步)
1) 哈希表工作原理
2) 添加自定义对象
根据哈希表的工作原理,请存储一个自定义对象到HashSet中。
1 package cn.sxt03.hashset; 2 3 4 5 public class Student { 6 7 private String id; 8 9 private String name; 10 11 privateintage; 12 13 14 15 // … 16 17 18 19 20 21 @Override 22 23 publicinthashCode() { 24 25 finalintprime = 31; 26 27 intresult = 1; 28 29 result = prime * result + age; 30 31 result = prime * result + ((id == null) ? 0 : id.hashCode()); 32 33 result = prime * result + ((name == null) ? 0 : name.hashCode()); 34 35 returnresult; 36 37 } 38 39 40 41 @Override 42 43 publicbooleanequals(Object obj) { 44 45 if (this == obj) 46 47 returntrue; 48 49 if (obj == null) 50 51 returnfalse; 52 53 if (getClass() != obj.getClass()) 54 55 returnfalse; 56 57 Student other = (Student) obj; 58 59 if (age != other.age) 60 61 returnfalse; 62 63 if (id == null) { 64 65 if (other.id != null) 66 67 returnfalse; 68 69 } elseif (!id.equals(other.id)) 70 71 returnfalse; 72 73 if (name == null) { 74 75 if (other.name != null) 76 77 returnfalse; 78 79 } elseif (!name.equals(other.name)) 80 81 returnfalse; 82 83 returntrue; 84 85 } 86 87 88 89 @Override 90 91 public String toString() { 92 93 return"Student [id=" + id + ", name=" + name + ", age=" + age + "]"; 94 95 } 96 97 98 99 }
总结
[1]如果向HashSet中存储元素时,元素一定要实现hashCode方法和equals方法。
[2]优点:添加、删除、查询效率高;缺点:无序
11.LinkedHashSet
LinkedHashSet是Set接口的实现类,底层数据结构哈希表+链表
哈希表用于散列元素;链表用于维持添加顺序。
如果要添加自定义对象元素,也需要重写hashCode和equals方法。
12. TreeSet
TreeSet 是Set接口的实现类,底层数据结构是二叉树。
TreeSet存储的数据按照一定的规则存储。存储规则让数据表现出自然顺序。
1) TreeSet工作原理
——添加一个新元素t的存储的步骤
[1]如果集合无元素,t直接加入;如果集合有元素,t和根节点比较;
[2] 如果t小于根节点;把t放到根节点的左子树上;重复1-3步骤
[3]t大于根节点;把t放到根节点的右子树上;重复1-3步骤
——输出时按照一定的规则:左子树->根节点->右子树
2)内部比较器和外部比较器
根据TreeSet的工作原理,向TreeSet添加自定义元素?
向TreeSet中添加元素时,一定要提供比较策略,否则会出现ClassCastException。
比较策略分两种:内部比较器和外部比较器
[1] 内部比较器
当一个自定义对象实现Comparable并实现compareTo方法时,通过指定具体的比较策略,此时称为内部比较器。
1 package cn.sxt05.treeset; 2 3 4 5 public class Student implements Comparable<Student>{ 6 7 private String id; 8 9 private String name; 10 11 privateintage; 12 13 14 15 // 。。。 16 17 18 19 @Override 20 21 public String toString() { 22 23 return"Student [id=" + id + ", name=" + name + ", age=" + age + "]"; 24 25 } 26 27 28 29 @Override 30 31 publicintcompareTo(Student o) { 32 33 if(this.getAge()<o.getAge()) { 34 35 return -1; 36 37 }elseif(this.getAge() == o.getAge()) { 38 39 return 0; 40 41 }else { 42 43 return 1; 44 45 } 46 47 } 48 49 }
比较策略的几种情况
—1—比较策略一般当前对象写在前面,待比较对象也在后面,比较结果默认升序
returnthis.getAge() - o.getAge() ; |
如果想要降序,改变两个比较对象的位置即可。
—2—-多种比较因素
1 @Override 2 3 public int compareTo(Student o) { 4 5 /*if(this.getAge()<o.getAge()) { 6 7 return -1; 8 9 }else if(this.getAge() == o.getAge()) { 10 11 return 0; 12 13 }else { 14 15 return 1; 16 17 }*/ 18 19 20 // return this.getAge() - o.getAge() ; 21 22 if(this.getAge()<o.getAge()) { 23 24 return -1; 25 26 }elseif(this.getAge() == o.getAge()) { 27 28 returnthis.getName().compareTo(o.getName()); 29 30 }else { 31 32 return 1; 33 34 } 35 36 }
[2] 外部比较器
当实际开发过程中不知道添加元素的源代码、无权修改别人的代码,此时可以使用外部比较器。
Comparator位于java.util包中,定义了compare(o1,o2) 用于提供外部比较策略。
TreeSet接受一个指定比较策略的构造方法,这些比较策略的实现类必须实现Comparator
接口。
需求:按照字符串的长度比较
1 publicclass Test01 { 2 3 public static void main(String[] args) { 4 5 6 7 LenComparator lenComparator = new LenComparator(); 8 9 TreeSet<String>set2 = new TreeSet<String>(lenComparator); 10 11 12 13 set2.add("banana"); 14 15 set2.add("coco"); 16 17 set2.add("apple"); 18 19 20 21 set2.add("apple"); 22 23 System.out.println(set2); 24 25 26 } 27 28 } 29 30 class LenComparator implements Comparator<String>{ 31 32 33 @Override 34 35 publicint compare(String o1, String o2) { 36 37 returno1.length() - o2.length(); 38 39 } 40 41 }
使用匿名内部类优化
1 publicclass Test02 { 2 3 public static void main(String[] args) { 4 5 6 TreeSet<String>set2 = newTreeSet<String>(new Comparator<String>() { 7 8 9 10 @Override 11 12 public int compare(String o1, String o2) { 13 14 returno1.length() - o2.length(); 15 16 } 17 18 19 20 }); 21 22 set2.add("banana"); 23 24 set2.add("coco"); 25 26 set2.add("apple"); 27 28 29 set2.add("apple"); 30 31 System.out.println(set2); 32 33 34 35 } 36 37 }
13. Map接口
Map接口称为键值对集合或者映射集合,其中的元素(entry)是以键值对(key-value)的形式存在。
Map容器接口中提供了增、删、改、查的方式对集合进行操作。
Map接口中都是通过key来操作键值对,一般key是已知。通过key获取value。
1) map常用方法
1 public static void main(String[] args) { 2 3 4 5 /** 6 7 * 增:put/putAll 8 9 * 删:clear/remove 10 11 * 改:put 12 13 * 查:get/containsKey/containsValue 14 15 * 其他:isEmpty/size 16 17 */ 18 19 20 Map<String, String>map = new HashMap<String,String>(); 21 22 23 24 // 【1】put 25 26 map.put("A", "apple"); 27 28 map.put("B", "banana"); 29 30 map.put("C", "coco"); 31 32 33 34 // 【2】删除 35 36 // map.clear(); 37 38 // smap.remove("A"); 39 40 41 42 // 【3】修改 43 44 //map.put("A", "apple x"); 45 46 47 48 // 【4】查看 49 50 String val = map.get("A"); 51 52 System.out.println(map.containsKey("D")); 53 54 55 System.out.println(map); 56 57 }
2). map接口的遍历
通过keySet() 返回map中键的set集合。
1 public static void main(String[] args) { 2 3 4 5 Map<String, String>map = new HashMap<String,String>(); 6 7 8 9 map.put("B", "banana"); 10 11 map.put("A", "apple"); 12 13 map.put("C", "coco"); 14 15 // map无序 16 17 // 可以根据key的自然顺序让map有序 =>一般用string作为key 18 19 System.out.println(map); 20 21 22 23 24 25 // 遍历 26 27 Set<String>keys = map.keySet(); 28 29 for (String key : keys) { 30 31 System.out.println(key+"=>"+map.get(key)); 32 33 } 34 35 36 37 Iterator<String>it = keys.iterator(); 38 39 while(it.hasNext()) { 40 41 String key = it.next(); 42 43 System.out.println(key+"=>"+map.get(key)); 44 45 } 46 47 }
map中以键值对作为元素,键值对在map中称为entry,entrySet返回键值对的set集合。
1 publicstaticvoid main(String[] args) { 2 3 4 5 Map<String, String>map = new HashMap<String,String>(); 6 7 8 9 map.put("B", "banana"); 10 11 map.put("A", "apple"); 12 13 map.put("C", "coco"); 14 15 // map无序 16 17 // 可以根据key的自然顺序让map有序 =>一般用string作为key 18 19 System.out.println(map); 20 21 22 23 // entrySet 24 25 Set<Entry<String, String>>entrySet = map.entrySet(); 26 27 for (Entry<String, String>entry : entrySet) { 28 29 System.out.println(entry.getKey()+"=>"+entry.getValue()); 30 31 } 32 33 34 35 Iterator<Entry<String, String>>it2 = entrySet.iterator(); 36 37 while(it2.hasNext()) { 38 39 Entry<String, String>entry = it2.next(); 40 41 System.out.println(entry.getKey()+"=>"+entry.getValue()); 42 43 } 44 45 }
Map接口的实现类HashMap、LinkedHashMap、TreeMap
14. HashMap
HashMap是Map的实现类,key以HashSet存储。
HashMap是线程不安全的 jdk1.2,Hashtable是HashMap的线程安全版本。Jdk1.0
1 public static void main(String[] args) { 2 3 4 5 /* 6 7 HashMap<String, Object> map = new HashMap<String,Object>(); 8 9 10 11 ArrayList<String> list1 = new ArrayList<String>(); 12 13 list1.add("alex"); 14 15 list1.add("alice"); 16 17 list1.add("allen"); 18 19 map.put("A", list1); 20 21 22 23 24 25 ArrayList<String> list2 = new ArrayList<String>(); 26 27 list2.add("ben"); 28 29 list2.add("bill"); 30 31 map.put("B", list2); 32 33 34 35 System.out.println(map); 36 37 */ 38 39 40 41 42 43 HashMap<Student, Object>map = new HashMap<Student,Object>(); 44 45 46 47 ArrayList<String>list1 = new ArrayList<String>(); 48 49 list1.add("alex"); 50 51 list1.add("alice"); 52 53 list1.add("allen"); 54 55 Students1 = newStudent("001", "大狗", 20); 56 57 map.put(s1, list1); 58 59 60 61 62 63 ArrayList<String>list2 = new ArrayList<String>(); 64 65 list2.add("ben"); 66 67 list2.add("bill"); 68 69 Students2 = newStudent("001", "大狗", 20); 70 71 // 修改 72 73 map.put(s2, list2); 74 75 System.out.println(map); 76 77 78 79 }
总结:
[1]向HashMap中存储元素时,key一定要实现hashCode和equals.
[2]一般建议使用String作为Map接口的key
15.LinkedHashMap
LinkedHashMap是Map接口的实现类,key以LinkedHashSet存储。
哈希表散列key,链表维持key的添加顺序。
1 public static void main(String[] args) { 2 3 4 5 6 7 /*LinkedHashMap<String, Object> map = new LinkedHashMap<String,Object>(); 8 9 10 11 ArrayList<String> list2 = new ArrayList<String>(); 12 13 list2.add("ben"); 14 15 list2.add("bill"); 16 17 map.put("B", list2); 18 19 20 21 ArrayList<String> list1 = new ArrayList<String>(); 22 23 list1.add("alex"); 24 25 list1.add("alice"); 26 27 list1.add("allen"); 28 29 map.put("A", list1); 30 31 32 33 System.out.println(map);*/ 34 35 36 37 38 39 40 41 HashMap<Student, Object>map = new HashMap<Student,Object>(); 42 43 44 45 ArrayList<String>list1 = new ArrayList<String>(); 46 47 list1.add("alex"); 48 49 list1.add("alice"); 50 51 list1.add("allen"); 52 53 Student s1 = new Student("001", "大狗", 20); 54 55 map.put(s1, list1); 56 57 58 59 ArrayList<String>list2 = new ArrayList<String>(); 60 61 list2.add("ben"); 62 63 list2.add("bill"); 64 65 Student s2 = new Student("001", "大狗", 20); 66 67 // 修改 68 69 map.put(s2, list2); 70 71 System.out.println(map); 72 73 74 75 }
16.TreeMap
TreeMap是Map的实现类,key以TreeSet存储。
1 public static void main(String[] args) { 2 3 4 5 6 7 /*TreeMap<String, Object> map = new TreeMap<String,Object>(new Comparator<String>() { 8 9 10 11 @Override 12 13 public int compare(String o1, String o2) { 14 15 return o1.length() - o2.length(); 16 17 } 18 19 }); 20 21 22 23 ArrayList<String> list2 = new ArrayList<String>(); 24 25 list2.add("ben"); 26 27 list2.add("bill"); 28 29 map.put("Aa", list2); 30 31 32 33 ArrayList<String> list1 = new ArrayList<String>(); 34 35 list1.add("alex"); 36 37 list1.add("alice"); 38 39 list1.add("allen"); 40 41 map.put("B", list1); 42 43 44 45 System.out.println(map);*/ 46 47 48 49 TreeMap<Student, Object>map = new TreeMap<Student,Object>(new Comparator<Student>() { 50 51 52 53 @Override 54 55 publicint compare(Student o1, Student o2) { 56 57 returno1.getAge() - o2.getAge(); 58 59 } 60 61 }); 62 63 ArrayList<String>list1 = new ArrayList<String>(); 64 65 list1.add("alex"); 66 67 list1.add("alice"); 68 69 list1.add("allen"); 70 71 Student s1 = new Student("001", "大狗", 20); 72 73 map.put(s1, list1); 74 75 76 ArrayList<String>list2 = new ArrayList<String>(); 77 78 list2.add("ben"); 79 80 list2.add("bill"); 81 82 Student s2 = new Student("001", "2狗", 20); 83 84 // 修改 85 86 map.put(s2, list2); 87 88 System.out.println(map); 89 90 91 92 }
17.总结