Java学习——对象容器

1.ArrayList

 

ArrayList类别实作了List接口,List接口是Collection接口的子接口,主要增加了根据索引取得对象的方法。

ArrayList使用数组实作List接口,所以对于快速的随机取得对象来说,使用ArrayList可以得到较好的效能,不过在移除对象或插入对象时,ArrayList就比较慢(使用 LinkedList 在这方面就好的多)。

来看看一个ArrayList的范例:

ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		List list = new ArrayList();
		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 之后新增了泛型(Generic)的功能,使用对象容器时建议容器中将储存的对象型态,如此您的对象在存入容器会被限定为您所宣告的型态,而取出时,也不至于失去原来的型态信息,可以避免型态转换时的问题。

使用add()方法可以将一个对象加入ArrayList中,使用size()方法可以传回目前的ArrayList的长度,使用get()可以传回指定索引处的对象,使用toArray()可以将ArrayList中的对象转换为对象数组。

以下是执行结果:

输入名称(quit结束)
# Justin
# caterpillar
# momor
# quit
显示输入: Justin caterpillar momor?

您可以使用get()方法指定索引值取出对象,然而如果您的目的是要循序取出容器中所有的对象,则您可以使用Iterator类,Iterator类实作 Iterator 模式,实际来看个例子:

ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		List list = new ArrayList();
		System.out.println("输入名称(quit结束)");
		while(true) {
			System.out.print("# ");
			String input = scanner.next();
			if(input.equals("quit"))
			break;
			list.add(input);
		}
		Iterator iterator = list.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
		System.out.println();
	}
}

iterator()方法会传回一个Iterator对象,这个对象提供的遍访的方法,hasNext()方法测试Iterator中是否还有对象,如果 有的话,可以使用next()取出。

事实上,在J2SE 5.0您也不必须使用iterator()了,使用增强的for循环可以直接遍访List的所有元素,例如:

ArrayListDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class ArrayListDemo {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		List list = new ArrayList();
		System.out.println("输入名称(quit结束)");
		while(true) {
			System.out.print("# ");
			String input = scanner.next();
			if(input.equals("quit"))
			break;
			list.add(input);
		}
		for(String s : list) {
			System.out.print(s + " ");
		}
		System.out.println();
	}
}

2.LinkedList

List类是以对象加入(add)容器的顺序来排列它们,如果您的对象加入之后大都是为了取出,而不会常作移除或插入(Insert)的动作,则使用ArrayList,如果您会经常从容器中作移除或插入对象的动作,则使用LinkedList会获得较好的效能。

LinkedList实作了List接口,并增加了一些移除与插入对象的特定方法,像是addFirst()、addLast()、 getFirst()、getLast()、removeFirst( )、removeLast()等等,由于在插入与移除时有较好的效能,适合拿来实作堆栈(Stack)与队列(Queue)。

以下实作一个简单的FILO(First-In, Last-Out)堆栈,可以存入字符串:

StringStack.java
package onlyfun.caterpillar;
import java.util.*;
public class StringStack {
	private LinkedList linkedList;
	public StringStack() {
		linkedList = new LinkedList();
	}
	public void push(String name) {
		linkedList.addFirst(name);
	}
	public String top() {
		return linkedList.getFirst();
	}
	public String pop() {
		return linkedList.removeFirst();
	}
	public boolean isEmpty() {
		return linkedList.isEmpty();
	}
}

而对于FIFO(First-In, First-Out)的队列,我们也可以使用LinkedList来实作:

StringQueue.java
package onlyfun.caterpillar;
import java.util.*;
public class StringQueue {
	private LinkedList linkedList;
	public StringQueue() {
		linkedList = new LinkedList();
	}
	public void put(String name) {
		linkedList.addFirst(name);
	}
	public String get() {
		return linkedList.removeLast();
	}
	public boolean isEmpty() {
		return linkedList.isEmpty();
	}
}

