• 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 

  • 相关阅读:
    lombok、japidocs、swagger学习
    mysql数据库添加新用户,并授予所有权限
    局域网内共享自己的数据库
    HttpURLConnection模板
    nginx简单学习总结
    redis常见命令
    mybatis中的#{}和${}的区别
    Python的多线程
    使用python发送邮件
    python操作MySQL数据库
  • 原文地址:https://www.cnblogs.com/heureuxl/p/13435952.html
Copyright © 2020-2023  润新知