zoukankan      html  css  js  c++  java
  • JAVA集合类兄妹List和Set

      List 接口及其实现类

    • 有序集合,集合中每个元素都有其对应的顺序索引,类似数组,索引也是从 0 开始,可以根据元素的索引,来访问元素。

    • List 集合允许添加相同的元素,因为它是通过下标来取值的,不会因为元素相同而产生冲突。

      如何应用接口List的一个重要实现类 ArrayList呢?

    1. ArrayList集合类的定义与添加集合元素(不同类型的元素)

      

      2.访问集合元素通过get(集合下标) 获取的是抽象Object对象类型,这里需要强转弱,自动拆箱

    •   String s1=(String)ls.get(0);
    •   int s2=(Integer)ls.get(1);
    •   double s1=(Double)ls.get(2);

      3.删除元素

      ls.remove(1);//删除下标为1的对象

      4.遍历集合元素

      数组遍历是通过游标遍历,List集合类遍历集合元素类似于数组遍历,也可以通过索引遍历,另外List集合类还可以使用Iterator接口遍历集合元素(实际上,所有Collection集合类都可以使用Iterator接口遍历集合元素,因为实现类都实现Iterable<E>接口

      

    • 使用Iterator接口遍历集合元素

      

      5.对元素集合进行排序

      一般有两种方式

      第一种是

      封装类实现了Comparator接口,封装类就是平常的VO/PO类,例如User

      

    public class User implements Comparable<User>  
    {  
        private String name;  
        private Integer age;  
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
        public Integer getAger() {  
            return age;  
        }  
        public void setAge(Integer age) {  
            this.age= age;  
        }  
        public int compareTo(User arg0) {  
            return this.getAge().compareTo(arg0.getAge());  
        }  
    }  

    //测试客户端代码
    public static void main(String[] args) {  
            User user1 = new User();  
            user1.setName("zhangsan");  
            user1.setAge(10);  
            User user2 = new User();  
            user2.setName("lisi");  
            user2.setAge(6);  
            List<User> list = new ArrayList<User>();  
            list.add(user1);  
            list.add(user2);  
            Collections.sort(list);  //排序
            for(User u : list){  
                System.out.println(u.getName());  //输出
         } 

         }
      lisi
     zhangshan

      第二种是封装类没有实现Comparable接口,此时需要在调用sort的另一个有参方法,依旧是这个封装类,但是没有实现Comparable,我这里就不写封装类,同上

      

            User user1 = new User();  
            user1.setName("zhangsan");  
            user1.setAge(10);  
            User user2 = new User();  
            user2.setName("lisi");  
            user2.setAge(6);  
            List<User> list = new ArrayList<User>();  
            list.add(user1);  
            list.add(user2);          //初始化list
            Collections.sort(list,new new Comparator<User >(){
                          
                //覆盖排序方法
              public int compare(User u1, User u2) {
                    //按照User的年龄进行升序排列
                    if(u1.getAge() > u2.getAge()){
                        return 1;
                    }
                    if(u1.getAge() == u2.getAge()){
                        return 0;
                    }
                    return -1;
                } 
             });  //排序    
      

      如何应用Vector?

      Vector与ArrayList在用法上几乎完全相同。但是它是线程安全的,也就是加了同步锁,相比之下性能会显得慢一些

      那么在多线程下的ArrayList怎么样?

      两个线程同时访问,对容器的同一位置进行了同一时刻的赋值,则会达不到希望容器产生的效果,比如

    •   循环10000次在多线程可能会小于100000次
    •   在ArrayList扩容的时候会造成数组越界,产生非常诡异的异常

      Set接口及其实现类

      Set集合类特点是什么?

    • 无序集合

    • 不允许包含重复元素,根据equals方法判断两个对象相同

      如何应用Set接口的一个重要实现类HashSet呢

      1.HashSet集合类的定义与添加集合元素

    • HashSet集合添加一个元素时,会先得到该对象的hashCode值,然后通过equals方法判断集合内是否已存在相同的对象,如果已存在相同的对象,即hashcode指向的内存地址相同,则无法添加该对象。String字符串重写了equals方法,虽然str1(小明)与str2(小张)是两个不同的对象,但str1.equals(str2);返回是false,因此添加str2失败。
    • HashSet是先比较元素的HashCode的值,也就是哈希值,如果哈希值相同的情况下,会调用equals方法比较两个元素的值是否相同。
    • Set的另外一个实现类TreeSet则是通过调用CompareTo的方法,如果返回值为0,证明两个元素相同,因此TreeSet其实是一个有序的集合。

      2.遍历集合元素

    •  HashSet集合只能通过Iterator接口或者增强for循环遍历集合元素,且因为HashSet不能保证元素的排列顺序,因而遍历读取集合元素的顺序是有可能发生变化的

     

    //增强for的方式
    for
    (Person p:set){ System.out.println(p.name+p.age); }

      3.删除元素

    • set.remove(p1);

      Map接口及其实现类

         Map集合的特点是什么?

    •  双列集合,保存两组值,一组是键key,另一组是值value,key和value之间存在单向一对一关系,通过指定的key,总能找到唯一的、确定的value
    • Map集合类的key不允许重复,根据equals方法判断两个key相同

    • Map集合类的key和value可以是任何类型的数据(键和值都可以为null)

      如何应用HashMap?

    • HashMap集合类添加键值对时,先根据equals方法判断要添加键值对的key是否存在,如果存在,value会发生覆盖,如果不存在,添加新的键值对。

      遍历集合元素

      1.keySet()方法获取元素

      原理:

    • 将Map集合中的所有键(Key)存入到Set集合中,因为Set集合具备迭代器,所以可以用迭代方式取出所有的键,再根据get方法获取每一个键对应的值。简单说就是:Map集合---->Set集合 ---->迭代器取出

     

       2.entrySet()方法获取元素:

      原理:

    • 将Map集合中的映射关系(Key-Value)存入到了Set集合中,而这个映射关系的数据类型是Map.Entry,在通过迭代器将映射关系存入到Map.Entry集合中,并通过其中的getKey()和getValue()放取出键值。

     

      其余还有其他遍历方式,比如说增强for,但是前提都是要获得Set存储Key的集合,即调用map.KeySet(),然后转化为String,在通过getValue("Key")的方式获取值,在实际开发当中比如获取数据库查询回来的ResultSet 都是rs,getString("字段名)

    • 遍历得到结果的顺序并不是添加顺序,实际上,Map里的key和Set集合的存储形式(无序)类似,与HashSet集合不能保证元素的顺序一样,HashMap也不能保证其中key-value键值对的顺序。

      删除集合元素

      map.remove(key);

      集合类之间的几种比较(小结)

      1.Vector、ArrayList、LinkedList的异同?分别适用于何种需求?

    ArrayList和Vector都是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许通过顺序索引查找元素,但是插入数据、删除数据要设计到数组元素移动等内存操作,所以查找数据快、增删数据慢。ArrayList和Vector在用法上几乎相同,但有一点明显区别:ArrayList是线程不安全的,多线程情况下,需要写代码保证集合的同步性;Vector是线程安全的,它使用了synchronized方法保证了多线程情况下集合的同步性;也正因为Vector的线程安全,它在性能上比ArrayList差。

    LinkedList,首先它是一个List集合,可以根据索引来随机访问集合中的元素,这个与ArrayList的用法相同。除此之外,LinkedList采用双向链表实现存储,查找数据时需要进行向前或向后遍历,直到找到索引数据;但是插入数据时只需要记录本项的前后项即可,所以查找数据慢、增删数据快。

    Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向链表数据结构(注意双向链表和双向循环链表的区别)

    ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)

     

    适用需求建议:

    • 需要经常遍历集合元素,建议使用ArrayList、Vector
    • 需要经常执行插入、删除操作来改变集合的大小,建议使用LinkedList
    • 多线程的情况下,可以考虑Vector。但也可以考虑ArrayList,另外写代码保证集合的同步性
    • 关于CopyOnWriteArrayList也是一个线程安全的容器,原理是

      CopyOnWriteArrayList底层就是数组,加锁就交由ReentrantLock来完成。

      在添加的时候就上锁,并复制一个新数组,增加操作在新数组上完成,将array指向到新数组中,最后解锁。

      在修改时,复制出一个新数组,修改的操作在新数组中完成,最后将新数组交由array变量指向。

      写加锁,读不加锁

     

      2.HashSet与TreeSet的异同?分别适用于何种需求?

    HashSet与TreeSet相同点:都是Set接口的实现类,集合元素都不允许重复;

    HashSet与TreeSet不同点:

    HashSet中的数据是无序的,可以放入null,且只能放入一个null,通过计算元素的hashCode值快速操作,所以HashSet的效率很高。

    TreeSet中的数据是自动排序的,这个有序不同于List接口那样按照插入的先后顺序而且有对应的索引,这个顺序是按照元素对象自己定义的排序规则而定的。默认情况下,TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列,基于TreeMap。因此,TreeSet中的每个对象的类都必须实现Comparable接口定义排序规则才可以正常使用,如String等这些类本身已经实现Comparable接口并有默认顺序,而null没有实现Comparable接口,所以TreeSet不允许放入null值。

      3.HashMap、TreeMap、HashTable的异同?分别适用于何种需求?

    HashMap和HashTable的关系类似于ArrayList和Vector的关系,HashTable与HashMap的用法基本相同,两者的区别有:

    HashMap允许有空键(null)与空值(null),非线程安全,效率较高;

    Hashtable不允许有空键(null)与空值(null),线程安全,效率较低;

    TreeMap与HashMap的关系也类似与TreeSet和HashSet的关系,TreeMap实现SortMap接口,能够把它保存的键值对根据key排序,基于红黑树,从而保证TreeMap中所有键值对处于有序状态。TreeMap要求所有的key必须实现Comparable接口,默认遵循key的默认排序规则,也可以指定排序的比较器。当用Iterator 遍历TreeMap时,得到的记录是排过序的(类似TreeSet),不允许有空键(null)。

      by the way

      fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。抛java.util.ConcurrentModificationException

      

  • 相关阅读:
    Software Solutions CACHE COHERENCE AND THE MESI PROTOCOL
    CACHE COHERENCE AND THE MESI PROTOCOL
    Multiprocessor Operating System Design Considerations SYMMETRIC MULTIPROCESSORS
    Organization SYMMETRIC MULTIPROCESSORS
    PARALLEL PROCESSING
    1分钟内发送差评邮件
    Secure Digital
    SYMMETRIC MULTIPROCESSORS
    A Taxonomy of Parallel Processor Architectures
    parallelism
  • 原文地址:https://www.cnblogs.com/zhuoqingsen/p/List_Set.html
Copyright © 2011-2022 走看看