事实上,如果您要使用队列的功能,您也不用亲自实作,在J2SE 5.0中,LinkedList也实作了新加入的java.util.Queue接口,这个接口有五个必须实作的方法:

element()

取得但不移除队列第一个组件,队列为空时会丢出例外

offer()

加入一个元素至队列中

peek()

取得但不移除队列第一个组件

poll()

取得并移去队列第一个组件,队列为空时传回null

remove()

取得并移除队列第一个组件

要使用队列的功能,您只要类似这样的宣告:

Queue<String> queue = new LinkedList<String>();

3.HashSet

HashSet实作Set接口,Set接口继承Collection接口,Set容器中的对象都是唯一的,加入 Set容器中的对象都必须重新定义equals()方法,作为唯一性的识别,Set容器有自己的一套排序规则。

HashSet的排序规则是利用Hash Table,所以加入HashSet容器的对象还必须重新定义hashCode()方法,利用Hash的方式,可以让您快速的找到容器中的对象,在比较两个加入Set容器中的对象是否相同时,会先比较hashCode()方法传回的值是否相同,如果相同,则再使用equals()方法比较,如果两者都相同,则视为相同的对象。

事实上,在撰写新的类别时,最好总是重新定义equals()与hashCode()方法,以符合Java的设计规范,您可以参考 Object 类别 中的介绍了解如何重新定义equals()与hashCode()。
来看一个例子:

HashSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashSetDemo {
	public static void main(String[] args) {
		Set set = new HashSet();
		set.add("caterpillar");
		set.add("justin");
		set.add("momor");
		set.add("justin");
		Iterator iterator = set.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
		System.out.println();
	}
}

执行结果:

momor  justin caterpillar

如上所示的,即使重复加入了"justin"字符串,HashSet中仍只有一个"justin"字符串对象,另一个要注意的是,选代所有的值时,其顺序 与您加入的顺序是不一样的,选代所有值时的顺序是HashSet排序过后的顺序。

LinkedHashSet是HashSet的子类,它在内部实作使用Hash Code进行排序,然而允许您在列举时行为像是LinkedList,简单的改写上面的程序即可了解:

LinkedHashSetDemo.java
package onlyfun.caterpillar;

import java.util.*;

public class LinkedHashSetDemo {
public static void main(String[] args) {
Set set = new LinkedHashSet();

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

Iterator iterator = set.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}

System.out.println();
}
}

执行结果:

caterpillar  justin momor

可以在执行结果中看到的,选代时的顺序正是您加入值的顺序。

4.TreeSet

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

看个简单的例子:

TreeSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeSetDemo {
	public static void main(String[] args) {
		Set set = new TreeSet();
		set.add("justin");
		set.add("caterpillar");
		set.add("momor");
		set.add("justin");
		Iterator iterator = set.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
		System.out.println();
	}
}

由于加入的是String对象,执行结果会自动依字典顺序进行排序的动作:

caterpillar  justin momor

依字典顺序排序String对象是TreeSet预设的,如果您对对象有自己的一套排序顺序,您要实作一个 Comparator 对象,您要实作compare()方法,它必须传回整数值,如果对象顺序相同则传回0,传回正整数表示compare()方法的第一个对象大于第二个对象,反之则传回负整数。

举个实际的例子,假设您想要改变TreeSet依字典顺序排列加入的对象为相反的顺序:

CustomComparator.java
package onlyfun.caterpillar;
import java.util.Comparator;
public class CustomComparator implements Comparator {
	public int compare(T o1, T o2) {
		if (((T) o1).equals(o2))
		return 0;
		return ((Comparable) o1).compareTo((T) o2) * -1;
	}
}

在自订的Comparator中,如果两个对象的顺序相同会传回0,这在TreeSet中表示两个对象是同一个对象,TreeSet要求传入的对象必须实 作java.lang.Comparable接口,范例中只是简单的将原来compareTo()传回的值乘以负一,如此在TreeSet中就可以简单的 让排列顺序相反。

