`
xyheqhd888
  • 浏览: 403574 次
  • 性别: Icon_minigender_1
  • 来自: 秦皇岛
社区版块
存档分类
最新评论

Java的对象容器

阅读更多

一  Collection类:

     Collection结构可持有各自独立的对象。在J2SE中,Collection包括了List与Set,List是实现java.util.List接口的相关类,可依对象被放置至容器中的顺序来排列对象。Set是实现java.util.Set接口的相关类,不接受重复的对象,并可拥有一套排序规则。

1.  List接口简介:

     (1) List接口是java.util.Colleciton接口的子接口,而Collection接口则是java.lang.Iterable的子接口。Iterable接口要求实现一个iterator()方法。

    

package java.lang;
import java.util.Iterator;
public interface Iterable<T>
{
     Iterator<T> iterator();
}

     从J2SE 5.0开始增加了泛型设计的新功能,所以像Iterable、Collection相关接口与其实现类,都使用泛型的功能重新改写了

     (2) Iterable接口要求实现它的类返回一个实现java.util.Iterator接口的对象,事实上在J2SE的API中找不到任何实现Iterator的类,因为Iterator会根据实际的容器数据结构来迭代元素,而容器的数据结构实现方式对外界是隐藏的,使用者不用知道这个结构,只需要知道Iterator的实现方法,就可以取出元素。Iterator接口的定义如下:

package java.util;
public interface Iterator<E>
{
    boolean hasNext();
    E next();
    void remove();
}

     Collection接口继承了Iterator接口,定义了加入元素、删除元素、元素长度等方法。如下代码(从JDK安装目录下src.zip中找出来的。)

  

package java.util;

public interface Collection<E> extends Iterable<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    <T> T[] toArray(T[] a);
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);
    void clear();
    boolean equals(Object o);
    int hashCode();
}

   Collection在删除元素及取得元素上的定义比较通用,List接口则又增加了根据索引取得对象的方法,这说明了List数据结构的特性,每个加入List中的元素是循序加入的,并可指定索引来存取元素。   

package java.util;
public interface List<E> extends Collection<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    <T> T[] toArray(T[] a);
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    boolean addAll(int index, Collection<? extends E> c);
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);
    void clear();
    boolean equals(Object o);
    int hashCode();
    E get(int index);
    E set(int index, E element);
    void add(int index, E element);
    E remove(int index);
    int indexOf(Object o);
    int lastIndexOf(Object o);
    ListIterator<E> listIterator();
    ListIterator<E> listIterator(int index);
    List<E> subList(int fromIndex, int toIndex);
}

   List可以使用数组(Array)或是链接串行(Linked List)来实现这个特性,前者在J2SE中的实现就是java.util.ArrayList,后者就是java.util.LinkedList。对于循序加入与存取,使用ArrayList的效率比较好,对于经常变动元素排列顺序的需求,使用LinkedList会比较好

(3)ArrayList: ArrayList实现了List接口,使用数组结构实现List数据结构。数组的特性是可以利用索引来快速指定对象的位置,所以对于快速的随机取得对象来说,使用ArrayList可以得到较好的效率。但由于使用数组实现,若要从中间作删除或插入对象的动作,会需要移动后段的数组元素以重新调整索引顺序,所以速度上会慢得多。下面是一个利用ArrayList的例子:

package onlyfun.caterpillar;

import java.util.*;

public class ArrayListDemo
{
	public static void main(String[] args)
	{
		Scanner scanner = new Scanner(System.in);
		List<String> list = new ArrayList<String>();
		System.out.println("输入名称(使用quit结束)");
		while(true)
		{
			System.out.print("# ");
			String input = scanner.next();
			if(input.equals("quit"))
				break;
			list.add(input);
		}
		System.out.print("显示输入");
		for(int i=0;i<list.size();i++)
		{
			System.out.print(list.get(i)+" ");
		}
		System.out.println();
	}
};

在J2SE 5.0之后新增了泛型功能,使用对象容器时可以声称将存储的对象类型。这样,对象在存入容器时会被限定为所声称的类型。编译器在编译时将协助进行类型检查,而取出对象时也不至于失去原来的类型信息,这可以避免类型转换时的问题。使用toArray()方法可以将ArrayList中的对象转换为对象数组,size()方法可以返回当前的ArrayList长度,add()方法可以将一个对象加入ArrayList中,get()方法可以返回指定索引处的对象。但如果您的目的是要循序取出容器中的所有对象,则建议使用Iterator。Iterator类的使用是Iterator模式的一个实例。下面使用Iterator的功能改写上面的程序:

package onlyfun.caterpillar;

import java.util.*;

public class IteratorDemo
{
	public static void main(String[] args)
	{
		Scanner scanner = new Scanner(System.in);
		List<String> list = new ArrayList<String>();
		System.out.println("输入名称(使用quit结束)");
		while(true)
		{
			System.out.print("# ");
			String input = scanner.next();
			if(input.equals("quit"))
				break;
			list.add(input);
		}
		System.out.print("显示输入");
		
        //使用Iterator取得元素
		Iterator iterator = list.iterator();
		while(iterator.hasNext())
		{
			System.out.print(iterator.next() + " ");
		}

		System.out.println();
	}
};

 iterator()方法会返回一个Iterator对象,这个对象提供遍访容器元素的方法。hasNext()方法测试Iterator中是否还有对象,如果有,可以使用next()方法取出。J2SE的API中没有实现Iterator的类,本例中Iterator的实例是在ArrayList中根据数组的数据结构而实现的。

    (4) LinkedList:List默认是以对象加入(Add)容器的顺序来排列它们,List上的add()方法也可以指定位置插入对象。如果对象加入之后是为了取出,而不会常作删除或插入的动作,则用ArrayList效率会比较好。如果经常从容器中作插入或删除的动作,则用java.util.LinkedList会获得较好的效率。由于使用LinkedList使用链表,在进行插入或删除动作时有较好的效果,适合用来实现堆栈(Stack)与队列(Queue)。下面是利用LinkedList实现的一个先进先出的队列实例,当然也可以利用LinkedList来实现一个先进后出的堆栈类。

package onlyfun.caterpillar;

import java.util.*;

public class StringQueue
{
	private LinkedList<String> linkedList;

	public StringQueue()
	{
		linkedList = new LinkedList<String>();
	}

	public void put(String name)
	{
		linkedList.addFirst(name);
	}

	public String get()
	{
		return linkedList.removeLast();
	}

	public boolean isEmpty()
	{
		return linkedList.isEmpty();
	}
}

   使用StringQueue类的示例如下:

  

package onlyfun.caterpillar;

import java.util.Scanner;

public class StringQueueDemo
{
	public static void main(String[] args) 
	{
		Scanner scanner = new Scanner(System.in);

		StringQueue queue = new StringQueue();

		System.out.println("输入名称(使用quit结束)");
		while(true)
		{
			System.out.print("# ");
			String input = scanner.next();

			if(input.equals("quit"))
			{
				break;
			}
			queue.put(input);
		}

		System.out.print("显示输入: ");
		while(!queue.isEmpty())
		{
			System.out.print(queue.get()+" ");
		}
		System.out.println();
	}
}

 事实上,如果要使用队列的功能,也不用亲自实现。在J2SE 5.0中,LinkedList也实现了java.util.Queue接口,所以可以直接实现LinkedList的实例进行队列实现。如下:

pakcage onlyfun.caterpillar;

import java.util.*;

public class QueueDemo
{
    public static void main(String[] args)
     {
          Scanner scanner = new Scanner(System.in);
          Queue<String> queue = new LinkedList<String>();
         
          System.out.println("输入名称,使用quit结束");

          while(true)
          {
                System.out.print("# ");
                String input = scanner.next();
                if(input.equals("quit"))
                     break;
                //加入元素到队列中
                queue.offer(input);
          }
          System.out.print("显示输入");
          String element = null;
          //poll():取得并删除队列中的元素
      //队列为空时就返回null
          while((element=queue.poll())!=null)
           {
                System.out.print(element+" ");
           }
           System.out.println();
     }
}

   Queue有五个必须要实现的方法,范例中示范了offer()与poll()的实现。另外,还有element()可取得但不得删除队列第一个组件,队列为空时抛出意外。remove()取得并删除队列第一个组件。peek()可取得但不删除队列的第一个组件。 

2. HashSet:java.util.HashSet实现了java.util.Set接口,Set接口一样继承了Collection接口。List容器中的对象允许重复,但Set容器中的对象不许重复,都是唯一的。加入Set容器中的对象都必须重新定义equals()方法,用作Set中对象的唯一识别。Set容器有自己的一套排序规则。

    HashSet的排序规则是利用哈希法(Hash),所以加入HashSet容器的对象还必须重新定义hashCode()方法。HashSet根据哈希码来确定对象在容器中存储的位置,也可以根据哈希码来快速地找到容器中的对象。在定义类时最好总是重新定义equals()与hashCode()方法,以符合Java的设计规范。下面程序片段展示了如何使用HashSet。

package ysu.hxy;
import java.util.*;

public class HashSetDemo
{
	public static void main(String[] args) 
	{
		Set<String> set = new HashSet<String>();
		
		set.add("sssssssss");
		set.add("ttttttt");
		set.add("gggggggg");

		//故意加入重复的对象 
        set.add("gggggggg");

		//使用Iterator显示对象
		Iterator iterator = set.iterator();
		while(iterator.hasNext())
			System.out.print(iterator.next()+ " ");
		System.out.println();

		set.remove("gggggggg");

		for(String name:set)
		{
			System.out.print(name+" ");
		}
		System.out.println();
	}
}

 虽然故意重复加入了gggggggg字符串,但HashSet中仍只有一个gggggggg字符串对象,这是Set的特性。迭代HashSet中所有的值时,其顺序与加入容器的顺序是不一样的,迭代所有值时的顺序是HashSet排序后的顺序。如果想要在显示时按加入的顺序显示,则可以使用java.util.LinkedHashSet。LinkedHashSet是HashSet的子类,它在内部实现时使用哈希码进行排序,然而允许在迭代时行为像LinkedList.

3.TreeSet:TreeSet实现Set接口与java.util.SortedSet接口,SortedSet提供相关的方法让您有序地取出对应位置的对象,像first()、last()等方法。TreeSet是J2SE中唯一实现SortedSet接口的类,它使用红黑树结构来对加入的对象进行排序

package ysu.hxy;
import java.util.*;

public class TreeSetDemo
{
	public static void main(String[] args) 
	{
		Set<String> set = new TreeSet<String>();

		set.add("justin");
		set.add("caterpillar");
		set.add("momor");

		for(String name: set)
			 System.out.print(name+ " ");
		System.out.println();
	}
}

 输出结果是:caterpillar justin momor。TreeSet默认的排序是依字典顺序来进行的。如果对对象有自己的一套排列顺序,要定义一个实现java.util.Comparator接口的对象,要实现接口中的compare()方法, compare()方法必须返回整数值。如果对象顺序相同则返回0,返回正整数表示compare()方法中传入的第一个对象大于第二个对象,反之则返回负整数。举个实际例子,假设想要改变TreeSet依字典顺序排列加入的对象为相反的顺序,可以如下自定义一个实现Comparator接口的类。

package ysu.hxy;
import java.util.Comparator;

public class CustomComparator<T> implements Comparator<T>
{
	public int compare(T o1,T o2)
	{
		if(((T)o1).equals(o2))
			return 0;
		return ((Comparable<T>)o1).compareTo((T)o2)*-1;
	}
}

 在此自定义的Comparator中,两个对象顺序相同会返回0,而为了便于比较,Comparator传入的对象必须实现Comparable接口(例如String对象就有实现Comparable接口)。乘以-1表示以字典顺序反序进行排列。用以下代码来使用自定义的排序方式,在建构TreeSet实例时一并指定自定义的Comparator。

package ysu.hxy;
import java.util.*;

public class TreeSetDemo2
{
	public static void main(String[] args) 
	{
		//自定义Comparator
		Comparator<String> comparator = new CustomComparator<String>();
		Set<String> set = new TreeSet<String>(comparator);

		set.add("justin");
		set.add("caterpillar");
		set.add("momor");

		for(String name:set)
			System.out.print(name + " ");

		System.out.println();
	}
}

 输出结果与上面的输出结果正好相反:momor justin caterpillar。

4. EnumSet:java.util.EnumSet是J2SE 5.0后新加入的新类,可在协助建立枚举值的集合。EnumSet提供了一系列的静态方法,可以让您指定不同的集合建立方式。如下简单示例:

package ysu.hxy;
import java.util.*;

//定义枚举类型
enum FontConstant{Plain,Bold,Italic};

public class EnumSetDemo
{
	public static void main(String[] args) 
	{
		//建立枚举值集合
		EnumSet<FontConstant> enumSet = EnumSet.of(FontConstant.Plain,FontConstant.Bold);
		
		//显示集合内容
		showEnumSet(enumSet);
		//显示补集合内容
		showEnumSet(EnumSet.complementOf(enumSet));
	}

	public static void showEnumSet(EnumSet<FontConstant> enumSet)
	{
		for(FontConstant constant:enumSet)
			System.out.println(constant);
		System.out.println();
	}
}

 可以指定枚举值来加入EnumSet中,使用of()方法会返回一个体EnumSet实例,其中包括所指定的枚举值,也可以使用complementOf()指定一个EnumSet的互补集。当然也可以先建立一个空的EnumSet,然后再逐个加入枚举值,如下程序片段:

package ysu.hxy;
import java.util.*;

enum FontConstant { Plain, Bold, Italic}

public class EnumSetDemo2
{
	public static void main(String[] args) 
	{
		//建立EnumSet实例,初始内容为空
		EnumSet<FontConstant> enumSet = EnumSet.noneOf(FontConstant.class);
		//加入枚举
		enumSet.add(FontConstant.Bold);
		enumSet.add(FontConstant.Italic);

		showEnumSet(enumSet);
	}

	public static void showEnumSet(EnumSet<FontConstant> enumSet)
	{
		for(FontConstant constant : enumSet)
		{
			System.out.println(constant);
		}
		System.out.println();
	}
}

 

二 Map类:

    实现java.util.Map接口的对象会将键(Key)映射至值(Value),值指的是存入Map容器的对象。在将对象存入Map对象时,需要同时给定一个键,要取回对象时可以指定键,这样就可以取得与键对应的对象值。Map中的每一个键都是唯一的,不能有重复的键,Map拥有自己的排序机制。

1.  HashMap:java.util.HashMap实现了Map接口,HashMap在内部实现使用哈希法,让您在很短的时间内可以寻得键-值匹配。如下代码:

package ysu.hxy;
import java.util.*;

public class HashMapDemo
{
	public static void main(String[] args)
	{
		Map<String,String> map = new HashMap<String,String>();

		String key1 = "caterpillar";
		String key2 = "justin";
        
		//Map的put()方法存入时,必须同时指定键和值
		map.put(key1,"caterpillar的信息");
		map.put(key2,"justin的信息");
        //需要取回对象时,使用get()方法并指定键,返回的会是对应于键的值
		System.out.println(map.get(key1));
		System.out.println(map.get(key2));
	}
}

  程序执行结果:caterpillar的信息
                       justin的信息

        可以使用values()方法返回一个实现Collection的对象,其中包括所有的值对象。如果需要一次迭代Map中所有的对象,这会很有用。如下:

package ysu.hxy;
import java.util.*;

public class HashMapDemo2
{
	public static void main(String[] args) 
	{
		Map<String,String> map = new HashMap<String,String>();

        map.put("momor","momor的信息");
		map.put("justin","justin的信息");
		map.put("caterpillar","caterpillar的信息");

        Collection collection = map.values();
		Iterator iterator = collection.iterator();
		while(iterator.hasNext())
			System.out.println(iterator.next());
		System.out.println();

		//用增强的for循环也可以
		for(String value:map.values())
			System.out.println(value);
	}
}

 运行结果:justin的信息
                momor的信息
                 caterpillar的信息

                 

                 justin的信息
                 momor的信息
                 caterpillar的信息

    如果想按插入的顺序来排列迭代的所有对象,则可以使用java.util.LinkedHashMap,它是HashMap的子类,在使用values()所返回的Collection对象,其内含对象之顺序即为当初加入对象之顺序。可以将上面代码中的new HashMap<String,String>()改为new LinkedHashMap<String,String>()进行测试。

     2. TreeMap:java.util.TreeMap实现Map接口与java.util.SortedMap接口,SortedMap接口提供的方法让您有序地取出对应位置的对象。像firstKey(),lastKey()等方法。TreeMap是J2SE中唯一实现SortedMap接口的类,它使用红黑树结构来对加入的对象进行排序(默认是依据键值的字典顺序排序)。可以直接用TreeSet的CustomComparator类来自定义排序规则。用以下代码来测试:

package ysu.hxy;
import java.util.*;

public class TreeMapDemo2
{
	public static void main(String[] args) 
	{
		CustomComparator<String> comparator = new CustomComparator<String>();
		Map<String,String> map = new TreeMap<String,String>(comparator);

		map.put("justin","justin的信息");
		map.put("momor","momor的信息");
		map.put("caterpillar","caterpillar的信息");

        for(String value:map.values())
			System.out.println(value);
	}
}

  3.EnumMap类:java.util.EnumMap类是专为枚举类设计的Map类,方便您使用枚举类及Map对象,如下例:

package ysu.hxy;
import java.util.*;

enum Action{TURN_LEFT,TURN_RIGHT,SHOOT}

public class EnumMapDemo
{
	public static void main(String[] args) 
	{
		Map<Action,String> map = new EnumMap<Action,String>(Action.class);

		map.put(Action.TURN_LEFT,"左转");
		map.put(Action.TURN_RIGHT,"右转");
		map.put(Action.SHOOT,"射击");

		for(Action action:Action.values())
		{
			//以Action枚举为键取出值
			System.out.println(map.get(action));
		}
	}
}

 运行结果: 左转
                  右转
                  射击

     与单纯的使用HashMap的差别是,EnumMap将根据枚举的顺序来维护对象的排列顺序,如在紧挨着的上段代码中,如果将三个map.put();调换顺序,最终输出的结果都是依据枚举的顺序来排列的。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics