博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Java编程思想》笔记08------持有对象
阅读量:6264 次
发布时间:2019-06-22

本文共 20931 字,大约阅读时间需要 69 分钟。

如果一个程序包含固定数量的且其生命周期都是已知的对象,那么这是一个非常简单的程序。然而事与愿违,通常情况下,程序在运行之前并不知道对象的数量,甚至不知道对象的类型。因此,需要引入一项新的技术,可以在任意时刻和任意位置创建任意数量的对象。 Java类库提供了一套相当完整的容器类来解决这个问题,其中基本的类型包括:List、Set、Map等,这些对象的类型也称为集合类。不同的容器有不同的特性,但它们的共性就是:都可以自动的调整自身的大小。因此,与数组不同,在编程时我们可以将任意数量的对象放置在容器中。

一、泛型与类型安全的容器

为了便于理解下面的这个例子,首先介绍一个简单容器 ArrayList,我们可以把ArrayList当做是一个可以自动扩充自身大小的数组。

我们可以通过add()方法插入对象,可以通过get()方法访问对象,还可以通过size()方法来获取当前容器的大小。


在Java SE5之前的版本,编译器允许向容器中插入不正确的类型。

例如:要创建一个ArrayList用于放置Apple对象。如果把Orange对象也放入容器中,编译器是不会报错的。

