Javaday14(集合)

 

   

  Collection是所有集合的接口,这个接口定义了一些集合统一访问的接口,子类集合根据自己的特点来实现这些接口功能。

  

   

   集合中通常使用foreach遍历 

   

一、List

  List是有序不重复有索引的集合,它用某种特定的插入顺序来维护元素顺序,可以根据索引来访问元素(类似于数组)。

  1.ArrayList(有序可重复有索引)

    ArrayList是一个用数组实现的集合,可以插入任何类型的元素甚至null也可以。

    每个ArrayList的初始容量都是10,但是ArrayList会根据用户所存的元素数量进行扩容。(扩容规则:(原数组长度*3)/2+1

    由于是数组实现的集合,所以插入和删除效率低,查询效率高。

    ArrayList是非线程安全的列表,Vector与ArrayList相似,操作几乎一模一样,但是是线程安全的。

    Vector在进行默认扩容时的扩容规则:(新数组长度=旧数组长度*2)

   

 1 package com.chinasofti.list;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 public class arraylist {
 7     public static void main(String[] args) {
 8         // 创建ArrayList集合对象 一般都是使用向上造型。用List引用指向ArrayList对象
 9         List arrayList = new ArrayList();
10         // 向集合中添加数据
11         arrayList.add(1);
12         arrayList.add("哈哈");
13         arrayList.add('A');
14         arrayList.add(1>2);
15 
16         // 遍历集合
17         /*for (Object o:arrayList) {
18             System.out.println(o);
19         }*/
20         // 使用for循环遍历集合内容
21         for (int i = 0; i < arrayList.size(); i++) {
22             // 获取集合中元素的值
23             System.out.println(arrayList.get(i));
24         }
25 
26         // 删除索引为1的值
27         arrayList.remove(1);
28         System.out.println("-------------------------");
29         // 查询集合中是否存在'A'
30         System.out.println("集合中是否存在'A':"+arrayList.contains('A'));
31 
32         // 删除集合内的所有内容
33         arrayList.clear();
34 
35         for (Object o:arrayList) {
36             System.out.println(o);
37         }
38     }
39 }

     

  2.LinkedList(有序可重复)

        LinkedList和ArrayList不同,linkedlist是由链表实现的,所以插入和删除效率高,查询效率低。除了ArrayList方法之外,还提供了对队里首位的get,remove,insert方法。

  List list = new LinkedList();
  // list首尾插入值   list.insertFirst(
"first");   list.insertLast("last");
  // 获取list的首尾值   list.getFirst();   list.getLast();
  // 删除list的首尾值   list.removeFirst();   list.removeLast();

         LinkedList实现方式不同,所以不能随机访问,所有的查询都是和链表一样,从头或者结尾开始遍历,这样的话损失了查询效率,但是增加了插入和删除的效率。

       linkedlist和ArrayList一样,也是非线程安全的。

 1 package com.chinasofti.list;
 2 
 3 import java.util.LinkedList;
 4 import java.util.List;
 5 
 6 public class LinkedListTest {
 7     public static void main(String[] args) {
 8         // 创建list集合对象 一般都是使用向上造型。用List引用指向list对象
 9 //        List list = new LinkedList();
10         LinkedList list = new LinkedList();
11         // 向集合中添加数据
12         list.add(1);
13         list.add("哈哈");
14         list.add('A');
15         list.add(1>2);
16 
17         // linkedlist 子类扩展的方法 注意:父类List里没有这些方法
18         list.addFirst("first");
19         list.addLast("last");
20         System.out.println("addFirst:" + list.getFirst());
21         System.out.println("addLast:" + list.getLast());
22 
23 
24         // 遍历集合
25         /*for (Object o:list) {
26             System.out.println(o);
27         }*/
28         // 使用for循环遍历集合内容
29         for (int i = 0; i < list.size(); i++) {
30             // 获取集合中元素的值
31             System.out.println(list.get(i));
32         }
33 
34         // 删除索引为1的值
35         list.remove(1);
36         System.out.println("-------------------------");
37         // 查询集合中是否存在'A'
38         System.out.println("集合中是否存在'A':"+list.contains('A'));
39 
40         // 删除集合内的所有内容
41         list.clear();
42 
43         for (Object o:list) {
44             System.out.println(o);
45         }
46     }
47 }

  3.stack

      继承自vector,实现了一个后入先出的栈。

     有五个方法:pop(出栈),push(入栈),peek(获得栈顶的元素),empty(判断栈是否为空),search(检测一个元素在栈里的位置)。

    stack在刚创建时是空栈。

  4.vector,ArrayList,linkedlist的区别

    vector:      线程安全 数组实现 效率低

    ArrayList:非线程安全 数组实现 查询效率高 插入和删除效率低

    linkedlist:非线程安全 链表实现 查询效率低 插入和删除效率高