在建构TreeSet实例时一并指定自订的Comparator,例如:

TreeSetDemo2.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeSetDemo2 {
	public static void main(String[] args) {
		// 自订Comparator
		Comparator comparator =
		new CustomComparator();
		Set set =
		new TreeSet(comparator);
		set.add("justin");
		set.add("caterpillar");
		set.add("momor");
		// 使用 enhanced for loop 显示对象
		for(String name : set) {
			System.out.print(name + " ");
		}
		System.out.println();
	}
}

执行的结果是相反的:

momor justin  caterpillar

5.EnumSet

EnumSet的名称说明了其作用,它是在J2SE 5.0后加入的新类别,可以协助您建立列举值的集合,它提供了一系列的静态方法,可以让您指定不同的集合建立方式,例如:

EnumSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
enum FontConstant { Plain, Bold, Italic }
public class EnumSetDemo {
	public static void main(String[] args) {
		EnumSet enumSet =
		EnumSet.of(FontConstant.Plain, FontConstant.Bold);
		showEnumSet(enumSet);
		showEnumSet(EnumSet.complementOf(enumSet));
	}
	public static void showEnumSet(
	EnumSet enumSet) {
		Iterator iterator = enumSet.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
		System.out.println();
	}
}

您可以指定列举值来加入EnumSet中,of()方法会返回一个EnumSet的实例,当中包括您所指定的列举值,您也可以使complementOf()指定一个EnumSet的互补集,以下是执行的结果:

Plain Bold 
Italic?

EnumSet实作了Set接口,所以您可以使用Set接口的所有方法来测试它所包括的列举值,例如测试一个集合中是否包括 FontConstant.Bold:

if(enumSet.contains(FontConstant.Bold)) {
	....
}

您也可以建立一个空的EnumSet,然后自己逐个加入列举值,例如:

EnumSetDemo.java
package onlyfun.caterpillar;
import java.util.*;
enum FontConstant { Plain, Bold, Italic }
public class EnumSetDemo {
	public static void main(String[] args) {
		EnumSet enumSet =
		EnumSet.noneOf(FontConstant.class);
		enumSet.add(FontConstant.Bold);
		enumSet.add(FontConstant.Italic);
		showEnumSet(enumSet);
	}
	public static void showEnumSet(
	EnumSet enumSet) {
		Iterator iterator = enumSet.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
		System.out.println();
	}
}

执行结果:

Bold Italic

您也可以由一个容器对象中建立EnumSet:

List list = new ArrayList();
list.add(FontConstant.Bold);
list.add(FontConstant.Italic);

showEnumSet(EnumSet.copyOf(list));

更多EnumSet相关的方法,您可以参考 EnumSet 在线API文件。

6.HashMap

 

HashMap实作Map接口,内部实作使用Hash Table,让您在常数时间内可以寻得key/value对。

所谓的key/value对,简单的说,您将Map容器对象当作一个有很多间房间的房子,每个房间的门有一把钥匙,您将对象储存至房间中时,要顺便拥有一把钥匙,下次要取回对象时,就是根据这把钥匙取得。

以一个简单的例子来作说明:

HashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashMapDemo {
	public static void main(String[] args) {
		Map< String, String> map =
		new HashMap< String, String>();
		map.put("caterpillar", "caterpillar's message!!");
		map.put("justin", "justin's message!!");
		System.out.println(map.get("justin"));
		System.out.println(map.get("caterpillar"));
	}
}

在宣告Map型态时,您指定了key/value各自的型态,这边都是宣告为String,也就是以String对象作为key对象的型态,而 value也是以String对象作为其型态。

使用Map的put()方法将对象存入,必须同时指定key/value,而要取回对象时,则指定key,程序的执行结果如下:

justin's message!!
caterpillar's message!!

HashMap是个被经常使用的对象,您可以参考下面几个例子中HashMap的应用:

  • Command 模式
  • Thread-Specific Storage 模式
  • 控 制器(Servlet)

