Java集合

1.1集合框架的优点

传统的容器(数组)进行增、删破坏性操作时,需要移动元素,可能导致性能问题同时添加、删除等算法和具体业务耦合在一起,增加了程序开发的复杂度。

Java集合框架提供了一套性能优良、使用方便的接口和类,它们位于java.util包中

2.2Collection

 

Collectionjava集合框架(collection-frame)的顶层接口。

 

Collection接口是一个容器,容器中只能存储引用数据类型建议存同一类型的引用类型,方便后续遍历等操作。

 

容器中的元素可以是有序的可重复的,List接口

 

也可能是无序的、唯一的称为Set接口。

 

1.2.1 集合的常用方法

 * :add/addAll

 * :clear/remove/removeAll/retainAll

 * :

 * :contains/containsAll/isEmpty/size

 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         Collection c1 = new ArrayList();
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         Collection c2 = new ArrayList();
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     }

1.2.2集合的遍历

关键字:Iterable

Iterable 遍历的接口,集合接口继承于它,集合支持快速遍历。

// 快速遍历
        // for-each
        // Object 表示元素类型 
        // item表示迭代变量
        // c1表示集合
        for (Object item : c1) {
            System.out.println(item.toString());
        }

快速遍历的本质

 

Collection继承Iterable接口,表示集合支持快速遍历。Iterable接口定义了一个方法iterator()用于获取集合的迭代器,是一个Iterator接口类型,iterator()内部返回一个实现类实现类Iterator接口这个实现类一定具有hasNextnext方法用于判断是否有下一个元素和获取下一个元素。快速遍历就是基于迭代器工作的。

 

 1 public static void main(String[] args) {
 2         
 3 
 4         Collection c1 = new ArrayList();
 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         Iterator it = c1.iterator();
21         while(it.hasNext()) {
22             Object item = it.next();
23             System.out.println(item.toString());
24         }
25         
26         // 国外
27         for(Iterator it2=c1.iterator();it2.hasNext();) {
28             Object item = it2.next();
29             System.out.println(item.toString());
30         }    
31     }

1.3 List接口

List 接口中的元素时有序的、可重复的。List接口的元素通过索引(index)确定元素的顺序。

 

有序的 collection(也称为序列)。可以对列表中每个元素的插入位置进行精确地控制。

 

用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素

1.3.1 List常用方法

增:add/addAll/add(index,el)/addAll(index,collection)

删:clear/remove/removeall/remove(index)

改:set(index,el)

查:get(index)/indexOf/lastIndexOf()

其他:contains/containsall/isEmpty/size

 

 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         List list1 = new ArrayList();
11         // 添加元素
12         list1.add("apple");
13         list1.add("banana");
14         // 在指定位置添加元素
15         list1.add(0, "coco");
16         
17         System.out.println(list1);
18         
19         List list2 = new ArrayList();
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     }

 

1.3.2 接口遍历

ListIterator继承于Iterator,在Itertaor的基础上提供了以正向遍历集合,也可以以遍历集合。

hasNext/ next 以正向 遍历

hasPrevious/previous 以遍历

【1】for each 遍历

【2】普通for遍历

【3】集合迭代器遍历

(1)正向遍历

(2)逆向遍历

 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(int i=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         ListIterator it3 = list1.listIterator(1);
42         while(it3.hasNext()) {
43             System.out.println(it3.next());
44         }
45     }

 

 1.4 数据结构

1.4.1线性表

线性表数据按照一定的逻辑顺序存储在内存中。线性表是有序的。线性表根据内存的物理结构分为两种:数组和链表

 

数组是一种逻辑上有序的线性表,物理上也连续

 

链表是一种逻辑上有序的线性表,但物理上不连续。

 

 数组和链表的区别:

 

相同:逻辑上有序

 

不同:数组是物理上有序的,链表是物理上无序的。

数组在查询时效率高,在添加、删除元素时效率低(涉及移动元素)

链表在查询时效率(每次从头开始不能跳跃访问),在添加、删除元素时效率(不涉及移动元素)

 1.4.2 栈

特性:进后出,后进先出

1.4.3 队列

特性:先进先出

 

 1.5 ArrayList/Vector

ArayList 是List接口的实现类,底层数据结构是数组,实现大小可变的数组。