二、set(无序不重复)

  EnumSet:是枚举专用的set,所有的元素类型都是枚举。

  HashSet:HashSet是查询速度最快的集合,因为内部是由HashCode来实现的,它内部元素的顺序是由哈希码来决定的,所以他不保证set的顺序问题。

  TreeSet:基于TreeMap,生成一个总是处于排队状态的set,内部是由TreeMap实现,它使用元素的自然顺序来排序,或者是创建set时提供comparator进行排序,具体取决于使用的构造方法。

  1.HashSet(无序)

    根据具体的hashCode方法,来判断是否是可以包含有重复元素,例如:hashcode方法是默认的(依据对象在内存中的地址来计算),并且HashSet存放引用数据类型,就算两个对象相同,但是由于两个对象的内存地址不同,所以可以存放。

    集合元素的hashCode方法返回的哈希值对HashSet非常重要,因为HashSet会优先使用这个哈希值判断两个元素是否相同并确定元素的位置。

    如果我们定义的hashCode方法不够合理,那么就会出现内存泄漏的现象。

    造成内存泄漏的原因是remove,当HashSet集合中的某个值发生变化,那么这个值的哈希值也会发生变化,这时如果使用remove删除这个值,那么由于哈希值的变化导致remove无法定位到索要删除的值的位置,所以无法删除这个值。示例:

    

    

 1 package com.chinasofti.set;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class HashSetTest {
 7     public static void main(String[] args) {
 8         /*
 9         * 默认的hashCode方法是按照对象的存储地址来进行计算的  如果重写hashcode方法不当,一个对象的hashcode值在修改后,
10         * hashcode值会发生变化,那么使用set.remove方法删除对象,并不会删除到之前的对象,这个过程叫做内存泄漏。
11         * */
12 
13         // 创建set集合
14         Set set = new HashSet();
15         // 创建Student对象
16         Student s1 = new Student(1001, "z1", 99);
17         Student s2 = new Student(1002, "z2", 91);
18         Student s3 = new Student(1003, "z3", 92);
19         Student s4 = new Student(1003, "z4", 92);
20         // set集合中添加数据
21         set.add(s1);
22         set.add(s2);
23         set.add(s3);
24         set.add(s4);
25         // 遍历set集合
26         for (Object s:set) {
27             System.out.println(s + "---" + s.hashCode());
28         }
29         // 查看set中的元素个数
30         System.out.println("size:" + set.size());
31         // 查看set集合中是否为空
32         System.out.println("isEmpty"+set.isEmpty());
33 
34         System.out.println(s1.hashCode());
35         s1.setId(100001);
36         s1.setName("100001");
37         s1.setScore(100001);
38         System.out.println(s1.hashCode());
39         // 删除remove
40         set.remove(s1);
41         // 遍历set集合
42         for (Object s:set) {
43             System.out.println(s + "---" + s.hashCode());
44         }
45     }
46 }

  2.TreeSet(有序不重复)

    TreeSet扩展自AbstractSet,并且实现了NavigableSet,AbstractSet扩展自AbstractCollection,TreeSet是一个有序的Set,为了实现排序功能,TreeSet需要实现Comparator。在实例化TreeSet时,我们也可以给TreeSet一个比较器来指定树形中元素的顺序。

    注意:例如下列代码中的比较器中设置比较两个student对象的成绩,当compareTo方法返回0时,TreeSet是默认两个对象是相等的,所以默认不添加到TreeSet集合中。

    

 1 package com.chinasofti.data.tree;
 2 
 3 public class TreeTest {
 4     private MyTree root;
 5 
 6     public TreeTest() {
 7         this.root = null;
 8     }
 9 
10     // 向树中添加节点
11     public void addNode(MyTree myTree) {
12         MyTree current = root;
13         // 如果根节点为null
14         if (root == null) {
15             this.root = myTree;
16         } else {
17             current = this.root;
18             while (true) {
19                 if (myTree.getKey() > current.getKey()) {
20                     // 如果新节点的值大于父节点 放右子树
21                     if (current.getRight() == null) {
22                         current.setRight(myTree);
23                         break;
24                     }
25                     current = current.getRight();
26                 } else if (myTree.getKey() < current.getKey()) {
27                     // 如果新节点的值小于父节点 放左子树
28                     if (current.getLeft() == null) {
29                         current.setLeft(myTree);
30                         break;
31                     }
32                     current = current.getLeft();
33                 }
34             }
35         }
36     }
37 
38     // 按照某个节点的key查找值
39     public int getValue(int key) {
40         MyTree current = this.root;
41 
42         while (true) {
43             // 判断节点是否为所查询节点
44             if (current.getKey() == key) {
45                 return current.getValue();
46             } else {
47                 // 判断key值和current节点的左子树和右子树的跟节点key值大小
48 
49                 if (current.getKey() > key) {
50                     // 如果所查的key值大于current的key 将左子树返回
51                     current = current.getLeft();
52                 }else {
53                     current = current.getRight();
54                 }
55             }
56         }
57     }
58 }