可以使用values()方法返回一个Collection对象,如果您需要一次选代Map中所有的对象,这会很有用,例如:

HashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class HashMapDemo {
	public static void main(String[] args) {
		Map< String, String> map =
		new HashMap< String, String>();
		map.put("justin", "justin's message!!");
		map.put("momor", "momor's message!!");
		map.put("caterpillar", "caterpillar's message!!");
		Collection collection = map.values();
		Iterator iterator = collection.iterator();
		while(iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

执行结果:

momor's message!!
justin's message!!
caterpillar's message!!

HashMap使用Hash Table,因而它有自己的排序方式,如果您想要在选代所有的对象时,依照插入的顺序来排序,则可以使用LinkedHashMap,它是HashMap 的子类,使用values()所返回的Collection对象,其内含对象之顺序即为当初您加入对象之顺序,例如:

LinkedHashMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class LinkedHashMapDemo {
	public static void main(String[] args) {
		Map< String, String> map =
		new LinkedHashMap< String, String>();
		map.put("justin", "justin's message!!");
		map.put("momor", "momor's message!!");
		map.put("caterpillar", "caterpillar's message!!");
		Collection collection = map.values();
		Iterator iterator = collection.iterator();
		while(iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

执行结果:

justin's message!!
momor's message!!
caterpillar's message!!

7.TreeMap

TreeMap实作Map接口与SortedMap接口,提供相关的方法让您有序的取出对应位置的对象,像是 firstKey()、lastKey()等方法,TreeMap是J2SE中唯一实作SortedMap接口的类别,它使用红黑树结构来对加入的对象进 行排序

看个简单的例子:

TreeMapDemo.java
package onlyfun.caterpillar;
import java.util.*;
public class TreeMapDemo {
	public static void main(String[] args) {
		Map< String, String> map =
		new TreeMap< String, String>();
		map.put("justin", "justin's message!!");
		map.put("momor", "momor's message!!");
		map.put("caterpillar", "caterpillar's message!!");
		Collection collection = map.values();
		Iterator iterator = collection.iterator();
		while(iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

由于您加入的是String对象,执行结果会自动依key的字典顺序进行排序的动作:

caterpillar's message!!
justin's message!!
momor's message!!

依字典顺序排序String对象是TreeMap预设的,如果您对对象有自己的一套排序顺序,您要实作一个 Comparator 对象,它有两个必须实作的方法,compare()与equals(),前者必须传回整数值,如果对象顺序相同则传回0,传回正整数表示compare ()方法的第一个对象大于第二个对象,反之则传回负整数,后者则是定义两个对象是否相等。

8、EnumMap

EnumMap是个专为列举型别设计的类别,方便您使用列举型别及Map对象,直接来举个实例:

EnumMapDemo.java
package onlyfun.caterpillar;
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( ) ) {
			System.out.println(map.get(action));
		}
	}
}

执行结果:

向左转
向右转
射击

与单纯的使用HashMap比较起来的差别是,在上面的程序中,EnumMap将根据列举的顺序来维护对象的排列顺序,从下面这个程序可以看个大概:

EnumMapDemo2.java
package onlyfun.caterpillar;
import java.util.*;
enum Action {TURN_LEFT, TURN_RIGHT, SHOOT}
public class EnumMapDemo2 {
	public static void main(String[] args) {
		Map< Action, String> map =
		new EnumMap< Action, String>(Action.class);
		map.put(Action.SHOOT, "射击");?
		map.put(Action.TURN_RIGHT, "向右转");
		map.put(Action.TURN_LEFT, "向左转");
		for(String value : map.values( )) {
			System.out.println(value);
		}
	}
}

执行结果:

向左转
向右转
射击

从遍访的结果可以看出,对象的顺序是根据列举顺序来排列的

 


本文转自ZH奶酪博客园博客,原文链接:http://www.cnblogs.com/CheeseZH/archive/2012/12/05/2803908.html,如需转载请自行联系原作者

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值