Java类集框架

2017-09-05  本文已影响0人  残月雨纷纷

在基础应用中,通常我们可以通过数组来保存一组具有相同属性的对象或者基本类型的数据,但使用数组的弊端在于其大小不可更改,出于灵活性考虑,可以使用链表来实现动态的数组。任何事情具有两面性,灵活性的代价就是操作上的繁琐。在计算机世界里,处理繁琐问题的常用方法就是将其封装,只向外提供可调用方法的视图。Java类集框架就是对这一方法的一种官方实现一套动态对象数组的操作类。本质上,Java类集框架就是Java对数据结构的一个大体上的封装。
在java.util包中定义了所有与类集有关的操作接口:Collection,List,Set,Map,Iteraror,ListIterator,Enumeration。

在Java中,每个变量都有其所属的数据类型,要么是基本数据类型(int,float,char等)要么是自定义的数据类型--即类。而泛型的本质就是将变量”的类型”参数化,也就是说所操作的数据类型被指定为一个参数这种参数类型可以用在类,接口和方法的创建中,分别称为泛型类,泛型接口,泛型方法。



类集接口

接口 描述
Collection 能操作一组对象,他位于类集层次结构的顶层
List 扩展Collection支持处理序列(对象的列表)
Set 扩展Collection支持处理集合,集合元素必须唯一
SortedSet 扩展Set支持处理序列集合

在这些接口中定义了操作该类集的一些方法。支持这些方法的类集被称为可修改的(modifiable)。不允许修改其内容的类集被称为不可修改的(unmodifiable)。而所有内置的类集都是可修改的。如果对一个不可修改的类集使用这些方法,将引发一个UnsupportedOperationExcepation异常



单值保存的最大父接口--Collection

Collection接口是构造类集框架的基础,是单值数据操作的最大父接口它声明了所有类集都将拥有的核心方法。所有类集均实现Collection。其中有几种方法可能会引发一个UnsupportedOperationExcepation异常。这些异常将发生在修改不能被修改的类集的时候。当一个对象与另一个对象不兼容,例如企图增加一个不兼容的对象到一个类集中时,将产生一个ClassCastException异常。

方法 描述
boean add(Object obj) 将obj加入到调用类集中。如果obj被加入到类集中了,则返回true;如果此collection不允许有重复元素,并且已经包含了obj,则返回false
boolean addALL(Collection c) 将c中所有元素都加入到调用类集中,如果操作成功(元素被加入了),则返回true,否则返回false
void clear( ) 从调用类集中删除所有元素
boolean contains(Obiect obj) 如果obj是调用类集的一个元素,则返回true,否则返回false
boolean containsALL(Collection c) 如果调用类集包含了c中的所有元素,则返回true,否则返回false
boolean equals(Object obj) 如果调用类集与obj相等,则返回true,否则返回false
int hashCode( ) 返回调用类集的hash(哈希)值
boolean isEmpty( ) 如果调用类集是空的,则返回true,否则返回false
Iterator iterator( ) 返回调用类集迭代器
boolean remove(Object obj) 从调用类集中删除obj的一个实例。如果这个元素被删除了则返回true,否则返回false
boolean removeALL(Collection c) 从调用类集中删除c的所有元素。如果类集被改变了(也就是说元素被删除了),则返回true,否则返回false
boolean retainALL(Collection c) 删除调用类集中除了包含在c中的元素之外所有元素,如果类集被改变了(也就是说元素被删除了),则返回true,否则返回false。
int size( ) 返回调用类集中元素的个数
Object[ ] toArray( ) 返回一个数组,该数组包含了所有存储在调用类集中的元素。数组元素是类集元素的备份
Object[ ] toArray(Object array[ ]) 返回一个数组,该数组仅仅包含了那些类型与数组元素类型匹配的类集元素。数组元素是类集元素的备份。如果array的大小与匹配元素的个数相等,它们被返回到array。如果的大小比匹配元素的个数小,将分配并返回一个所需大小的新数组。如果array的大小比匹配元素的个数大,在数组中,在类集元素之后的单元被置为null。如果任一类集元素的类型都不是array的子类型,则引发ArrayStoreException异常

