Java集合类

简介: 数组是一种很常见的数据结构,开始接触编程的时候多数程序都和数组相关。刚开始接触Java时也是一直使用数组写一些程序,后来越来越觉得数组这东西没法满足需求了,这时一位“前辈”对我说了一句:不会用集合类就等于没学过Java。

     数组是一种很常见的数据结构,开始接触编程的时候多数程序都和数组相关。刚开始接触Java时也是一直使用数组写一些程序,后来越来越觉得数组这东西没法满足需求了,这时一位“前辈”对我说了一句:不会用集合类就等于没学过Java。然后才知道有集合类。

    想想已经是3、4年前的事了,时间如白驹过隙啊。

    什么时候数组会显得力不从心,没法满足需求,需要集合类呢?

  1. 不知道具体数据长度
  2. 需要自动排序
  3. 存储键值对

    当然,上面的情况不是绝对的,只是数组比较难满足。这时集合类(也可称为容器类)就显示了它强大的功能。

    集合类的分类(图片转自http://biancheng.dnbcw.info/1000wen/359774.html)

    

    上图中不包含Queue内容,部分Map的实现类未给出。

    常见使用的有List、Set、Map及他们的实现类。

    List、Set、Map接口及各实现类的特性

接口

特性

实现类

实现类特性

成员要求

List

线性、有序的存储容器,可通过索引访问元素

ArrayList

数组实现。非同步。

 

Vector

类似ArrayList,同步。

 

LinkedList

双向链表。非同步。

 

Map

保存键值对成员

HashMap

基于哈希表的 Map 接口的实现,满足通用需求

任意Object对象,如果修改了equals方法,需同时修改hashCode方法

TreeMap

默认根据自然顺序进行排序,或者根据创建映射时提供的 Comparator进行排序

键成员要求实现caparable接口,或者使用Comparator构造TreeMap。键成员一般为同一类型。

LinkedHashMap

类似于HashMap,但迭代遍历时取得“键值对”的顺序是其插入顺序或者最近最少使用的次序

与HashMap相同

IdentityHashMap

使用==取代equals()对“键值”进行比较的散列映射

成员通过==判断是否相等

WeakHashMap

弱键映射,允许释放映射所指向的对象

 

ConcurrentHashMap

线性安全的Map

 

Set

成员不能重复

HashSet

为快速查找设计的Set

元素必须定义hashCode()

TreeSet

保持次序的Set,底层为树结构

元素必须实现Comparable接口

LinkedHashSet

内部使用链表维护元素的顺序(插入的次序)

元素必须定义hashCode()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   

 

 

 

 

 

    在满足要求的情况下,Map应尽量使用HashMap,Set应尽量使用HashSet。

    集合类的基本使用

    List

List基本操作
 1 ArrayList<String> arrayList = new ArrayList<String>();
 2         arrayList.add("Tom");
 3         arrayList.add("Jerry");
 4         arrayList.add("Micky");
 5         // 使用Iterator遍历元素
 6         Iterator<String> it = arrayList.iterator();
 7         while (it.hasNext()) {
 8             String str = it.next();
 9             System.out.println(str);
10         }
11         // 在指定位置插入元素
12         arrayList.add(2, "Kate");
13         // 通过索引直接访问元素
14         for (int i = 0; i < arrayList.size(); i++) {
15             System.out.println(arrayList.get(i));
16         }
17         List<String> subList = new ArrayList<String>();
18         subList.add("Mike");
19         // addAll(Collection<? extends String> c)添加所给集合中的所有元素
20         arrayList.addAll(subList);
21         // 判断是否包含某个元素
22         if (arrayList.contains("Mike")) {
23             System.out.println("Mike is include in the list");
24         }
25 
26         LinkedList<String> linkedList = new LinkedList<String>();
27         linkedList.addAll(arrayList);
28         // 获取指定元素
29         System.out.println(linkedList.get(4));
30         // 获取第一个元素
31         System.out.println(linkedList.getFirst());
32         // 获取最后一个元素
33         System.out.println(linkedList.getLast());
34         // 获取并删除第一个元素
35         System.out.println(linkedList.pollFirst());
36         // 获取,但不移除第一个元素
37         System.out.println(linkedList.peekFirst());

    ArrayList和LinkedList的效率比较

ArrayList添加元素的效率
 1 ArrayList<String> arrList = new ArrayList<String>();
 2         long startTimeMillis, endTimeMillis;
 3         startTimeMillis = System.currentTimeMillis();
 4         for (int i = 0; i < 10000; i++) {
 5             arrList.add(0, "addString");
 6         }
 7         endTimeMillis = System.currentTimeMillis();
 8         System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
 9                 + "ms");