/** * 泛型的使用 * @author LiangYu * 2018-01-11 */public class GenericityTest {	@Test	public void test() throws Exception {		ArrayList apples = new ArrayList();		for(int i = 0 ; i < 4 ; i++){			Apple apple = new Apple();			apple.setId(i);			apples.add(apple);		}		//新来的同事手误,将Orange对象也放入了apples容器中		Orange orange = new Orange();		//编译器并没有报错		apples.add(orange);		//遍历容器的时候,悲剧了。。		for(int i = 0 ; i < apples.size() ; i++){			Apple apple = (Apple) apples.get(i);			System.out.println(apple.getId());		}	}}class Apple{	private int id;	public void setId(int id){		this.id = id;	}	public int getId(){		return id;	}}class Orange{}复制代码

上面的例子可以看到,当我们把Orange对象放入盛有Apple对象的容器中的时候,编译器并没有报错,而是在运行的时候,发现问题,并抛出异常。

为了将类似的错误扼杀在摇篮中,我们可以声明ArrayList<Apple>,用于告诉编译器:这个容器只能盛放Apple对象,如果有人错把其他对象放入容器,那么请编译器报错提示。

@Testpublic void test() throws Exception {	ArrayList
apples = new ArrayList
(); for(int i = 0 ; i < 4 ; i++){ Apple apple = new Apple(); apple.setId(i); apples.add(apple); } //新来的同事手误,准备将Orange对象也放入了apples容器中 Orange orange = new Orange(); //此时编译器报错,提示他不能将Orange对象放入容器中// apples.add(orange); //遍历容器,运行正常 for(int i = 0 ; i < apples.size() ; i++){ Apple apple = apples.get(i); System.out.println(apple.getId()); }}复制代码

通过泛型,编译器可以阻止Orange对象放入apples容器中,将运行时错误,变成了编译时错误

二、基本概念

Java容器类的主要用途是“保存对象”,并将其划分为两个概念:

1.Collection:一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素;Set不能有重复元素,Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。

2.Map:一组成对的“键值对”对象,允许使用键来查找值。ArrayList允许使用数字来查找值。因此,在某种意义上讲,它将数字和对象关联在一起。映射表允许我们使用另一个映射来查找某个对象,它也称为“关联数组”。因为它将某些对象和另一些对象关联在了一起。或者成为“字典”,因为可以使用键对象来查找值对象。

在创建的时候就要指定所使用的精确类型,例如:

List
texts = new ArrayList
();复制代码

使用接口的目的在于如果决定去修改你的实现,只需要在创建时修改它,例如:

List
texts = new LinkedList
();复制代码

Collection接口概括了序列的概念——————一种存放对象的方式。

例如:用Integer对象填充一个Collection,然后打印容器中所有元素。

/** * 序列的概念 * @author LiangYu * 2018-01-16 */public class CollectionTest {	@Test	public void test() throws Exception {		Collection
numbers = new ArrayList
(); for(int i = 0 ; i < 10 ; i++){ numbers.add(i); } for(int i : numbers){ System.out.println(i); } }}复制代码

add()方法的名称就比表明它要将一个新元素加入到Collection中。 所有的Collection都可以用foreach遍历。

三、添加一组元素

在java.util包下的Arrays和Collections类中的很多实用方法可以在一个Collection中添加一组元素。

Arrays.asList()方法接受一个数组或是一个用逗号分隔的元素列表(可变参数),并将其转换为一个List对象。

Collections.addAll()方法接受一个Collection对象,以及一个数组或是一个用逗号分隔的列表,将元素添加到Collection中。

/** * 添加一组元素 * @author LiangYu * 2018-01-16 */public class AddCollectionTest {	@Test	public void test() throws Exception {		//Collection的构造器可以接受另一个Collection		Collection
numbers = new ArrayList
(Arrays.asList(2,4,6,8,10)); Integer[] moreInts = {
1,3,5,7,9}; //Collection.addAll()运行起来要快很多,但是它只能接受另一个Collection作为参数,不够灵活 numbers.addAll(Arrays.asList(moreInts)); //Collections.addAll()是首选方式 Collections.addAll(numbers, 11,12,13,14); Collections.addAll(numbers, moreInts); List
numberList = Arrays.asList(15,16,17,18,19,20); numberList.set(2, 21); //通过Arrays.asList()创建的Collection对象底层依旧是数组,因此,不能调整尺寸。// numberList.add(98); 运行时报错:UnsupportedOperationException System.out.println(numbers); System.out.println(numberList); }}复制代码

总结:

  1. Collection的构造器可以接受另一个Collection
  2. Collection对象的addAll()运行起来要快很多,但是它只能接受另一个Collection作为参数,不够灵活
  3. Collections.addAll()是首选方式
  4. 通过Arrays.asList()创建的Collection对象底层依旧是数组,因此,不能调整尺寸。

Arrays.asList()方法的限制是它对所产生的List的类型做出最理想的假设,而并没有注意你会给它赋予什么类型。有时会引发问题。

四、容器的打印

必须使用Arrays.toString()方法来产生数组的可打印表示。打印容器不需要任何帮助。

eg:

/** * Collection的打印 * @author LiangYu * 2018-01-16 */public class CollectionPrintTest {	@Test	public void test() throws Exception {		System.out.println("ArrayList:"+fill(new ArrayList
())); System.out.println("LinkedList:"+fill(new LinkedList
())); System.out.println("HashSet:"+fill(new HashSet
())); System.out.println("TreeSet:"+fill(new TreeSet
())); System.out.println("LinkedHashSet:"+fill(new LinkedHashSet
())); System.out.println("HashMap:"+fill(new HashMap
())); System.out.println("TreeMap:"+fill(new TreeMap
())); System.out.println("LinkedHashMap:"+fill(new LinkedHashMap
())); } Collection fill(Collection
collection){ collection.add("dog"); collection.add("cat"); collection.add("fish"); collection.add("dog"); return collection; } Map fill(Map
map){ map.put("cat", "Apache"); map.put("dog", "Cookie"); map.put("fish", "Tom"); map.put("dog", "July"); return map; }}复制代码

结论:

1.Collection在每一个“槽”里面只能保存一个元素,此类容器包括:List(以特定的顺序保存一组元素)、Set(不能重复)、Queue(只允许容器的一端插入元素,另一端移除元素); Map在每一个“槽”里面保存两个元素,分别是元素的键和它对应的值。

2.ArrayList和LinkedList都是List类型,按照被插入的顺序保存元素。不同之处:

(1)在执行某些类型的操作时性能不同

(2)LinkedList包含的操作多于ArrayList

3.HashSet和TreeSet、LinkedHashSet都是Set类型,输出显示在Set中。每一个相同的项只能保存一次。HashSet拥有最快的获取元素方式;TreeSet按照比较结果升序保存对象;LinkedHashSet按照被添加的顺序保存对象。

4.HashMap和TreeMap、LinkedHashMap都是Map类型。Map是通过键来查找对象。对于每一个键,Map只存储一次。HashMap提供了最快的查找技术;TreeMap按照比较结果升序保存键;LinkedHashMap根据插入顺序保存键,同时保留了HashMap的查询速度。

五、List

List可以将元素维护在特定的序列中。List接口在Collection的基础上添加了大量的方法,使得可以在List中间插入和移除元素。

有两种类型的List:

  • 基本的ArrayList,随机访问元素比较快,但是在List的中间插入和移除元素时较慢。
  • LinkedList:可以用较低代价进行插入和移除操作,优化了顺序访问,在随机访问方面比较慢。
/** * ArrayList和LinkedList的使用 * @author LiangYu * 2018-01-16 */public class ListTest {	@Test	public void test() throws Exception {		List
pets = new ArrayList
(Arrays.asList(new Pet(),new Dog(),new OrangeCat(),new Mouse(),new BlueCat(),new Dog(),new WhiteMouse())); System.out.println("1:"+pets); BlueMouse blueMouse = new BlueMouse(); //添加元素 pets.add(blueMouse); System.out.println("2:"+pets); System.out.println("3:"+pets.contains(blueMouse)); //判断元素是否存在 pets.remove(blueMouse); //移除元素 Pet p = pets.get(2); //根据索引获取元素 System.out.println("4:"+p+" "+pets.indexOf(p)); //获取元素的索引 Pet orangeCat = new OrangeCat(); System.out.println("5:"+pets.indexOf(orangeCat)); //如果元素不存在,索引返回-1 System.out.println("6:"+pets.remove(orangeCat)); //如果元素不存在,remove方法返回false System.out.println("7:"+pets.remove(p)); //移除元素成功,remove方法返回true System.out.println("8:"+pets); pets.add(1,new Mouse()); //在指定位置添加对象 System.out.println("9:"+pets); List
sub = pets.subList(1, 5); //截取集合 System.out.println("subList:"+sub); System.out.println("10:"+pets.containsAll(sub)); //判断某集合是不是该集合的子集 Collections.shuffle(sub,new Random(47)); //打乱排序 System.out.println("shuffle:"+sub); List
petsCopy = new ArrayList
(pets); //拷贝一个元素内容相同的容器 sub = Arrays.asList(pets.get(2),pets.get(4)); System.out.println("sub:"+sub); petsCopy.retainAll(sub); // 获取两个集合的交集部分 System.out.println("11:"+petsCopy); petsCopy = new ArrayList
(pets); petsCopy.remove(2); System.out.println("12:"+petsCopy); petsCopy.removeAll(sub); //移除和sub交集的部分 System.out.println("13:"+petsCopy); petsCopy.set(1, new BlackMouse()); //将指定位置的元素进行修改 System.out.println("14:"+petsCopy); petsCopy.addAll(2,sub); //在指定位置插入集合 System.out.println("15:"+petsCopy); System.out.println("16:"+pets.isEmpty()); //isEmpty方法判断集合是否为空 pets.clear(); //清空集合 System.out.println("17:"+pets); System.out.println("18:"+pets.isEmpty()); Object[] objects = petsCopy.toArray(); //list转换为数组 System.out.println("19:"+objects[2]); }}class Pet{ @Override //打印时输出类名 public String toString() { return getClass().getSimpleName(); }}class Cat extends Pet{}class OrangeCat extends Cat{}class BlueCat extends Cat{}class Dog extends Pet{}class Mutt extends Dog{}class Pug extends Dog{}class SmallOrangeCat extends OrangeCat{}class Mouse extends Pet{}class WhiteMouse extends Mouse{}class BlackMouse extends Mouse{}class BlueMouse extends Mouse{}复制代码

结论:

  1. List允许在它被创建以后添加元素、移除元素,或者自我调节尺寸
  2. contains()方法用于判断某个对象是否存在于容器中
  3. remove()移除、add()添加
  4. 通过indexOf()方法用于获取指定元素的索引
  5. subList()可以获取列表的片段
  6. removeAll(List list) 从List中移除参数List中的所有元素
  7. retainAll(List list) 获取交集
  8. set(int index,Object object) 将指定位置的元素替换
  9. isEmpty() 判断列表是否为空; clear() 清空列表

六、迭代器

任何容器类都必须有某种方式可以插入元素并将它们再次取回。对于List而言,add()是插入元素的方法之一,get()是取出元素的方法之一。

如果原本对着List编码,但是后来发现能够把相同的代码应用于Set,此时如果代码使用了add()和get()将会影响可移植性。

迭代器的概念则可以用于达成此目的。迭代器是一个对象,它的工作是遍历并选择序列中的对象。开发者不需要关注该序列底层的结构。无论是List还是Set都可以直接使用迭代器。此外,迭代器是轻量级对象,创建它的代价非常小。因此,它的功能受到了一定的限制。

  1. 迭代器只能单向移动
  2. 通过iterator()要求容器返回一次Iterator对象。Iterator将准备好返回序列的第一个元素。
  3. 使用next()方法可以获取序列中的下一个元素
  4. 使用hasNext()判断序列中是否还有元素
  5. 使用remove() 将迭代器新近返回的元素删除
/** * 迭代器的使用 * @author LiangYu * 2018-01-16 */public class IteratorTest {	@Test	public void test() throws Exception {		List
numbers = new ArrayList
(Arrays.asList(0,1,2,3,4,5,6,7,8,9)); //获取迭代器 Iterator
iterator = numbers.iterator(); //迭代 while(iterator.hasNext()){ int num = iterator.next(); System.out.print(num); } System.out.println(); for(int i : numbers){ System.out.print(i); } System.out.println(); //重置迭代器 iterator = numbers.iterator(); for(int i = 0 ; i < 4 ; i++){ iterator.next(); iterator.remove(); } System.out.print(numbers); }}复制代码

有了迭代器,我们就不需要关心容器中元素的数量。那是hasNext()和next()关心的事。

Iterator中,remove()方法可以移除next()产生的最后一个元素,因此,调用remove()之前,首先需要调用next()

如果只是遍历List,而不修改List本身,那么foreach语法更简洁。

例:创建一个display方法,用于遍历所有内容,而不需要关注容器的确切类型

/** * 通过迭代器展示所有元素 * @author LiangYu * 2018-01-16 */public class DisplayCollectionTest {	@Test	public void test() throws Exception {		ArrayList
textList = new ArrayList
( Arrays.asList("Qwe","ert","yui","opasdf","ghj","kl","zx","Qwe","xcvb")); LinkedList
textLinkedList = new LinkedList
(textList); TreeSet
textTreeSet = new TreeSet
(textList); HashSet
textHashSet = new HashSet
(textList); DisplayUtil.display(textList.iterator()); DisplayUtil.display(textLinkedList.iterator()); DisplayUtil.display(textTreeSet.iterator()); DisplayUtil.display(textHashSet.iterator()); }}class DisplayUtil{ //通用方法,可以在不考虑容器类型的前提下,遍历展示所有元素 static void display(Iterator
texts){ while(texts.hasNext()){ String msg = texts.next(); System.out.print(msg+" "); } System.out.println(); }}复制代码

Iterator可以将遍历序列的操作与序列底层的结构分离。

ListIterator

ListIterator是Iterator的子类型,只能用于List类的访问。ListIterator可以双向移动。它还可以产生相对于迭代器在列表中指向当前位置的前一个元素和后一个元素的索引。并且可以使用set()方法替换它访问过的最后一个元素。同时,还可以调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素。

/** * ListIterator的使用 * @author LiangYu * 2018-01-16 */public class ListIteratorTest {	@Test	public void test() throws Exception {		List
numbers = new ArrayList
( Arrays.asList(1,3,5,7,9,11,13,15,17,19,21,23,25,27,29)); //创建一个ListIterator ListIterator
listIterator = numbers.listIterator(); //获取元素为17的前一个元素索引和后一个元素索引 while(listIterator.hasNext()){ System.out.print(listIterator.next()+","+listIterator.previousIndex()+","+listIterator.nextIndex()); System.out.println(); } //创建一个ListIterator,并且,从第10个索引开始 listIterator = numbers.listIterator(10); //反向遍历 while(listIterator.hasPrevious()){ System.out.print(listIterator.previous()+" "); } System.out.println(); //修改元素的值 listIterator = numbers.listIterator(); while(listIterator.hasNext()){ listIterator.set(listIterator.next()-1); } System.out.println(numbers); }}复制代码

七、LinkedList

LinkedList也像ArrayList一样,实现了基本的List接口。但是它在执行插入和移除时,比ArrayList高效。

LinkedList还添加了可以使其用作栈、队列、双端队列的方法。这些方法中有些彼此之间只是名字不同或者只存在些许差异。例如:

getFirst()方法和element()方法完全一样,返回列表的第一个元素,而并不移除它,如果List为空,则抛异常。

peek()方法也是获取列表的第一个元素,如果List为空,则返回null。

removeFirst()和remove()完全一样。它们移除并返回列表的头,而在List为空时抛出异常。

poll()方法也是移除并返回头,如果List为空,则返回null。

addFirst()\add()\addLast() 都是在指定位置插入元素。

removeLast() 移除并返回最后一个元素。

/** * LinkedList的使用 * @author LiangYu * 2018-01-16 */public class LinkedListTest {	@Test	public void test() throws Exception {		LinkedList
texts = new LinkedList
(Arrays.asList("A","B","C","D","E","F","G","H")); System.out.println(texts); //获取列表的第一个元素 System.out.println("texts.getFirst()--->"+texts.getFirst()); System.out.println("texts.element()--->"+texts.element()); System.out.println("texts.peek()--->"+texts.peek()); //获取并移除列表的第一个元素 System.out.println("texts.remove()--->"+texts.remove()); System.out.println("texts.removeFirst()--->"+texts.removeFirst()); System.out.println("texts.poll()--->"+texts.poll()); //添加元素 texts.offer("I"); System.out.println("texts.offer()--->"+texts); texts.addFirst("J"); System.out.println("texts.addFirst()--->"+texts); texts.add("K"); System.out.println("texts.add()--->"+texts); texts.removeLast(); System.out.println("texts.removeLast()--->"+texts); }}复制代码

八、Stack

栈:后进先出。最后一个进栈的元素第一个出来。

LinkedList具备直接实现栈功能的所有方法。不过,为了能够看清楚栈的功能,在这里创建一个Stack类:

/** * 栈 * @author LiangYu * 2018-01-16 */public class StackTest {	@Test	public void test() throws Exception {		Stack
texts = new Stack
(); texts.push("A"); texts.push("B"); texts.push("C"); while(!texts.isEmpty()){ System.out.print(texts.pop()); } System.out.println(); }}class Stack
{ private LinkedList
storage = new LinkedList
(); //添加数据到栈顶 public void push(T v){ storage.addFirst(v); } //获取栈顶的元素 public T peek(){ return storage.getFirst(); } //移除栈顶 public T pop(){ return storage.removeFirst(); } //判断是否为空 public boolean isEmpty(){ return storage.isEmpty(); } //重载toString @Override public String toString() { return storage.toString(); }}复制代码

九、Set

Set不保存重复的元素,如果试图将相同元素的多个实例添加到Set中,那么它会阻止这种重复现象。Set最常被使用的是测试归属性,你可以轻易的询问某个对象是否在Set中,对于Set而言,查找是最重要的操作。

Set和Collection一样的接口,没有任何额外的功能,其实Set就是Collection,只是行为不同。Set是基于对象值来确定归属性。

/** * Set的使用 * @author LiangYu * 2018-01-16 */public class SetTest {	@Test	public void test() throws Exception {		Random random = new Random(47);		Set
numbers = new HashSet
(); for(int i = 0 ; i < 10000;i++){ numbers.add(random.nextInt(20)); } System.out.println(numbers); }}复制代码

输出的顺序是从0~29。(Java8版本之后,HashSet的底层使用算法已经作了修改。后面会专门写几篇关于utils包下一些类的源码解析,此处不再赘述

十、Map

用于将对象映射到其他对象。

例如:检查Random的随机性。(键为随机数,值为该数字出现的次数)

/** * 使用Map容器检查Random * @author LiangYu * 2018-01-16 */public class RandomTest {	@Test	public void test() throws Exception {		Random random = new Random(47);		Map
randomMap = new HashMap
(); for(int i = 0 ; i < 40000 ; i++){ int r = random.nextInt(20); Integer value = randomMap.get(r); randomMap.put(r, value==null?1:value+1); } System.out.println(randomMap); }}复制代码

结论:

1.get(Object key) 通过键获取值

2.put(Object key,Object value) 插入数据

eg:创建一个Map容器,键:宠物名称(String),值:宠物类型(Pet)

/** * 创建一个Map容器,键:宠物名称(String),值:宠物类型(Pet) * @author LiangYu * 2018-01-16 */public class PetMapTest {	@Test	public void test() throws Exception {		Map
petMap = new HashMap
(); petMap.put("Apache",new Cat()); petMap.put("Cookie", new Dog()); petMap.put("Jerry", new Mouse()); System.out.println(petMap); System.out.println(petMap.get("Cookie")); System.out.println(petMap.containsKey("Apache")); System.out.println(petMap.containsValue(new Mouse())); System.out.println(petMap.containsValue(petMap.get("Jerry"))); }}复制代码

Map甚至可以是多维的。 例如:创建一个容器,键为Person对象,值为Pet的List容器,代表一个人拥有多个宠物。

/** * 一个人拥有多个宠物的情况 * @author LiangYu * 2018-01-16 */public class PersonPetListTest {	@Test	public void test() throws Exception {		Map
> personPetListMap = new HashMap
>(); personPetListMap.put(new Person(0,"KosmoLeung"),Arrays.asList(new Dog(),new Cat())); personPetListMap.put(new Person(1,"AirSu"),Arrays.asList(new BlackMouse(),new BlueCat())); personPetListMap.put(new Person(2,"LindaWu"), Arrays.asList(new BlueMouse(),new WhiteMouse())); System.out.println("People:"+personPetListMap.keySet()); System.out.println("Pets:"+personPetListMap.values()); //遍历Map(同时需要key和value时) for(Map.Entry
> entry : personPetListMap.entrySet()){ System.out.println(entry.getKey()+"---"+entry.getValue()); } //遍历Map(仅需要输出key或value二者之一) for(Person person : personPetListMap.keySet()){ System.out.println(person); } for(List
petValue : personPetListMap.values()){ System.out.println(petValue); } //遍历Map(可以遍历的同时删除某个元素,用remove方法) Iterator
>> iterator = personPetListMap.entrySet().iterator(); while(iterator.hasNext()){ Map.Entry
> entry = iterator.next(); System.out.println(entry.getKey()+"---"+entry.getValue()); } }}复制代码

十一、Queue

队列:先进先出。从容器的一端放入数据,另一端取出数据。

队列在并发编程中非常重要。(以后写)

LinkedList提供了方法以支持队列的行为。并且它实现了Queue接口。因此LinkedList可以用作Queue的实现。通过将LinkedList向上转型为Queue。

eg:

/** * 队列的使用 * @author LiangYu * 2018-01-16 */public class QueueTest {	void printQueue(Queue queue){		while(queue.peek() != null){			System.out.print(queue.remove()+" ");		}		System.out.println();	}		@Test	public void test() throws Exception {		Queue
queue = new LinkedList
(); Random random = new Random(47); for(int i = 0 ; i < 10 ; i++){ queue.offer(random.nextInt(i+10)); } printQueue(queue); Queue
text = new LinkedList
(); for(char c : "Hello World!".toCharArray()){ text.offer(c); } printQueue(text); }}复制代码

结论:

  1. 添加元素 : offer()
  2. 获取第一个元素:peek() element()
  3. 删除元素: poll() remove()

PriorityQueue 优先级队列

对象会在容器内部被排序,默认的排序是队列的自然排序,也可以通过提供自己的Comparator来修改这个顺序。

/** * 优先级队列 * @author LiangYu * 2018-01-16 */public class PriorityQueueTest {	@Test	public void test() throws Exception {		PriorityQueue
pStrings = new PriorityQueue
(); for(char c : "Hello World!".toCharArray()){ pStrings.add(c); } printPriorityQueue(pStrings); } void printPriorityQueue(PriorityQueue
pStrings){ while(pStrings.peek() != null){ System.out.print(pStrings.remove()+" "); } System.out.println(); }}复制代码

十二、Collection和Iterator

/** * Collection与Iterator * @author LiangYu * 2018-01-16 */public class CollectionVSIteratorTest {	void display(Iterator
it){ while(it.hasNext()){ Student student = it.next(); System.out.println(student); } System.out.println("*************************************"); } void display(Collection
students){ for(Student student : students){ System.out.println(student); } System.out.println("*************************************"); } @Test public void test() throws Exception { List
students = new ArrayList
(Arrays.asList( new Student(1, "KosmoLeung"), new Student(2, "AirSu"), new Student(3, "LindaWu"), new Student(4, "NancyLee"))); Set
studentSet = new HashSet
(students); Map
studentMap = new LinkedHashMap
(); String[] ids = "s001,s002,s003,s004".split(","); for(int i = 0 ; i < ids.length ; i++){ studentMap.put(ids[i], students.get(i)); } display(students); display(studentSet); display(students.iterator()); display(studentSet.iterator()); System.out.println(studentMap); System.out.println(studentMap.keySet()); display(studentMap.values()); display(studentMap.values().iterator()); }}class Student{ private int id; private String name; public Student(int id,String name) { this.id = id; this.name = name; } @Override public String toString() { return id+":"+name; }}复制代码

结论:

1.Collection接口和Iterator都可以将display方法与底层容器解耦

2.Collection更方便一些,可以使用foreach

Foreach与迭代器

foreach可以应用于任何Collection对象。

因为Java SE5引入了新的被称为Iterable的接口,该接口包含iterator方法,并且Iterable接口被foreach用来在序列中移动。因此,只要你创建了任何实现Iterable的类,都可以将它用于foreach语句。

/** * Iterable的使用 * @author LiangYu * 2018-01-16 */public class IterableTest {	@Test	public void test() throws Exception {		IterableClass iterableClass = new IterableClass("Hello,World,I,am,Kosmo,Leung,!".split(","));		for(String msg : iterableClass){			System.out.print(msg+" ");		}	}}class IterableClass implements Iterable
{ private String[] word; public IterableClass(String[] word){ this.word = word; } @Override public Iterator
iterator() { return new Iterator
() { private int index = 0; @Override public boolean hasNext() { return index

注意:foreach可以用于数组或其他任何Iterable,但并不意味着数组肯定是Iterable,而自动包装也不会发生

例如:

/** * 数组并不一定是Iterable * @author LiangYu * 2018-01-16 */public class ArrayIsNotIterableTest {	@Test	public void test() throws Exception {		String[] textArray = {
"A","B","C"};// iterable(textArray); //编译不通过 iterable(Arrays.asList(textArray)); }
void iterable(Iterable
iterable){ for(T t : iterable){ System.out.print(t+" "); } }}复制代码

转载地址:http://cfkpa.baihongyu.com/

你可能感兴趣的文章
lock关键字理解
查看>>
20172303 2018-2019-1 《程序设计与数据结构》第3周学习总结
查看>>
[Javascript]史上最短的IE浏览器判断代码
查看>>
关于《大道至简》第五章的收获
查看>>
网卡驱动
查看>>
kinect sdk开发入门WPFdemo笔记
查看>>
Server.Transfer详细解释
查看>>
java单链表的增、删、查操作
查看>>
The working copy at 'xxx' is too old 错误解决
查看>>
jadclipse
查看>>
// 1.什么是JOSN?
查看>>
SQL语句详细汇总
查看>>
如何保护.net中的dll文件(防破解、反编译)
查看>>
Python 装饰器
查看>>
Docker 网络模式
查看>>
[POI2013]Usuwanka
查看>>
problem-solving-with-algorithms-and-data-structure-usingpython(使用python解决算法和数据结构) -- 算法分析...
查看>>
nodejs + CompoundJS 资源
查看>>
转:C#并口热敏小票打印机打印位图
查看>>
scau 17967 大师姐唱K的固有结界
查看>>