在Collection接口中所提供的方法一定是日后进行程序开发中使用最多的方法,但是Collection接口很少在开发中直接使用,往往都会使用它的子接口:List(允许有重复元素,Set(不允许有重复元素)。



Collection接口的具体实现类
一些类提供了完整的可以被使用的工具。另一些类是抽象的,提供主框架工具,作为创建具体类集的起始点。没有一个屋Collection接口是同步的,但是可以通过一些方法获得同步版本。标准的Collection实现类如下:

描述
AbstractCollection 实现大多数Collection接口
AbstractList 扩展AbstractCollection并实现大多数List接口
AbstractSequentialList 为了被类集使用而扩展AbstractList,是连续而不是用随机方式访问其元素
LinkedList 通过扩展AbstractSequentialList来实现链接表
ArrayList 通过扩展AbstractList来实现动态数组
AbstractSet 扩展AbstractCollection并实现大多数Set接口
HashSet 为了使用散列表而扩展AbstractSet
TreeSet 实现存储在数中的一个集合,扩展AbstractSet

除了Collection接口之外,还有几个以前版本遗留下来的类,如Vector,Stack和Hashtable等均被重新设计成支持类集的形式。



允许重复的子接口---List
List(列表)是Collection接口之中最为常见的一个子接口。 List子接口定义:
public interface List<E> extends Collection<E>
List子接口对Collection接口进行了大量的扩充。List接口扩展了Collection并声明存储一系列元素的类集的特性。使用一个基于零的下标,元素可以通过他们在列表中的位置被插入和访问。
一个列表可以包含重复的元素,即可以存在完全相同的两个元素。除了由Collection定义的方法之外,List还定义了一些他自己的方法。注意:当类集不能被修改时,其中几种方法将引发UnsupportedOperationException异常。当一个对象与另一个不兼容时,例如企图将一个不兼容的对象加入一个类集中,将产生ClassCastException异常

方法 描述
void add(int index,Object obj) 将obj插入调用列表,插入位置的下标由index传递。任何已存在的,在插入点以及插入点之后的元素将后移。因此没有元素被覆写
boolean addALL(int index,Collection c) 将c中的所有元素插入到调用列表中,插入点的下标由index传递。在插入点以及插入点之后的元素将后移。因此,没有元素被覆写。如果调用列表变了,则返回true,否则返回false
Object get(int index) 返回存储在调用类集指定下标处对象
int indexOf(Object obj) 返回调用列表中obj第一次出现的下标。如果obj不是列表中的元素,则返回-1
int lastIndexOf(Object obj) 返回调用列表中obj最后一次出现的下标。如果obj不是列表中的元素则返回-1
ListIterator listIterator() 返回调用列表开始的迭代器
ListIterator listIterator(int index) 返回调用列表在指定下标处开始的迭代器
Object remove(int index) 删除调用列表中index位置的元素并返回删除的元素删除后,列表被压缩。也就是说被删除元素的后面的元素下标减一
Object set(int index,Object obj) 用obj对调用列表内由index指定的位置进行赋值
List subList(int start,int end) 返回一个列表,该列表包括了调用列表中从start到end-1的元素。返回列表中的元素也被调用对象引用

对于由Collection定义的add()和addALL()方法,List增加了方法add(int,Object)和addALL(int,Collection)的语义也被List改变了,以便他们在列表的尾部增加元素。
为了获得在指定位置存储的对象,可以用对象的下标调用get()方法。为了给类集中的一个元素赋值,可以调用set()方法,指定被改变的对象的下标。调用indexOf()或lastIndexOf()可以得到一个对象的下标。通过调用subList()方法,可以获得列表的一个指定了开始下标和结束下标的子列表。
由于List本身还属于接口,要想使用接口,就必须知道实现这个接口的子类,在List接口中有两个最为常用的子类:ArrayList,Vector



ArrayList类
ArrayList类扩展AbstractList并执行List接口。ArdayList支持可随需要而增长的动态数组。在Java中,标准类型的数组是定长的。一旦数组被创建之后,他们不能被加长或缩短,这就意味着开发者必须事先知道数组可以容纳多少元素。
但是一般情况下,只有在运行时才知道需要多大的数组。为了解决这个问题,类集框架定义了ArrayList。本质上,ArrayList是对象引用的一个变长数组。也就是说,ArrayList能够动态的增加或减小其大小。数组列表以一个原始大小被创建。当超过了它的大小时,类集自动增大,当有对象被删除,数组就可以缩小(动态数组也被从前版本遗留下来的类Vector所支持)。

ArrayList构造方法如下:
ArrayList()
ArrayList(Collection)
ArrayList(int capacity)
第一个构造方法构造一个初始容量为10的空列表。第二个构造方法建立一个数组列表,该数组列表由类c中的元素初始化。第三个构造方法建立一个数组列表,该数组有指定的初始容量(capacity),容量用于存储元素的基本数组的大小。当元素被追加到数组列表上时,容量会自动增加。

ArrayList类使用范例
import java.util.*;
public class Main
{
    public static void main(String args[])
    {
        //创建一个ArrayList对象
        ArrayList<String> al=new ArrayList<String>();  //尖括号<>中的String表明ArrayList的数组链表对象al,这个数组链表中的元素为String类型。尖括号<>内的数据类型是可变的,除了String类型还可以是其他类型如Integer等,这表明变量类型也是可变的---这就是Java泛型的表现
        System.out.println("a1中元素的个数"+al.size());
        //向ArrayList对象中添加新内容
        al.add("C");   //在数组列表0位置添加元素C
        al.add("A");   //在数组列表1位置添加元素A
        al.add("E");   //在数组列表2位置添加元素E
        al.add("B");   //在数组列表3位置添加元素B
        al.add("D");   //在数组列表4位置添加元素D
        al.add("F");   //在数组列表5位置添加元素F
        al.add(1,"A2");  //把A2加在ArrayList对象的第二个位置
        System.out.println("a1加入元素之后的元素个数:"+al.size());
        System.out.println("a1的内容:"+al);   //显示ArrayList数据
        al.remove("F");  //删除元素F
        al.remove(2);  //删除下标为2的元素
        System.out.println("a1删除元素之后的元素个数:"+al.size());
        System.out.println("a1的内容:"+al);
        
    }
}

当对象被存储在ArrayList对象中时,其容量会自动增加。然而也可以调用ensureCapacity()方法来人工增加ArrayList的容量。如果事先知道将在当前的类集中存储大量数据时,可以这么做。在开始通过一次性人工增加它的容量,就能避免后面的再分配。因为在分配很花时间,避免不必要的处理可以提高性能。

ArrayList类使用范例
import java.util.*;
public class Main
{
    public static void main(String args[])
    {
        //创建一个ArrayList对象al
        ArrayList<Integer> al=new ArrayList<Integer>();
        //向ArrayList中加入对象
        al.add(new Integer(1));
        al.add(new Integer(2));
        al.add(new Integer(3));
        al.add(new Integer(4));
        System.out.println("ArrayList中的内容:"+al);
        //得到对象数组
        Object ia[]=al.toArray();
        int sum=0;
        //计算数组内容
        for(int i=0;i<ia.length;i++)
        {
            sum+=((Integer)ia[i].intValue();   //将元素转换成Integer类型并取值
        }
        System.out.println("数组累加结果是:"+sum);
    }
}


LinkedList类
LinkedList类扩展了AbstractSequentialList类并实现List接口它提供了一个链接列表的数据结构。构造方法如下:
LinkedList()
LinkedList(Collection c)
第一个构造方法建立一个空的链接列表。第二个构造方法建立一个链接列表。该链接列表由类c中的元素初始化。
除了它继承的方法之外,LikedList类本身还定义了一些有用的方法,这些方法主要用于操作和访问列表。使用addFirst()方法可以在列表头增加元素,使用addLast()方法可以在列表的尾部增加元素。形式如下:
void addFirst(Object obj)
void addLast(Object obj)
在这里obj是被增加的对象。
调用getFirst()方法可以获得第一个元素,调用getLast()方法可以得到最后一个元素。形式如下:
Object getFirst();
Object getLast();
为了删除第一个元素,可以使用removeFirst()方法。删除最后一个元素,可以调用removeLast()方法。形式如下:
Object removeFirst();
Object removeLast();

LinkedList类的使用**
import java.util.*;
public class Main
{
    public static void main(String args[])
    {
        LinkedList<String> LL=new LinkedList<String>();
        //加入元素到LinkedList对象
        LL.add("F");
        LL.add("F");
        LL.add("D");
        LL.add("E");
        LL.add("C");
        //在链表的最后一个位置加上数据
        LL.addLast("Z");
        //在链表的第一个位置加上数据
        LL.addFirst("A");
        //在链表第二个元素的位置加上数据
        LL.add(1,"A2");
        System.out.println("LL最初的内容:"+LL);
        //从LinkedList中移除元素
        LL.remove("F");
        System.out.println("删除元素Fh后LL的内容:+"+LL);
        LL.remove(2);
        System.out.println("从LL中移除第二个元素后的内容:"+LL);
        //移除第一个和最后一个元素
        LL.removeFirst();
        LL.removeLast();
        System.out.println("LL移除第一个和最后一个元素之后的内容:"+LL);
        //取得并设值
        Object val=LL.get(2);
        LL.set(2,(String)val+"Changed");
        System.out.println("LL被改变之后:"+LL);
    }
}


旧的子类---Vector
Vector实现动态数组,与ArrayList相似,但两者不同的是:Vector是同步的,并且它包含了许多不属于类集框架的从以前版本遗留下来的方法。随着Java2的公布,Vector被重新设计来扩展AbstractList和实现List接口,因此他是与类集完全兼容的。下面构造方法:
Vector()
Vector(int size)
Vector(int size,int incr)
Vector(Collection c)
第一种形式创建一个原始大小为10的默认矢量。第二种形式创建一个其原始容量由size指定的矢量。第三种形式创建一个其原始容量由size指定,并且它的增量由incr指定的矢量,增量指定了矢量每次允许向上改变大小的元素个数。第四种形式创建一个包含类集c中元素的矢量。
所有矢量开始都有一个原始的容量。在这个原始容量达到以后,下次在试图向矢量中存储对象时,矢量会自动为那个对象分配空间,同时分别为对象增加额外的空间。通过分配超过需要的内存,减小了矢量可能产生的分配次数。这种次数的减少是很重要的,因为分配内存很花时间,在每一次再分配中,分配的额外空间的总数由在创建矢量时指定的增量来确定。如果没有指定增量,在分配周期,矢量的大小增加一倍。
Vector定义了下面的保护数据成员:
int capacityIncrement;
int elementCount;
Object elementData[ ];
增量值被存储在capacityIncrement中,矢量中的当前元素的个数被存储在elementCount中,保存矢量的数组被存储在elementData中。
除了由List定义类集方法之外,Vector还定义了几个以前版本遗留下来的方法:

方法 描述
finalvoiddaddElement(Objectelement) 将element指定的对象加入矢量
intcapacity() 返回矢量的容量
Objectclone() 返回调用矢量的一个备份
booleancontains(Objectarray[]) 将包含在调用矢量中的元素复制到由array指定的数组中
ObjectelementAt(intindex) 返回由index指定位置的元素
Enumerationelements() 返回矢量中元素的一个枚举
ObjectfirstElement() 返回矢量的第一个元素
intindexOf(Objectelement) 返回element首次出现的位置下标。如果对象不在矢量中,则放-1
intindexOf(Objectelement,intstart) 返回element在矢量中,在start以及之后第一次出现的位置下标。如果该对象不属于矢量的这一部分,则返回-1
voidinsertElementAt)Objectelement,int index) 在矢量中,在由index指定的位置处加入element
booleanisEmpty() 如果矢量是空的,则返回true,如果他包含了一个或更多个元素,则返回false
ObjectlastElement() 返回矢量中最后一个元素
intlastIndexOf(Objectelement) 返回element在矢量中最后一次出现的位置下标。如果对象不包含在矢量中,则返回-1
intlastIndexOf(Objectelement,intstart) 返回element在矢量中,在start之前最后一次出现的位置下标。如果该对象不属于矢量的这一部分,则返回-1
voidremoveALLElements() 清空矢量,在这个方法执行以后,矢量大小为0
booleanremoveElement(Objectelement) 从矢量中删除element。对于指定的对象,矢量中如果有许多个实例,则其中的第一个实例被删除。如果删除成功,则返回true,如果没有发现对象,则返回false
voidremoveElementAt(intindexx 删除由index指定位置处的元素
voidsetElementAt(Objectelement,intindex) 将由index指定的位置分配给element
voidsetSize(intsize) 讲矢量中元素个数设置为size。如果新的长度小于老的长度,元素将会丢失,如果新的长度大于老的长度,则在后增加null元素
intsize() 返回矢量中当前元素的个数
StringtoString() 返回矢量的字符成为等价形式
voidtrimToSize() 将矢量的容量设为与其当前拥有的元素个数相等

因为Vector实现List,所以可以像使用ArrayList的一个实例那样使用矢量。也可以使用从它的以前版本遗留下来的方法来操作她。例如,在后面实例化Vector,可以通过调用addElement()方法而为其增加一个元素。调用element()可以获得指定位置处的元素。
调用firstElement()方法可以得到矢量的第一个元素,调用lastElement()可以检索到矢量的最后一个元素,使用indexOf()和lastIndexOf()方法可以获得元素的下标,调用removeElement()或removeElementAt()方法可以删除元素。

使用矢量存储不同类型的数值对象
import java.util.*;
class jdjdkdxk
{
    public static void main(String args[])
    {
        Vector<String> v=new Vector<String>();
        v.add("A");
        v.add("B");
        v.add("C");
        v.add("D");
        v.add("E");
        v.add("F");
        Enumeration<String> e=v.elements();
        while(e.hasMoreElements())
        {
            System.out.println(e.nextElement()+"   ");
        }
    }
}
枚举方法nextElement()用于获得枚举中的下一个元素

Java2以后,Vector增加了对迭代(Iterator)方法的支持。可以使用迭代方法来代替枚举去遍历对象。下例基于迭代方法的程序代码可以被替换到上面的程序中

import java.util.*;
class jdjdkdxk
{
    public static void main(String args[])
    {
        Vector v=new Vector();
        v.add("A");
        v.add("B");
        v.add("C");
        Iterator i=v.iterator();
        while(i.hasNext())
        {
            System.out.println(i.next()+"\t");
        }
    }
}


数组操作类------Arrays
本质上,类集本身是一个对象数组。java.util.Arrays类是可以操作数组的。Arrays类数组操作类,可用来操作数组(如数组元素排序,搜索和填充等)的各种方法。Arrays类常用如下方法表示:

方法名称 类型 功能简述
static<T>List<T> asList(T...a) 静态 将多个元素变为List集合
static int binarySearch(int[] a,int key) 静态 使用二分搜索法,查询key元素值是否在a数组中,若不存在则返回负数,调用次方法前要求数组以升序排序。次方法可以被多次重载
static int[] copyOf(int[] original,int newLenggh 静态 复制指定的数组。original表示原数组,newLength表示需要复制的长度,默认从第一个元素开始赋值。次方发可以被多次重载。
static int[] copyOf(int[] original,int newLength) 静态 newLength表示需要复制的长度。默认从第一个元素开始赋值。此方发可以被多次重载
static boolean equals(int[] a,int[] a2) 静态 比较两个数组是否相等,若相等则返回true,否则返回false。此方发可以被多次重载
static void fill(int[] a,int val) 静态 将指定的int val分配给指定的int型数组的每个元素。此方发可以被多次重载
static void sort(int[] a) 静态 对指定的数组按升序排序。此方发可以被多次重载
static String toString(int[] a) 静态 返回指定数组内容的字符串表示形式。此方发可以被多次重载


使用数组操作类Arrays的使用(ArrayDemo.java)

import java.util.List;
public class ArrayDemo
{
public static void main(String args[])
{
List<String> all=Arrays.asList("Hello","World","你好","世界");
System.out.println(all);
}
}


数组操作类Arrays排序及二分查找方法的使用

import java.util.Arrays;
import java.util.Scanner;
class ArraysDemo
{
    public static void main(String args[])
    {
        int arrInt[]={17,40,12,6,15,16,8,10,18,50};
        //升序排序数组
        Arrays.sort(arrInt);
        Scanner scan =new Scanner(System.in);
        System.out.println("请输入需要查找的整数:");
        //获取输入整数
        int search=scan.nextInt();
        //输出排序后的数组
        for(int i=0;i<arrInt.length;i++)
        {
            //System.out.println(arrInt(i)+ " ");
        }
        //利用二分法查找指定整数
        int seaInt=Arrays.binarySearch(arrInt,search);
        if(seaInt>=0)
        {
            System.out.println(search+" 是数组得第 "+(seaInt+1)+" 位元素");
        }
        else
        {
            System.out.println(search +"不是数组得元素");
        }
        scan.close();   //关闭输入流
    }
}


比较器

需要为多个对象排序时必须设置排序规则,而排序规则就可以通过比较器进行设置,Java中比较器提供了两种:Comparable和Comparator

Comparable接口
Comparable是一个要进行多个对象比较的类需要默认实现的一个接口,这个接口定义如下:
public interface Comparable<T>
{public int comparableTo(T o)};//T是对象类型,o是对象类型所定义得对象
从接口定义的格式来看,可以发现要想实现对象得排序功能,要实现Comparable接口,并覆写comparable(T o)方法。此方法返回得是一个int类型数据,该返回值只能有以下三种情况之一
1,相等:0;
2,大于:1;
3,小于:-1;

上一篇下一篇

猜你喜欢

热点阅读