ArrayList 线程不安全jdk1.2

 

 ArrayList底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,

 ArrayList自动拓容,拓容原则:newCapacity = oldCapacity + oldCapacity / 2(oldCapacity>>1);

 如果未来确定序列的元素不再增加,通过trimTosize()调制容量至合适的空间。

ArrayList 作为List接口的实现类,常用方法和遍历方法参考List接口。

 

Vector 是List接口的实现类,底层数据 结构也是数组 ,也是大小可变的数组 。

 Vector是线程安全的,jdk1.0

 

Vector底层数据结构是数组,默认数组大小是10,

 如果添加的元素个数超过默认容量,Vector会自动拓容,拓容原则:newCapacity = oldCapacity +capacityIncrement(增长因子);如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。

 注意:Vector 实现List接口的同时,同添加了自身特有的方法xxxElement,未来使用时为了程序的可拓展性,一定要按照接口来操作Vector

 1.6 Linkedlist

LInkedLIst是LIst接口的实现类,底层数组结构是链表。

LinkedList常用方和遍历方法参照List接口。

LinkedList线程不安全。

LinkedList坠子实现List接口,还实现栈接口。

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 }

 

队列(Queue)接口

add/remove/element()可能会出现NoSuchElementException异常

 1 public static void main(String[] args) {
 2         
 3         LinkedList queue = new LinkedList();
 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         LinkedList queue = new LinkedList();
 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     }

双向队列(Deque)接口

 1 /**
 2  * 以双向队列形式操作LinkedList
 3  */
 4 public class Test04 {
 5     public static void main(String[] args) {
 6         
 7         LinkedList queue = new LinkedList();
 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 }

1.7 Iterator和LIstiterator

Iterator在迭代过程中不允许向集合中添加元素

 Listiterator可以在迭代过程中添加元素

 

 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         Iterator it = 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 并发修改异常。

 ListIterator允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置

 1 public class Test01 {
 2     public static void main(String[] args) {
 3         ArrayList list = new ArrayList();
 4         list.add("apple");
 5         list.add("banana");
 6         list.add("coco");
 7         
 8         ListIterator it = 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 }

 

 1.8 泛型(generic)

1.8.1 反省的概念

泛型允许开发者在强类型程序设计 语言(java)编写代码时定义一些可变部分,这些部分在使用前必须作出指明。

泛型就是将类型参数化。

ArrayList<E> list 表示声明了一个列表list,列表的元素是E类型。

ArrayList<String> list = new ArrayList<String>();

声明了一个列表list,列表的元素只能是String类型。

泛型编译器起作用,运行时jvm察觉不到泛型的存在。

 

1.8.2 泛型的擦除

泛型在运行时已经被擦除了。

1 public static void main(String[] args) {
2         ArrayList<String> list = new ArrayList<String>();
3         list.add("apple");
4         System.out.println(list instanceof ArrayList);
5         System.out.println(list instanceof ArrayList<String>);//错的表达方式
6          System.out.println(list instanceof ArrayList<?>);//正确的表达方式
7 }

错误时的异常:

Cannot perform instanceof check against parameterized type ArrayList<String>. Use the form ArrayList<?> instead since further generic type information will be erased at runtime

1.8.3 泛型的应用

1.8.3.1 泛型类

当一个类中属性的数据类型不确定时,具体是什么类型由开发者决定,使用泛型。泛型类的形式:

public class 类名<T> {
    
}

定义一个泛型类

 1 public class FanClass<T> {
 2     private T t;
 3 
 4     public T getT() {
 5         return t;
 6     }
 7 
 8     public void 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     public static void 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 }

1.8.3.2 泛型方法

当现代战争方法的参数 类型不确定时,具体是什么类型由使用者来确定,可以考虑使用泛型方法。

形式:

【1】把类定义成泛型类,如下:

public <T> void xxx(T a) {
    System.out.println(a);
}

【2】

 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(T a) {
17         System.out.println(a);
18     }
19 }
1 public static void main(String[] args) {
2         
3         Student stu = new Student();
4         stu.showInfo(1);
5         stu.showInfo("apple");
6         stu.showInfo(1.0f);
7     }

泛型方法在调用时确定(指明)类型

泛型方法在一定程度上优化了方法重载。

 

泛型方法可以定义多个泛型类型

 

1 // 可以定义多个泛型的类型
2     public <A,B> void showInfo(A a,B b) {
3         System.out.println(a);
4         System.out.println(b);
5     }

多个泛型类型进一步优化了方法重载。

多个同类型的泛型

 

 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是什么类型的数组由开发者调用处传决定。

 

1 stu.print(1);
2 stu.print(1,2);
3         
4 stu.print("apple");
5 stu.print("apple","banana");

print(A...a) 方法称为可变参数的泛型形式。

2.1.1.1 泛型接口C)