10 
11         arrList.clear();
12 
13         startTimeMillis = System.currentTimeMillis();
14         for (int i = 0; i < 20000; i++) {
15             arrList.add(0, "addString");
16         }
17         endTimeMillis = System.currentTimeMillis();
18         System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
19                 + "ms");
20 
21         arrList.clear();
22 
23         startTimeMillis = System.currentTimeMillis();
24         for (int i = 0; i < 40000; i++) {
25             arrList.add(0, "addString");
26         }
27         endTimeMillis = System.currentTimeMillis();
28         System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
29                 + "ms");
30 
31         arrList.clear();
32 
33         startTimeMillis = System.currentTimeMillis();
34         for (int i = 0; i < 80000; i++) {
35             arrList.add(0, "addString");
36         }
37         endTimeMillis = System.currentTimeMillis();
38         System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
39                 + "ms");
40 
41         arrList.clear();
42 
43         startTimeMillis = System.currentTimeMillis();
44         for (int i = 0; i < 160000; i++) {
45             arrList.add(0, "addString");
46         }
47         endTimeMillis = System.currentTimeMillis();
48         System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
49                 + "ms");
50 
51         arrList.clear();
52 
53         startTimeMillis = System.currentTimeMillis();
54         for (int i = 0; i < 320000; i++) {
55             arrList.add(0, "addString");
56         }
57         endTimeMillis = System.currentTimeMillis();
58         System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
59                 + "ms");

 

    执行时间比较

执行次数(在0号位置插入)

ArrayList所用时间(ms)

LinkedList所用时间(ms)

10000

31

0

20000

141

0

40000

484

16

80000

1985

0

160000

7906

0

320000

31719

16

执行次数(在尾部插入)

ArrayList所用时间(ms)

LinkedList所用时间(ms)

10000

0

0

20000

15

0

40000

0

0

80000

0

0

160000

0

15

320000

0

16

循环输出次数(get(index)方法)

ArrayList所用时间(ms)

LinkedList所用时间(ms)

10000

93

204

20000

188

797

40000

328

2734

80000

688

13328

160000

1594

62313

320000

2765

太久了……

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    

   

 

 

 

    因为ArrayList底层由数组实现,在0号位置插入时将移动list的所有元素,在末尾插入元素时不需要移动。LinkedList是双向链表,在任意位置插入元素所需时间均相同。所以在List中有较多插入和删除操作的情况下应使用LinkedList来提高效率,而有较多索引查询的时候使用ArrayList(使用增强型的for循环或Iterator遍历LinkedList效率将提高很多)。

    Map

Map基本操作
 1 HashMap<String, Integer> map = new HashMap<String, Integer>();
 2         // 向Map中添加元素
 3         map.put("Tom", 26);
 4         map.put("Jack", 18);
 5         map.put("Micky", 17);
 6         map.put("Kate", 15);
 7         // 根据Key获取Value
 8         System.out.println("Jack is " + map.get("Jack") + " years old");
 9         // 移除
