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();
}

  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 }

输出结果为:

[[email protected], [email protected], [email protected]]
******************
[email protected]
[email protected]
[email protected]

为了显示更加明显的信息,因此增加重写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 }

输出结果为:

[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 }

显示结果为:

[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     }

显示结果为:

[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]);
         }

    }
}

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 }

输出结果为:

[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 }

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

需要注意:

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

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

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

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

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

时间: 2024-10-09 07:22:19

JAVA集合一之集合简介(Collection,List,Set)的相关文章

Java学习关于集合框架的基础接口--Collection接口

 集合框架(Collection  Framework)是Java最强大的子系统之一,位于java.util 包中.集合框架是一个复杂的接口与和类层次,提供了管理对象组的最新技术.Java集合框架标准化了程序处理对象组的方式. 集合框架在设计上需要满足几个目标.首先,框架必须是高性能的.基本集合(动态数组.链表.树以及哈希表)的实现是高效率的.很少需要手动编写这些数据引擎中的某一个.其次,框架必须允许不同类型的集合以类似的方式进行工作,并且具有高度的互操作性.再次,扩展或改造必须易于实现.为了满

Java基础知识强化之集合框架笔记12:Collection集合存储字符串并遍历

1.  Collection集合存储字符串并遍历 分析: (1)创建集合对象 (2)创建字符串对象 (3)把字符串对象添加到集合中 (4)遍历集合 2. 代码示例: 1 package cn.itcast_04; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 import java.util.Iterator; 6 7 /* 8 * 需求:存储字符串并遍历. 9 * 10 * 分析: 11 * A:创建集合对象

JAVA之旅(十八)——基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用

JAVA之旅(十八)--基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用 JAVA把完事万物都定义为对象,而我们想使用数据类型也是可以引用的 一.基本数据类型的对象包装类 左为基本数据类型,又为引用数据类型 byte Byte int Integer long Long boolean Booleab float Float double Double char Character 我们拿Integer来举例子 //整

Java学习2-日期类和Collection集合

Java学习2-日期类和Collection集合 一.日期类 1.date类 1.1 构造方法 date类用来获取时间,将毫秒值转化为时间.常用构造方法有如下: public Date():分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒). public Date(long date):分配Date对象并初始化此对象,以表示自从标准基准时间(称为"历元(epoch)",即1970年1月1日00:00:00 GMT)以来的指定毫秒数. 无参构造可以获得当前的系统时间,有参

Java基础知识强化之集合框架笔记10:Collection集合使用的步骤

集合使用的步骤: (1)创建集合对象 (2)创建元素对象 (3)把元素添加到集合 (4)遍历集合:             • 通过集合对象获取迭代器对象 • 通过迭代器对象的hasnext()方法判断是否有元素  • 通过迭代器对象的next()方法获取元素,并移动到下一个位置 备注: 迭代器,是遍历集合的一种方式. 迭代器是依赖于集合而存在的

Java基础知识强化之集合框架笔记38:Set集合之Set集合概述和特点

1. Set集合概述和特点 Collection            |--List                     有序(存储顺序和取出顺序一致),可重复            |--Set                     无序(存储顺序和取出顺序不一致),唯一  HashSet:它不保证 set 的迭代顺序:特别是它不保证该顺序恒久不变. 注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序, 而你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以

Java笔记(15):集合框架(01)

1.对象数组的概述和使用 1 package cn.itcast_01; 2 3 public class Student { 4 // 成员变量 5 private String name; 6 private int age; 7 8 // 构造方法 9 public Student() { 10 super(); 11 } 12 13 public Student(String name, int age) { 14 super(); 15 this.name = name; 16 thi

java高级特性之集合概述

java中的集合概述 map 接口 总结 java集合学习 1 java中存储数据的方式 1 数组 (基本数据类型+引用数据类型).2 集合(对象) 数组存储数据的缺点1:数组一旦创建,长度固定 2:数组不能直接确定有效元素的个数 java中的集合概述: java集合接口:Collection 接口 和Map 接口 (Collection接口 表示不按照添加顺序存放对象的集合,而且集合内的元素可以重复即 无序可重复 集合,它是List,Set,Queue..接口的父接口) Collection

java中 列表,集合,数组之间的转换

List和Set都是接口,它们继承Collection(集合),集合里面任何数据类型都可以添加 List是有序的队列,可以用重复的元素:而Set是数学概念中的集合,不能有重复的元素. 数组 长度固定  可存储任何数据类型       集合 长度可变(包括:list,set)可存储任何数据类型 列表 list   有序   长度可变   元素可重复     集set  无序   长度可变   元素不可重复 将数组转化为一个列表时,程序员们经常这样做: String[] arr = {"a"

java集合 之 set 集合

set集合可以存储多个对象,但并不会记住元素的存储顺序,也不允许集合中有重复元素(不同的set集合有不同的判断方法). 1.HashSet类 HashSet按照Hash算法存储集合中的元素,具有很好的存取和查找性能.当向HashSet中添加一些元素时,HashSet会根据该对象的HashCode()方法来得到该对象的HashCode值,然后根据这些HashCode的值来决定元素的位置. HashSet的特点:1.存储顺序和添加的顺序不同 2.HashSet不是同步的,如果多个线程同时访问一个Ha