如果接口中的方法参数(形参返回值)确定,可以考虑使用泛型接口形式

1 public interface FanInterface<T> {
2 
3 public void showInfo(T t);
4 
5 }

[1]实现类能确定泛型接口的类型

 1 public class ImplClass implements FanInterface<String>{
 2 
 3 @Override
 4 
 5 public void showInfo(String t) {
 6 
 7 // TODO Auto-generated method stub
 8 
 9 }
10 
11 }

[2]实现类不能确定泛型接口的类型->继续

 1 public class ImplClass2<T> implements FanInterface<T>{
 2 
 3 @Override
 4 
 5 public void showInfo(T t) {
 6 
 7  
 8 }
 9 
10 }

2.1.1.2 泛型的上限和下限 (C)

1 public static void print(ArrayList<? extends Pet> list) {
2 
3 for (Pet pet : list) {
4 
5 pet.showInfo();
6 
7 }
8 
9 }

泛型的上限ArrayList<? extends Pet> list 声明了一个容器,容器中的元素类型一定要继承于Pet,我们称这种形式叫做泛型的上限。

泛型的下ArrayList<? super Pet> list 声明了一个容器容器中的元素类型一定要Pet父类我们称这个形式为泛型的下限。

 

3.1 Set接口

Set接口表示一个唯一、无序的容器(添加顺序无关)

3.1.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 boolean r = 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 }

 

3.1.2 Set接口的遍历

 1 public static void main(String[] args) {
 2 
 3 
 4 Set<String> set = new HashSet<String>();
 5 
 6 set.add("banana");
 7 
 8 set.add("apple");
 9 
10 set.add("coco");
11 
12  
13 
14 // 快速遍历
15 
16 for (String item : set) {
17 
18 System.out.println(item);
19 
20 }
21 
22 
23 // 迭代器
24 
25 Iterator<String> it = set.iterator();
26 
27 while(it.hasNext()) {
28 
29 String item = it.next();
30 
31 System.out.println(item);
32 
33 }
34 
35 }

Set接口的实现类常见的有HashSetLinkedHashSetTreeSet

3.2 HashSet

HashSetSet接口的实现类,底层数据结构是哈希表。

HashSet是线程不安全的(不保证同步)

3.2.1 哈希表工作原理

3.2.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 private int age;
12 
13  
14 
15 //
16 
17  
18 
19  
20 
21 @Override
22 
23 public int hashCode() {
24 
25 final int prime = 31;
26 
27 int result = 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 return result;
36 
37 }
38 
39  
40 
41 @Override
42 
43 public boolean equals(Object obj) {
44 
45 if (this == obj)
46 
47 return true;
48 
49 if (obj == null)
50 
51 return false;
52 
53 if (getClass() != obj.getClass())
54 
55 return false;
56 
57 Student other = (Student) obj;
58 
59 if (age != other.age)
60 
61 return false;
62 
63 if (id == null) {
64 
65 if (other.id != null)
66 
67 return false;
68 
69 } else if (!id.equals(other.id))
70 
71 return false;
72 
73 if (name == null) {
74 
75 if (other.name != null)
76 
77 return false;
78 
79 } else if (!name.equals(other.name))
80 
81 return false;
82 
83 return true;
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] 优点:添加、删除、查询效率高;缺点:无序

3.3 LinkedHashSet

LinkedHashSetSet接口的实现底层数据结构哈希表+链表

哈希表用于散列元素;链表用于维持添加顺序。

如果要添加自定义对象元素,也需要重写hashCodeequals方法。

 

3.4 TreeSet

TreeSet Set接口的实现类,底层数据结构是二叉树。

TreeSet 存储的数据按照一定的规则存储。存储规则让数据表现自然序。

 

3.4.1 TreeSet工作原理

 

 

