zoukankan      html  css  js  c++  java
  • JAVA集合一之集合简介(Collection,List,Set)

      在编写JAVA程序中,我们经常会遇到需要保存一组数据对象,此时,我们可以采用对象数组来进行多个对象的保存,但对象数组存在一个最大的问题即在于长度上的限制,如果说我们现在要保存一组对象,但是我们并知道数组对象到底有多少个的时候,那么此时就遇到了困难,因此为了解决此问题,在JDK1.2中,提出了类集框架的概念,并在JDK1.5中对此框架进行了修改,加入了泛型的支持,从而保证了操作的安全性。而在整个集合中,提供了几个集合核心操作的接口,分别为:Collection、Set、List、Enumeration、Iterator、ListIterator等。

      1)单值保存的最大父接口:Collection

        所谓的单值保存指的是每次操作只保存一个对象,每次增加只增加一个对象,而在Collection接口之中定义了如下几个常用的方法:

    package com.njupt.study.collection;
    
    import java.util.Iterator;
    
    public interface Collection<E> extends Iterable<E>{
    
        /**
         * 增加数据
         * @param e
         * @return
         */
        boolean add(E e);
        /**
         * 删除指定的元素
         * @param o
         * @return
         */
        boolean remove(Object o);
        /**
         * 清除数据
         */
        void clear();
        /**
         * 判断集合是否为空
         * @return
         */
        boolean isEmpty();
        /**
         * 获取元素的个数
         * @return
         */
        int size();
        /**
         * 查找一个数据是否存在
         * @param o
         * @return
         */
        boolean contains(Object o);
        /**
         * 将集合变为对象数组后返回
         * @return
         */
        Object[] toArray();
        /**
         * 将集合变为指定类型的对象数组
         * @param <T>
         * @param a
         * @return
         */
        <T> T[] toArray(T[] a);
        /**
         * 为Iterator接口实例化,来源于父类接口Iterable
         */
        Iterator<E> iterator();
        
    }

      Collection接口本身在开发之中并不会直接的去使用,而在开发之中往往会使用两个子接口:List、Set。

      2)允许重复的子接口:List

          List接口是Collection接口的子接口,是有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

      public interface List<E>extends Collection<E>

          List接口对Collection接口进行了大量的扩充操作,而主要的扩充方法有如下几个:

      

    public interface List<E> extends Collection<E> {
        
         /**
          * 返回指定位置上的数据
          * @param index
          * @return
          */
         E get(int index);
         
         /**
          * 修改指定位置上的数据
          * @param index
          * @param element
          * @return
          */
         E set(int index, E element);
         
         /**
          * 为ListIterator接口实例化
          * @return
          */
         ListIterator<E> listIterator();
    }
    View Code

        List本身也是一个接口,所以如果要想使用这个接口就必须有子类,实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。

    1. ArrayList:

         在List接口里面ArrayList子类的使用几率是最高的,一般List接口实例化,一般想到的为ArrayList。

         

     1 package com.njupt.study.collection;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 class Student
     7 {
     8     private String name;
     9     
    10     private int age;
    11 
    12     public Student(){};
    13     
    14     public Student(String n,int a)
    15     {
    16         this.name = n;
    17         this.age = a;
    18     }
    19     
    20     public String getName() {
    21         return name;
    22     }
    23 
    24     public void setName(String name) {
    25         this.name = name;
    26     }
    27 
    28     public int getAge() {
    29         return age;
    30     }
    31 
    32     public void setAge(int age) {
    33         this.age = age;
    34     }
    35     
    36 }
    37 
    38 
    39 public class Demo02 {
    40 
    41     public static void main(String[] args) {
    42          List<Student> list  = new ArrayList<Student>();
    43          
    44          list.add(new Student("zhangsan",18));
    45          
    46          list.add(new Student("lisi",19));
    47          
    48          list.add(new Student("wangwu",17));
    49          
    50          System.out.println(list);
    51          
    52          System.out.println("******************");
    53          
    54          for(int i=0;i<list.size();i++)
    55          {
    56              System.out.println(list.get(i));
    57          }
    58     }
    59 }
    View Code

          输出结果为:

         

    [com.njupt.study.collection.Student@1fc4bec, com.njupt.study.collection.Student@dc8569, com.njupt.study.collection.Student@1bab50a]
    ******************
    com.njupt.study.collection.Student@1fc4bec
    com.njupt.study.collection.Student@dc8569
    com.njupt.study.collection.Student@1bab50a

    为了显示更加明显的信息,因此增加重写toString()方法,

    public String toString()
    {
    return this.name+"---->"+this.age;
    }

    显示结果为:

    [zhangsan---->18, lisi---->19, wangwu---->17]
    ******************
    zhangsan---->18
    lisi---->19
    wangwu---->17

    可以看见ArrayList采用的为数组方式保存元素对象。

    add 为添加元素,那么remove 可以删除元素,那么我们试试删除元素:

     1 package com.njupt.study.collection;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 class Student
     7 {
     8     private String name;
     9     
    10     private int age;
    11 
    12     public Student(){};
    13     
    14     public Student(String n,int a)
    15     {
    16         this.name = n;
    17         this.age = a;
    18     }
    19     
    20     public String getName() {
    21         return name;
    22     }
    23 
    24     public void setName(String name) {
    25         this.name = name;
    26     }
    27 
    28     public int getAge() {
    29         return age;
    30     }
    31 
    32     public void setAge(int age) {
    33         this.age = age;
    34     }
    35     
    36     public String toString()
    37     {
    38         return this.name+"---->"+this.age;
    39     }
    40 }
    41 
    42 
    43 public class Demo02 {
    44 
    45     public static void main(String[] args) {
    46          List<Student> list  = new ArrayList<Student>();
    47          
    48          list.add(new Student("zhangsan",18));
    49          
    50          list.add(new Student("lisi",19));
    51          
    52          list.add(new Student("wangwu",17));
    53          
    54          System.out.println(list);
    55          
    56          System.out.println("******************");
    57          
    58          for(int i=0;i<list.size();i++)
    59          {
    60              System.out.println(list.get(i));
    61          }
    62          
    63          System.out.println("*********删除元素*************");
    64          
    65          list.remove(new Student("wangwu",17));
    66          for(int i=0;i<list.size();i++)
    67          {
    68              System.out.println(list.get(i));
    69          }
    70          
    71     }
    72 }
    View Code

    输出结果为:

    [zhangsan---->18, lisi---->19, wangwu---->17]
    ******************
    zhangsan---->18
    lisi---->19
    wangwu---->17
    *********删除元素*************
    zhangsan---->18
    lisi---->19
    wangwu---->17

    可以看见元素并没有被删除,为什么呢?  那我们试试非自定义对象是否可以删除呢?

     1 package com.njupt.study.collection;
     2 
     3 import java.util.ArrayList;
     4 
     5 public class Demo01 {
     6 
     7     /**
     8      * @param args
     9      */
    10     public static void main(String[] args) {
    11         java.util.List<String> list =  new ArrayList<String>();
    12         
    13         list.add("a");
    14         
    15         list.add("b");
    16         
    17         list.add("c");
    18         
    19         System.out.println(list);    
    20         
    21         for (int x = 0; x < list.size(); x++) {
    22             System.out.println(list.get(x));
    23         }
    24 
    25         list.remove("c");
    26         
    27         System.out.println("**********************");
    28         
    29         for (int x = 0; x < list.size(); x++) {
    30             System.out.println(list.get(x));
    31         }
    32     }
    33 
    34 }
    View Code

    显示结果为:

    [a, b, c]
    a
    b
    c
    **********************
    a
    b

    我们发现是可以删除的,为什么我们自己定义的不能删除呢?我们看下String的源码有什么不同?

     public boolean equals(Object anObject) {
    	if (this == anObject) {
    	    return true;
    	}
    	if (anObject instanceof String) {
    	    String anotherString = (String)anObject;
    	    int n = count;
    	    if (n == anotherString.count) {
    		char v1[] = value;
    		char v2[] = anotherString.value;
    		int i = offset;
    		int j = anotherString.offset;
    		while (n-- != 0) {
    		    if (v1[i++] != v2[j++])
    			return false;
    		}
    		return true;
    	    }
    	}
    	return false;
        }
    

      原因应该就是上面的,因为对象在删除的时候,需要判断集合中的对象和要删除的对象是否一致,然后才能删除,但我们自定义对象中,并没有重写equals方法所以,删除的时候没有成功,为此,我们增加equals方法试试如何?

     1 public boolean equals(Object obj)
     2     {
     3        if(this == obj)
     4        {
     5            return true;
     6        }
     7        
     8        if(obj == null)
     9        {
    10            return false;
    11        }
    12        
    13        if( ! (obj instanceof Student) )
    14        {
    15            return false;
    16        }
    17        
    18        Student other = (Student) obj;
    19        
    20        if(this.name.equals(other.name) && this.age == other.age)
    21        {
    22            return true;
    23        }
    24        return false;        
    25     }
    View Code

         显示结果为:

         

    [zhangsan---->18, lisi---->19, wangwu---->17]
    ******************
    zhangsan---->18
    lisi---->19
    wangwu---->17
    *********删除元素*************
    zhangsan---->18
    lisi---->19

    已成功删除。

    注意:

    既然ArrayList类可以为List接口实例化,那么也就可以为Collection接口实例化,但是这个时候已经不可以继续使用get()方法操作了,所以此时只能够将Collection变为对象数组后返回。

    package com.njupt.study.collection;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    class Student
    {
        private String name;
        
        private int age;
    
        public Student(){};
        
        public Student(String n,int a)
        {
            this.name = n;
            this.age = a;
        }
        
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
        
        
        public boolean equals(Object obj)
        {
           if(this == obj)
           {
               return true;
           }
           
           if(obj == null)
           {
               return false;
           }
           
           if( ! (obj instanceof Student) )
           {
               return false;
           }
           
           Student other = (Student) obj;
           
           if(this.name.equals(other.name) && this.age == other.age)
           {
               return true;
           }
           return false;        
        }
        
        /*public boolean equals(Object obj) {
            if (this == obj) {
                return true ;
            }
            if (obj == null) {
                return false ;
            }
            if (! (obj instanceof Student)) {
                return false ;
            }
            Student t = (Student) obj ;
            if(this.name.equals(t.name ) && this.age == t.age) {
                return true ;
            }
            return false ;
        } */
    
        
        public String toString()
        {
            return this.name+"---->"+this.age;
        }
    }
    
    
    public class Demo02 {
    
        public static void main(String[] args) {
             Collection<Student> list  = new ArrayList<Student>();
             
             list.add(new Student("zhangsan",18));
             
             list.add(new Student("lisi",19));
             
             list.add(new Student("wangwu",17));
             
             System.out.println(list);
             
             System.out.println("******************");
             
             Student[] all = list.toArray(new Student[]{});
             
             for(int i=0;i<all.length;i++)
             {
                 System.out.println(all[i]);
             }
             
        }
    }
    View Code

         2. LinkedList

         同样实现List接口的LinkedList与ArrayList不同,ArrayList是一个动态数组,而LinkedList是一个双向链表。所以它除了有ArrayList的基本操作方法外还额外提供了insert方法在LinkedList的首部或尾部。

         由于实现的方式不同,LinkedList不能随机访问,它所有的操作都是要按照双重链表的需要执行。在列表中索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。这样做的好处就是可以通过较低的代价在List中进行插入和删除操作。

         与ArrayList一样,LinkedList也是非同步的。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List: 
    List list = Collections.synchronizedList(new LinkedList(…));

         ArrayList擅长于随机访问。同时ArrayList是非同步的。

         3. Vector

         Vector类是在JDK 1.0的时候所推出的最早的实现数据结构支持的类,其最早翻译为向量,但是到了JDK 1.2之后,为了使其可以继续使用,所以让这个类多实现了一个List接口,这样一来,就造成了Vector子类的操作方法比ArrayList更多,但是一般这些多的方法很少考虑。

          与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。

          4.Stack

          Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop 方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

    ArrayList和Vector的区别:

    ArrayList和Vector都属于List接口的常用子类,这两者在操作形式以及概念上的区别如下:

    No.

    区别点

    ArrayList

    Vector

    1

    推出时间

    JDK 1.2时推出,属于新的类

    JDK 1.0时推出,属于旧的类

    2

    性能

    使用异步处理方式,性能较高

    采用同步处理操作,性能相对较低

    3

    安全性

    非线程安全

    线程安全

    4

    输出

     

     

             因为Java主要从事于网络的开发,所以使用异步的处理操作形式要比使用同步(Synchronized)更多。

      3)不允许重复的子接口:Set

          Set接口与List接口最大的不同在于里面的数据不允许有重复,那么首先观察一下Set接口的继承结构:

    public interface Set<E>
    extends Collection<E>

             Set是一种不包括重复元素的Collection,与List一样,它同样运行null的存在但是仅有一个。由于Set接口的特殊性,所有传入Set集合中的元素都必须不同,同时要注意任何可变对象,如果在对集合中元素进行操作时,导致e1.equals(e2)==true,则必定会产生某些问题。实现了Set接口的集合有:EnumSet、HashSet、TreeSet。

              1.EnumSet

               是枚举的专用Set。所有的元素都是枚举类型。

               2.HashSet

                哈希(Hash)是一种数据的排列算法,这种算法的典型操作就是加塞算法,那块有地就保存,所以只要带有hash都是无序的。HashSet堪称查询速度最快的集合,因为其内部是以HashCode来实现的。它内部元素的顺序是由哈希码来决定的,所以它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。

     1 package com.njupt.study.collection;
     2 
     3 import java.util.HashSet;
     4 import java.util.Set;
     5 
     6 public class Demo03 {
     7 
     8     /**
     9      * @param args
    10      */
    11     public static void main(String[] args) {
    12         Set<String> all = new HashSet<String>();
    13         all.add("Hello");
    14         all.add("World");
    15         all.add("Hello"); // 重复数据
    16         System.out.println(all);
    17     }
    18 
    19 }
    View Code

    输出结果为:

    [World, Hello]

    通过本程序可以发现,里面所保存的顺序改变,而且如果有重复的数据也不能够保存。

              3.TreeSet

              在TreeSet子类里面所有保存的数据是没有重复的,而且可以为用户自动的进行排序。基于TreeMap,生成一个总是处于排序状态的set,内部以TreeMap来实现。它是使用元素的自然顺序对元素进行排序,或者根据创建Set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

    关于排序的说明:既然在TreeSet中的所有数据都可以排序,而且里面设置的数据也都是对象,那么下面就使用自定义类完成。

    但是这个时候必须注意到一点:对于现在的TreeSet子类而言,由于其要对一组对象进行排序,那么这个对象所在的类就一定要实现Comparable接口,用于指定排序规则;

     1 package com.njupt.study.collection;
     2 
     3 import java.util.Set;
     4 import java.util.TreeSet;
     5 
     6 
     7 class Student implements Comparable<Student>
     8 {
     9     private String name;
    10     
    11     private int age;
    12 
    13     public Student(){};
    14     
    15     public Student(String n,int a)
    16     {
    17         this.name = n;
    18         this.age = a;
    19     }
    20     
    21     public String getName() {
    22         return name;
    23     }
    24 
    25     public void setName(String name) {
    26         this.name = name;
    27     }
    28 
    29     public int getAge() {
    30         return age;
    31     }
    32 
    33     public void setAge(int age) {
    34         this.age = age;
    35     }
    36     
    37     
    38     public boolean equals(Object obj)
    39     {
    40        if(this == obj)
    41        {
    42            return true;
    43        }
    44        
    45        if(obj == null)
    46        {
    47            return false;
    48        }
    49        
    50        if( ! (obj instanceof Student) )
    51        {
    52            return false;
    53        }
    54        
    55        Student other = (Student) obj;
    56        
    57        if(this.name.equals(other.name) && this.age == other.age)
    58        {
    59            return true;
    60        }
    61        return false;        
    62     }
    63 
    64     
    65     public String toString()
    66     {
    67         return this.name+"---->"+this.age;
    68     }
    69 
    70     @Override
    71     public int compareTo(Student o) {
    72         if (this.age > o.age) {
    73             return 1;
    74         } else if (this.age < o.age) {
    75             return -1;
    76         } else {
    77             return this.name.compareTo(o.name);
    78         }
    79     }
    80 }
    81 
    82 public class Demo04 {
    83 
    84     /**
    85      * @param args
    86      */
    87     public static void main(String[] args) {
    88         Set<Student> all = new TreeSet<Student>();
    89         all.add(new Student("张三",20)) ;
    90         all.add(new Student("李四",19)) ;
    91         all.add(new Student("王五",22)) ;    // 年龄一样
    92         all.add(new Student("赵六",22)) ;    // 年龄一样
    93         all.add(new Student("孙七",25)) ;
    94         all.add(new Student("孙七",25)) ;    // 插入了重复的数据
    95         all.remove(new Student("李四",19)) ;    // 删除一个数据 
    96         System.out.println(all);
    97     }
    98 
    99 }
    View Code

    显示结果为:[张三---->20, 王五---->22, 赵六---->22, 孙七---->25]

    需要注意:

    实现了对自定义类对象的排序,并且可以判断重复元素,但是TreeSet类只是利用了Comparable完成了重复元素的判断,可是这种判断并不是真正意义上的重复元素判断。

    如果说现在要想判断一个对象是否重复,严格来讲,这个操作是由Object类所提供的,在任何一个子类里面需要覆写Object类中的以下两个方法;

                      · 对象比较:public boolean equals(Object obj);

                      · 对象编码:public int hashCode();

             hashCode()方法是用于进行对象编码计算的操作方法,如果要想进行对象的编码,那么肯定需要一些数学上的支持,这里就不详细讲解了。

  • 相关阅读:
    接口与抽象类
    观察者模式
    kibana安装
    使用CGLib完成代理模式遇到的错误
    代理模式
    HashMap resize方法的理解(一)
    装饰模式
    volatile关键字解析(二)
    https网站引用http路径的js和css失效解决办法
    IIS7.5配置自动添加www 及 限制通过IP访问web
  • 原文地址:https://www.cnblogs.com/pony1223/p/4869422.html
Copyright © 2011-2022 走看看