Collection与Map容器

Posted xfbb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Collection与Map容器相关的知识,希望对你有一定的参考价值。

1.Collection接口

Collection 是java集合框架的顶层接口,它表示为容器,只能存储应用类型数据,为了方便后续遍历最后存储同一类型数据。

Collection 有增删改查等方法。

 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     }

 集合的遍历

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         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     }

 

Collection 有两个子接口分别为Set 和 List

Set 接口是无序的、唯一的;List接口是有序的、不唯一的。

List 接口

1.1.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         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.1.1 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(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     }

 

技术图片

 

因Link 接口继承于Collection接口,所以拥有增删改查方法且自身拥有一些特殊方法。

Link接口有三个重要的实现类:ArrayLink、vector、LinkedList

ArrayLink

ArrayLink的底层数据结构是数组,

默认数组大小是10,如果添加的元素个数超过默认容量,ArrayList会自动拓容,拓容原则:newCapacity = oldCapacity + oldCapacity / 2;

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

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

优点:使用索引查询效率高,添加有序。缺点:删除、增加数据效率低

Vector

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

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

Vector跟ArrayLink基本一样;区别在于Vector是线程安全的,ArrayLink线程不安全。

 

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 }

 

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     }

 

Set接口

因Set 接口继承于Collection接口,所以拥有增删改查方法且自身拥有一些特殊方法

Set接口的三个实现类分别是:HarhSet、LinkedHarhSet、TreeSet

HarhSet

HarhSet的底层数据结构是哈希表,优点:增删查效率高;缺点:无序

LinkedHarhSet

LinkedHarhSet底层数据结构是链表+哈希表;优点:增删改效率高,添加有序;

TreeSet

TreeSet 底层数据结构是二叉树;唯一的,增删查效率中等,存储的数据按照一定的规则存储;存储规则让数据表现出自然顺序。

2.泛型(generic)

概念:

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

泛型就是将类型参数化

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

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

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

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

 

 泛型的擦除

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

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 }
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 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 }
21 
22 public class Test01 {
23     public static void main(String[] args) {
24         FanClass<String> fan = new FanClass<String>();
25         fan.setT("apple");
26         
27         FanClass<Integer> fan2 = new FanClass<Integer>();
28         fan2.setT(1);
29     }
30 }

泛型方法

当一个方法的参数类型不确定时,具体是什么类型由使用者来确定,可以考虑使用泛型方法。形式:

 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 }
20 
21 public static void main(String[] args) {
22         
23         Student stu = new Student();
24         stu.showInfo(1);
25         stu.showInfo("apple");
26         stu.showInfo(1.0f);
27     }

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

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

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

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) 方法称为可变参数的泛型形式。

1.1.1 泛型接口C)

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

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

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

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

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

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

 

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

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

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

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

 

3.Map接口

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

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

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

 

Map接口的三个重要实现类:TreeMap \\LinkHashMap \\HashMap

TreeMap

TreeMap底层数据结构为二叉树;keyTreeSet(二叉树)存储。

 

 1 public static void main(String[] args) {
 2         
 3         
 4         /*TreeMap<String, Object> map = new TreeMap<String,Object>(new Comparator<String>() {
 5 
 6             @Override
 7             public int compare(String o1, String o2) {
 8                 return o1.length() - o2.length();
 9             }
10         });
11         
12         ArrayList<String> list2 = new ArrayList<String>();
13         list2.add("ben");
14         list2.add("bill");
15         map.put("Aa", list2);
16         
17         ArrayList<String> list1 = new ArrayList<String>();
18         list1.add("alex");
19         list1.add("alice");
20         list1.add("allen");
21         map.put("B", list1);
22         
23         System.out.println(map);*/
24         
25         
26         
27         TreeMap<Student, Object> map = new TreeMap<Student,Object>(new Comparator<Student>() {
28 
29             @Override
30             public int compare(Student o1, Student o2) {
31                 return o1.getAge() - o2.getAge();
32             }
33         });
34         
35         ArrayList<String> list1 = new ArrayList<String>();
36         list1.add("alex");
37         list1.add("alice");
38         list1.add("allen");
39         Student s1 = new Student("001", "大狗", 20);
40         map.put(s1, list1);
41         
42         
43         ArrayList<String> list2 = new ArrayList<String>();
44         list2.add("ben");
45         list2.add("bill");
46         Student s2 = new Student("001", "2狗", 20);
47         // 修改
48         map.put(s2, list2);
49         System.out.println(map);
50         
51     }

 

 

 

LinkHashMap

LinkHashMap底层数据结构为链表+哈希表;key以LinkedHashSet存储。哈希表散列key,链表维持key的添加顺序。

 1 public static void main(String[] args) {
 2         
 3         
 4         /*LinkedHashMap<String, Object> map = new LinkedHashMap<String,Object>();
 5         
 6         ArrayList<String> list2 = new ArrayList<String>();
 7         list2.add("ben");
 8         list2.add("bill");
 9         map.put("B", list2);
10         
11         ArrayList<String> list1 = new ArrayList<String>();
12         list1.add("alex");
13         list1.add("alice");
14         list1.add("allen");
15         map.put("A", list1);
16         
17         System.out.println(map);*/
18         
19         
20         
21         HashMap<Student, Object> map = new HashMap<Student,Object>();
22         
23         ArrayList<String> list1 = new ArrayList<String>();
24         list1.add("alex");
25         list1.add("alice");
26         list1.add("allen");
27         Student s1 = new Student("001", "大狗", 20);
28         map.put(s1, list1);
29         
30         
31         ArrayList<String> list2 = new ArrayList<String>();
32         list2.add("ben");
33         list2.add("bill");
34         Student s2 = new Student("001", "大狗", 20);
35         // 修改
36         map.put(s2, list2);
37         System.out.println(map);
38         
39     }

HashMap

HashMap底层数据结构哈希表;key以HashSet存储。

 

 1 public static void main(String[] args) {
 2         
 3         /*
 4         HashMap<String, Object> map = new HashMap<String,Object>();
 5         
 6         ArrayList<String> list1 = new ArrayList<String>();
 7         list1.add("alex");
 8         list1.add("alice");
 9         list1.add("allen");
10         map.put("A", list1);
11         
12         
13         ArrayList<String> list2 = new ArrayList<String>();
14         list2.add("ben");
15         list2.add("bill");
16         map.put("B", list2);
17         
18         System.out.println(map);
19         */
20         
21         
22         HashMap<Student, Object> map = new HashMap<Student,Object>();
23         
24         ArrayList<String> list1 = new ArrayList<String>();
25         list1.add("alex");
26         list1.add("alice");
27         list1.add("allen");
28         Student s1 = new Student("001", "大狗", 20);
29         map.put(s1, list1);
30         
31         
32         ArrayList<String> list2 = new ArrayList<String>();
33         list2.add("ben");
34         list2.add("bill");
35         Student s2 = new Student("001", "大狗", 20);
36         // 修改
37         map.put(s2, list2);
38         System.out.println(map);
39         
40     }

总结:

[1] 向HashMap中存储元素时,key一定要实现hashCode和equals

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

 技术图片

以上是关于Collection与Map容器的主要内容,如果未能解决你的问题,请参考以下文章

Java 中的容器 Collection 和 Map

Java容器总结

JAVA_Collection容器

java容器

Java Review - 集合框架=Collection+Map

Java--容器认识