添加一个新元素t存储的步骤:

[1] 如果集合无元素,t直接加入;如果集合有元素,t和根节点比较;

[2] 如果t小于根节点;把t放到根节点的左子树上;重复1-3步骤

[3] t大于根节点;把t放到根节点的右子树上;重复1-3步骤

 

输出时按照一定的规则:子树->节点->右子树

 

根据TreeSet工作原理,向TreeSet添加自定义元素

TreeSet中添加元素时,一定要提供比较策略否则会出现ClassCastException

 

比较策略分两种:内部比较器外部比较器

 

3.4.2 内部比较器

一个自定义对象实现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 private int age;
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 public int compareTo(Student o) {
32 
33 if(this.getAge()<o.getAge()) {
34 
35 return -1;
36 
37 }else if(this.getAge() == o.getAge()) {
38 
39 return 0;
40 
41 }else {
42 
43 return 1;
44 
45 }
46 
47 }
48 
49  
50 
51 }

比较策略几种情况

[1]比较策略一般当前对象写在前面,比较对象也在后面,比较结果默认升序

return  this.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 
21 // return  this.getAge() - o.getAge() ;
22 
23 
24 if(this.getAge()<o.getAge()) {
25 
26 return -1;
27 
28 }else if(this.getAge() == o.getAge()) {
29 
30 return this.getName().compareTo(o.getName());
31 
32 }else {
33 
34 return 1;
35 
36 }
37 
38 }

3.4.3 外部比较

实际开发过程不知道添加元素的源代码无权修改别人的代码此时可以使用外部比较器。

 

Comparator 位于java.util中,定义了compare(o1,o2) 用于提供外部比较策略。

TreeSet接受一个指定比较策略的构造方法,这些比较策略的实现类必须实现Comparator

接口

 

需求:按照字符串的长度比较

 1 public class Test01 {
 2 
 3 public static void main(String[] args) {
 4 
 5 
 6 LenComparator lenComparator = new LenComparator();
 7 
 8 TreeSet<String> set2 = new TreeSet<String>(lenComparator);
 9 
10  
11 
12 set2.add("banana");
13 
14 set2.add("coco");
15 
16 set2.add("apple");
17 
18 set2.add("apple");
19 
20 System.out.println(set2);
21 
22  
23 
24 }
25 
26 }
27 
28 
29 class LenComparator implements Comparator<String>{
30 
31  
32 
33 @Override
34 
35 public int compare(String o1, String o2) {
36 
37 return o1.length() - o2.length();
38 
39 }
40 
41 }

使用匿名内部类优化

 1 public class Test02 {
 2 
 3 public static void main(String[] args) {
 4 
 5 
 6 TreeSet<String> set2 = new TreeSet<String>(new Comparator<String>() {
 7 
 8 
 9 @Override
10 
11 public int compare(String o1, String o2) {
12 
13 return o1.length() - o2.length();
14 
15 }
16 
17 
18 });
19 
20 set2.add("banana");
21 
22 set2.add("coco");
23 
24 set2.add("apple");
25 
26 
27 set2.add("apple");
28 
29 System.out.println(set2);
30 
31 
32 }
33 
34 }

3.5 Map接口

Map接口称为键值对集合或者映射集合其中的元素(entry)键值对(key-value)的形式存在

Map 容器接口中提供了增、删、改、查的方式对集合进行操作。

Map接口中都是通过key来操作键值对,一般key是已知。通过key获取value

3.5.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 
21 Map<String, String> map = new HashMap<String,String>();
22 
23  
24 
25 // 【1】put
26 
27 map.put("A", "apple");
28 
29 map.put("B", "banana");
30 
31 map.put("C", "coco");
32 
33  
34 
35 // 【2】删除
36 
37 // map.clear();
38 
39 // map.remove("A");
40 
41  
42 
43 // 【3】修改
44 
45 //map.put("A", "apple x");
46 
47  
48 
49 // 【4】查看
50 
51 String val = map.get("A");
52 
53 System.out.println(map.containsKey("D"));
54 
55  
56 
57  
58 
59 System.out.println(map);
60 
61 }

3.5.2 map接口的遍历

通过keySet() 返回mapset集合

 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 Iterator<String> it = keys.iterator();