10         map.remove("Micky");
11         // 遍历Map
12         for (Entry<String, Integer> entry : map.entrySet()) {
13             System.out.println("name:" + entry.getKey() + " age:"
14                     + entry.getValue());
15         }
16         // Key相同的元素将被覆盖
17         map.put("Jack", 19);
18         // 根据Key获取Value
19         System.out.println("Jack is " + map.get("Jack") + " years old");
20         // 判断是否包含某个Key
21         if (map.containsKey("Tom")) {
22             System.out.println(map.get("Tom"));
23         }
24         // 判断是否包含某个Value
25         if (map.containsValue(26)) {
26             System.out.println("The map include the value 26");
27         }
28         // 判断map是否为空
29         if (!map.isEmpty()) {
30             // 获取map大小
31             System.out.println("The map's size=" + map.size());
32         }
33         // 获取Key的集合
34         for (String str : map.keySet()) {
35             System.out.println(str);
36         }
37 
38         TreeMap<String, Integer> treeMap = new TreeMap<String, Integer>();
39         treeMap.putAll(map);
40         // 输出内容按照key值排序
41         for (Entry<String, Integer> entry : treeMap.entrySet()) {
42             System.out.println("name:" + entry.getKey() + " age:"
43                     + entry.getValue());
44             // name:Jack age:19
45             // name:Kate age:15
46             // name:Tom age:26
47         }
48 
49         LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<String, Integer>();
50         // 向Map中添加元素
51         linkedHashMap.put("Tom", 26);
52         linkedHashMap.put("Jack", 18);
53         linkedHashMap.put("Micky", 17);
54         linkedHashMap.put("Kate", 15);
55         // 保持了插入的顺序
56         for (Entry<String, Integer> entry : linkedHashMap.entrySet()) {
57             System.out.println("name:" + entry.getKey() + " age:"
58                     + entry.getValue());
59             // name:Tom age:26
60             // name:Jack age:18
61             // name:Micky age:17
62             // name:Kate age:15
63         }

    Set

Set基础操作
 1            List<Integer> list = new ArrayList<Integer>();
 2            list.add(3);
 3            list.add(4);
 4            HashSet<Integer> hashSet = new HashSet<Integer>();
 5            hashSet.add(1);
 6            hashSet.add(3);
 7            hashSet.add(2);
 8            hashSet.add(6);
 9            // 重复元素将不能被添加
10            hashSet.add(3);
11            // 只要有元素被添加就返回true
12            if (hashSet.addAll(list)) {
13                System.out.println("Add success");
14            }
15            // 判断是否存在某个集合
16            if (hashSet.containsAll(list)) {
17                System.out.println("The hashSet is contain 3 and 4");
18            }
19            Iterator<Integer> it = hashSet.iterator();
20            while (it.hasNext()) {
21                System.out.print(it.next() + " ");
22                // 1 2 3 4 6
23                // 看结果是被排序了,HashSet按照Hash函数排序,Integer值的HashCode就是其int值
24            }
25            // 换转成数组
26            Object[] integers = hashSet.toArray();
27            for (int i = 0; i < integers.length; i++) {
28                System.out.print((Integer) integers[i]);
29            }
30            //移除元素
31            hashSet.remove(3);
32            
33            TreeSet<String> treeSet = new TreeSet<String>();
34            treeSet.add("C");
35            treeSet.add("A");
36            treeSet.add("D");
37            treeSet.add("B");
38            for (Iterator<String> strIt = treeSet.iterator(); strIt.hasNext();) {
39                System.out.print(strIt.next());
40                // ABCD 按照字母顺序
41            }
42            LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
43            linkedHashSet.add("C");
44            linkedHashSet.add("A");
45            linkedHashSet.add("D");
46            linkedHashSet.add("B");
47            for (Iterator<String> linkedIt = linkedHashSet.iterator(); linkedIt
48                    .hasNext();) {
49                System.out.print(linkedIt.next());
50                // CADB 按照插入顺序
51            }    

 

 

 

 

    本文没有对ArrayList及HashMap进行深入的分析,这两个类是集合类中最常用的类,将另开文章进行深入剖析。

     ArrayList深入分析:《ArrayList源码分析》

如果本文对您有帮助,点一下右下角的“推荐”
目录
相关文章
|
1月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
141 57
|
2天前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
13天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
33 5
|
25天前
|
存储 缓存 安全
Java 集合框架优化:从基础到高级应用
《Java集合框架优化:从基础到高级应用》深入解析Java集合框架的核心原理与优化技巧,涵盖列表、集合、映射等常用数据结构,结合实际案例,指导开发者高效使用和优化Java集合。
36 4
|
1月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
48 8
|
1月前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
73 17
|
1月前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
33 2
|
1月前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
1月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
1月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
129 4