三、Map    

   Map是由一系列的键值对组成的集合,提供了key到value的映射。Map没有继承Collection。

   在Map中保证了key和Value之间的一一对应,也就是说一个key对应一个value,所以key值不能出现重复,如果出现重复,那么就会覆盖。

   value可以相同。

                    

   1.HashMap(无序):     

    在之前的版本中,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里(和我们在之前自行实现的哈希表相同)。但是当链表中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。

      而JDK1.8中,HashMap采用数组+链表+红黑树(一种平衡搜索二叉树)实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间 

    

       HashMap是基于哈希表的Map接口的非同步实现,继承自AbstractMap,AbstractMap是部分实现Map接口的抽象类

    和vector类似,Map体系也有一个自JDK1.2之前遗留的工具:HashTable,它的操作接口和HashMap相似,和HashMap的区别在于:HashMap是非线程安全的,HashTable是线程安全的。

      LinkedHashMap:继承自HashMap,他主要是使用链表来扩展HashMap类,HashMap类中条目是没有顺序的,但是在LinkedHashMap中元素既可以按照他们插入时的顺序,也可以按照他们最后一次被访问的顺序排序。

    注意:Map中是根据键值来细算hashcode值。

     

 1 package com.chinasofti.map;
 2 
 3 import com.chinasofti.set.Student;
 4 
 5 import java.util.HashMap;
 6 import java.util.Map;
 7 import java.util.Set;
 8 
 9 public class HashMapTest {
10 //     必须保证key不重复
11     public static void main(String[] args) {
12         // 创建一个hashmap对象
13         Map<Integer, Student> map = new HashMap<>();
14 
15         Student s1 = new Student(1001, "z1", 99);
16         Student s2 = new Student(1002, "z2", 91);
17         Student s3 = new Student(1003, "z3", 92);
18         Student s4 = new Student(1004, "z3", 92);
19 
20         map.put(s1.getId(),s1);
21         map.put(s2.getId(),s2);
22         map.put(s3.getId(),s3);
23         map.put(s4.getId(),s4);
24 
25         // 遍历需要先获取map中的所有key值 返回一个set集合
26         Set<Integer> keys = map.keySet();
27         // 然后遍历keys 来获取每一个map内的value数据
28         for ( Integer i:keys) {
29             System.out.println(i + "---" + map.get(i));
30         }
31     }
32 }

   2.TreeMap

     TreeMap是基于红黑树实现的,键值可以使用Comparable或者Comparator接口来排序。TreeMap继承自AbstractMap,同时实现了接口的NavigableMap,而接口NavigableMap则继承自SortedMap。SortedMap是Map的子接口,使用它可以确保树中的条目是排序好。

    注意:例如下列代码中的比较器中设置比较两个student对象的成绩,当compareTo方法返回0时,TreeMap是默认两个对象是相等的,所以默认不添加到TreeSet集合中。

 1 package com.chinasofti.map;
 2 
 3 import com.chinasofti.set.Student;
 4 
 5 import java.util.Map;
 6 import java.util.Set;
 7 import java.util.TreeMap;
 8 
 9 public class TreeMapTest {
10     public static void main(String[] args) {
11         // TreeMap的排序是按照key来排序 必须保证key不重复
12         Map<Student, Student> map = new TreeMap<Student, Student>((o1,o2)->{
13             // 按照id的升序排列
14 //            return ((Integer)o1.getId()).compareTo((Integer)o2.getId());
15             return ((Double)o1.getScore()).compareTo((Double)o2.getScore());
16         });
17 
18         Student s1 = new Student(1001, "z1", 99);
19         Student s2 = new Student(1002, "z2", 91);
20         Student s3 = new Student(1003, "z3", 92);
21         Student s4 = new Student(1004, "z3", 92);
22 
23         map.put(s1,s1);
24         map.put(s2,s2);
25         map.put(s3,s3);
26         map.put(s4,s4);
27 
28         Set<Student> students = map.keySet();
29 
30         for (Student s :students) {
31             System.out.println(map.get(s));
32         }
33     }
34 }

    

    在实际使用中,如果更新Map时不需要保持图中元素的顺序,就使用HashMap,

    如果需要保持Map中元素的插入顺序或者访问顺序,就使用LinkedHashMap,

    如果需要使图按照键值排序,就使用TreeMap 

原文地址:https://www.cnblogs.com/heureuxl/p/13435952.html