37 
38 while(it.hasNext()) {
39 
40 String key = it.next();
41 
42 System.out.println(key+"=>"+map.get(key));
43 
44 }
45 
46 }

 

map中以键值对作为元素,键值对map中称为entryentrySet返回键值对的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 // entrySet
23 
24 Set<Entry<String, String>> entrySet = map.entrySet();
25 
26 for (Entry<String, String> entry : entrySet) {
27 
28 System.out.println(entry.getKey()+"=>"+entry.getValue());
29 
30 }
31 
32 
33 Iterator<Entry<String, String>> it2 = entrySet.iterator();
34 
35 while(it2.hasNext()) {
36 
37 Entry<String, String> entry = it2.next();
38 
39 System.out.println(entry.getKey()+"=>"+entry.getValue());
40 
41 }
42 
43 }

Map接口的实现类HashMapLinkedHashMapTreeMap

3.6 HashMap

HashMap Map的实现类,keyHashSet存储。

 

 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 Student s1 = new Student("001", "大狗", 20);
56 
57 map.put(s1, list1);
58 
59 
60 
61 ArrayList<String> list2 = new ArrayList<String>();
62 
63 list2.add("ben");
64 
65 list2.add("bill");
66 
67 Student s2 = new Student("001", "大狗", 20);
68 
69 // 修改
70 
71 map.put(s2, list2);
72 
73 System.out.println(map);
74 
75  
76 
77 }

 

总结:

[1] HashMap中存储元素时,key一定要实现hashCodeequals(用于去重,用以符合哈希表工作原理)

[2] 一般建议使用String作为Map接口key

 

3.7 LinkedHashMap

LinkedHashMapMap接口的实现类,keyLinkedHashSet存储。

哈希表散列key,链表维持key的添加顺序。

 

 1 public static void main(String[] args) {
 2 
 3 /*LinkedHashMap<String, Object> map = new LinkedHashMap<String,Object>();
 4 
 5 ArrayList<String> list2 = new ArrayList<String>();
 6 
 7 list2.add("ben");
 8 
 9 list2.add("bill");
10 
11 map.put("B", list2);
12 
13  
14 
15 ArrayList<String> list1 = new ArrayList<String>();
16 
17 list1.add("alex");
18 
19 list1.add("alice");
20 
21 list1.add("allen");
22 
23 map.put("A", list1);
24 
25  
26 
27 System.out.println(map);*/
28 
29 
30 HashMap<Student, Object> map = new HashMap<Student,Object>();
31 
32 ArrayList<String> list1 = new ArrayList<String>();
33 
34 list1.add("alex");
35 
36 list1.add("alice");
37 
38 list1.add("allen");
39 
40 Student s1 = new Student("001", "大狗", 20);
41 
42 map.put(s1, list1);
43 
44  
45 
46 ArrayList<String> list2 = new ArrayList<String>();
47 
48 list2.add("ben");
49 
50 list2.add("bill");
51 
52 Student s2 = new Student("001", "大狗", 20);
53 
54 // 修改
55 
56 map.put(s2, list2);
57 
58 System.out.println(map);
59 
60  
61 
62 }

1.8 TreeMap

TreeMapMap的实现类,keyTreeSet存储。

 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  
50 
51  
52 
53 TreeMap<Student, Object> map = new TreeMap<Student,Object>(new Comparator<Student>() {
54 
55  
56 
57 @Override
58 
59 public int compare(Student o1, Student o2) {
60 
61 return o1.getAge() - o2.getAge();
62 
63 }
64 
65 });
66 
67  
68 
69 ArrayList<String> list1 = new ArrayList<String>();
70 
71 list1.add("alex");
72 
73 list1.add("alice");
74 
75 list1.add("allen");
76 
77 Student s1 = new Student("001", "大狗", 20);
78 
79 map.put(s1, list1);
80 
81 
82 
83 ArrayList<String> list2 = new ArrayList<String>();
84 
85 list2.add("ben");
86 
87 list2.add("bill");
88 
89 Student s2 = new Student("001", "2狗", 20);
90 
91 // 修改
92 
93 map.put(s2, list2);
94 
95 System.out.println(map);
96 
97  
98 
99 }

1.9 总结

 

posted @ 2019-04-30 20:47  cowbe  阅读(249)  评论(0编辑  收藏  举报