若是一个程序只包含固定数量的且其生命期都是已知的对象,那么这是一个很是简单的程序。java
使用ArrayList:建立一个实例,用add()插入对象,而后用get()访问对象,此时须要使用索引,像数组同样,但不是要[]。程序员
import java.util.ArrayList; public class ApplesAndOrangesWithoutGenerice { @SuppressWarnings("unchecked")//不受检查异常的警告 public static void main(String[] args) { ArrayList apples = new ArrayList(); for (int i = 0; i < 3; i++) { apples.add(new Apple()); } apples.add(new Orange()); for (Object obj : apples) { System.out.println(((Apple) obj).id()); } } } class Apple { private static long counter; private final long id = counter++; public long id() { return id; } } class Orange { }
ArrayList保存的是Object。
要想定义保存特定类型的ArrayLIst可使用泛型<>。正则表达式
import java.util.ArrayList; public class ApplesAndOrangesWithoutGenerice { @SuppressWarnings("unchecked")//不受检查异常的警告 public static void main(String[] args) { ArrayList<Apple> apples = new ArrayList(); for (int i = 0; i < 3; i++) { apples.add(new Apple()); } //apples.add(new Orange()); for (Object obj : apples) { System.out.println(((Apple) obj).id()); } } } class Apple { private static long counter; private final long id = counter++; public long id() { return id; } } class Orange { }
当指定了某个类型做为泛型参数时,并不只限于只能将该确切类型的对象放置到容器中,向上转型也能够像做用于其余类型同样做用于泛型。数据库
import java.util.ArrayList; public class ApplesAndOrangesWithoutGenerice { @SuppressWarnings("unchecked")//不受检查异常的警告 public static void main(String[] args) { ArrayList<Apple> apples = new ArrayList(); for (int i = 0; i < 3; i++) { apples.add(new A()); apples.add(new B()); apples.add(new C()); } //apples.add(new Orange()); for (Object obj : apples) { System.out.println(((Apple) obj).id()); } } } class Apple { private static long counter; private final long id = counter++; public long id() { return id; } } class A extends Apple { } class B extends Apple { } class C extends Apple { } class Orange { }
Java容器类类库的用途是保存对象,并将其划分为两个不一样的概念:编程
List<Type> types=new ArrayList<Type>()
ArrayList被向上转型为List。
Conllection接口归纳了序列的概念——一种存放一组对象的方式。数组
import java.util.ArrayList; import java.util.Collection; public class SimpleCollection { public static void main(String[] args) { Collection<Integer> c = new ArrayList<Integer>(); for (int i = 0; i < 10; i++) { c.add(i); } for (int i : c) { System.out.println(i); } } }
Arrays.asList()方法接受一个数组或一个用逗号分隔的元素列表,并将其转换为一个List对象。Collections.addAll()方法接受一个Collection对象,以及一个数组或一个用逗号分隔的列表,将元素添加到Collection中。安全
import java.util.*; public class AddingGroups { public static void main(String[] args) { Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4)); Integer[] moreInts = {6, 7, 8, 9}; collection.addAll(Arrays.asList(moreInts)); Collections.addAll(collection,12,13,14); Collections.addAll(collection,moreInts); List<Integer> list=Arrays.asList(13,14,15); } }
Collection.addAll()成员方法只能接受一个Collection对象做为参数,所以不如Arrays.asList()和Collections.addAll()灵活,着两个方法均可以是可变参数。
能够直接使用Arrays.asList()的输出,将它当成List,但在这种状况下,地城是数组。数据结构
import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public class AsListInference { public static void main(String[] args) { List<Snow> snow1 = Arrays.asList(new P(), new S()); List<Snow> snow2 = Arrays.asList(new P(), new S(), new L()); List<Snow> snow3 = Arrays.asList(new H(), new L()); List<Snow> snow4 = new ArrayList<Snow>(); Collections.addAll(snow4, new P(), new L()); List<Snow> snow5 = Arrays.<Snow>asList(new L());//显示类型参数说明 } } class Snow{} class P extends Snow{} class L extends P{} class H extends P{} class S extends Snow{}
import java.util.*; public class PrintingContainers { static Collection fill(Collection<String> coll) { coll.add("rat"); coll.add("cat"); return coll; } static Map fill(Map<String, String> map) { map.put("rat", "r"); map.put("cat", "c"); return map; } public static void main(String[] args) { System.out.println(fill(new ArrayList<String>())); System.out.println(fill(new LinkedList<String>())); System.out.println(fill(new HashSet<String>())); System.out.println(fill(new TreeSet<String>())); System.out.println(fill(new LinkedHashSet<String>())); System.out.println(fill(new HashMap<String,String>())); System.out.println(fill(new TreeMap<String,String>())); System.out.println(fill(new LinkedHashMap<String,String>())); } }
Collection在每一个槽中只能保存一个元素,此类容器还包括List。Map每一个槽内保存两个元素,键和值相关联的值。
ArrayList和LinkedList都是List类型,从输出能够看出,它们都是按照被插入的顺序保存元素的。
二者的不一样之处不只在于执行某写类型的操做时的性能。并且LinkedList包括的操做也多于ArrayList。
HashSet、TreeSet和LinkedHashSet都是Set类型。
Map使得你能够用键来查找对象,就像一个简单的数据库。键所关联的对象称为值。
HashSet同样,HashMap也提供了最快的查找技术,也没有按照任何明显的顺序来保存元素。TreeMap按照比较结果的升序保存键,而LinkedHashMap则按照插入顺序保存键,同时还保留了HashMap的查询速度。并发
List能够将元素维护在特定的序列中。List接口在Collection的基础上添加大量的方法,使得能够在List的中间插入和移除元素。
有两种类型的List:app
持有事物是容器最基本的工做,要使用容器,必须对容器的确切类型编程。
若是只要使用容器,不知道或者不关心容器的类型,要如何不重写代码就能够应用于不一样类型的容器?
使用迭代器:迭代器是一个对象,它的工做是遍历并选择序列中的对象,而客户端程序员不须要指定序列底层的结构。迭代器一般被称为轻量级对象:建立它的代价很小,常常能够看到对迭代器的奇怪限制。
好比Java中的Iterator只能单向移动。
接受对象容器并传递它,从而再每一个对象上都执行操做。
建立一个display方法,没必要知道容器的确切类型:
display方法不包含任何有关它遍历的序列的类型信息:可以将遍历序列的操做与序列底层的结构分离。因此,迭代器统一了对容器的访问方式。
ListIterator是一个更增强大的Iterator的子类型,它只能用于各类List类访问。但ListIterator能够双向移动。
LinkedList也像ArrayList同样实现了基本的List接口,可是它执行某些操做比ArrayList更高效,但再随机访问操做要差一些。
栈一般是指后进先出的容器。有时也被称为叠加栈,由于最后压入栈的元素,第一个弹出栈。
直接将LinkedList做为栈使用。
import java.util.LinkedList; public class Stack<T> { LinkedList<T> storage=new LinkedList<T>(); public void push(T t){storage.addFirst(t);}//插入一个元素 public T peek(){return storage.getFirst();}//获取第一个元素 public T pop(){return storage.removeFirst();}//移除第一个元素 public boolean empty(){return storage.isEmpty();}//是否还有元素 public String toString(){return storage.toString();} }
建立一个新的Stack类:
public class StackTest { public static void main(String[] args){ Stack<String> stack=new Stack<String>(); for(String s:"My dog has fleas".split(" ")) stack.push(s); while (!stack.empty()) System.out.println(stack.pop()); } }
Set不保存重复的元素。
Set具备与Collection彻底同样的接口。实际上Set就是Collection,只是行为不一样。Set基于对象的的值来肯定归属性。
import java.util.HashSet; import java.util.Random; import java.util.Set; import java.util.TreeSet; public class SetOfInteger { public static void main(String[] args){ Random rand=new Random(47); Set<Integer> intset=new HashSet<Integer>(); for (int i=0;i<10;i++) intset.add(rand.nextInt(30)); for(int i:intset) System.out.println(i); } }
HashSet所维护的顺序与TreeSet或LinkedHashSet都不一样。TreeSetj将元素存储再红——黑树数据结构中,而HashSet使用的是散列函数。LinkedHashList由于查询速度的缘由也使用了散列。
对结构排序,使用TreeSet来代替HashSet
import java.util.HashSet; import java.util.Random; import java.util.Set; import java.util.TreeSet; public class SetOfInteger { public static void main(String[] args){ Random rand=new Random(47); Set<Integer> intset=new TreeSet<Integer>(); for (int i=0;i<10;i++) intset.add(rand.nextInt(30)); for(int i:intset) System.out.println(i); } }
使用contains()测试Set归属性
import java.util.Collections; import java.util.HashSet; import java.util.Set; public class SetOperations { public static void main(String[] args){ Set<String> set1=new HashSet<String>(); Collections.addAll(set1,"a b c d e f g".split(" ")); set1.add("m"); System.out.println("m:"+set1.contains("m")); System.out.println("h:"+set1.contains("h")); } }
打开文件,并将其读入一个Set中。
TextFile继承自List< Sting >,其构造器将打开文件,并更具正则表达式将其断开。
若是要按照字母排序,能够向TreeSet构造器传入String.CASE_INSENTIVE_ORDER比较器。
import net.mindview.util.TextFile; import java.util.Set; import java.util.TreeSet; public class UniqueWordsAlphabetic { public static void main(String[] args){ Set<String> words=new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); words.addAll(new TextFile("第十一章持有对象\\src\\SimpleCollection.java","\\W+")); System.out.println(words); } }
将对象映射到其余对象的能力是一种解决编程问题的杀手锏。
import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class MapOfList { public static Map<Integer, List<? extends Person>> petPeople = new HashMap<Integer, List<? extends Person>>(); static { petPeople.put(1, Arrays.asList(new Man("aaa"),new WoMan("bbb"))); } public static void main(String[] args){ System.out.println(petPeople.keySet()); System.out.println(petPeople.values()); System.out.println(petPeople); } } class Person { private String name; Person(String name){ this.name=name; } } class Man extends Person { public Man(String name){ super(name); } } class WoMan extends Person { WoMan(String name){ super(name); } }
Map能够返回它的键的Set,它的值Collection,或者它的键值对的Set。
队列是一个典型的先进先出的容器。队列在并发编程中特别重要,由于它们能够安全地将对象从一个任务传输给另外一个任务。
LinkedLisk提供了方法以支持队列的行为,而且它实现了Queue接口,所以LinkedLisk能够用做Queue的一种实现。
import java.util.LinkedList; import java.util.Queue; import java.util.Random; public class QueueDemo { public static void printQ(Queue queue){ while (queue.peek()!=null) System.out.print(queue.remove()+" "); System.out.println(); } public static void main(String[] args){ Queue<Integer> queue=new LinkedList<Integer>(); Random ran=new Random(); for(int i=0;i<10;i++) queue.offer(ran.nextInt(i+10)); printQ(queue); Queue<Character> qc=new LinkedList<Character>(); for (char c:"Brontosaurus".toCharArray()) qc.offer(c); printQ(qc); } }
offer()方法将一个元素插入到队尾,或者返回false。peek()和element()都将在不移除的状况下返回对头。poll()和remove()方法将移除并返回对头。
优先级队列声明下一个弹出元素最须要的元素。
当你在PriorityQueue上调用offer()方法来插入一个对象时,这个对象会在队列中被排序。默认排序将使用对象在队列中天然顺序,但你能够经过提供本身的Comparator来修改这个顺序。
import java.util.*; public class PriorityQueueDemo { public static void main(String[] args) { PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>(); Random rand = new Random(47); for (int i = 0; i < 10; i++) priorityQueue.offer(rand.nextInt(i + 10)); QueueDemo.printQ(priorityQueue); List<Integer> ints = Arrays.asList(25, 22, 20, 18, 14, 9, 3, 1, 1, 2, 3); priorityQueue = new PriorityQueue<Integer>(ints); QueueDemo.printQ(priorityQueue); priorityQueue = new PriorityQueue<Integer>(ints.size(), Collections.reverseOrder()); priorityQueue.addAll(ints); QueueDemo.printQ(priorityQueue); String face = "EDUCATION SHOULD ESCHEW"; List<String> strings = Arrays.asList(face.split(" ")); PriorityQueue<String> stringPQ = new PriorityQueue<String>(strings); QueueDemo.printQ(stringPQ); stringPQ = new PriorityQueue<String>(strings.size(), Collections.reverseOrder()); stringPQ.addAll(strings); QueueDemo.printQ(stringPQ); Set<Character> characters = new HashSet<Character>(); for (char c : face.toCharArray()) characters.add(c); PriorityQueue<Character> characterspc = new PriorityQueue<Character>(characters); QueueDemo.printQ(characterspc); } }
在PriorityQueue重复是容许的,最小值拥有最高优先级。
Collection是描述因此有序列容器的共性的根接口,它可能会被认为是一个附属接口,即由于要表示其余若干接口的共性出现的接口。
经过针对接口而非具体实现编写代码,咱们的代码能够应用于更多的对象类型。
import java.util.*; public class InterfaceVsIterator { public static void display(Iterator<Integer> it) { while (it.hasNext()) { Integer i = it.next(); System.out.print(i+","); } System.out.println(); } public static void display(Collection<Integer> ints) { for(Integer i:ints) System.out.print(i+"-"); System.out.println(); } public static void main(String[] args) { List<Integer> intList= Arrays.asList(1,2,3,15,3); Set<Integer> intSet=new HashSet<Integer>(intList); Map<String,Integer> intmap=new LinkedHashMap<String,Integer>(); String[] s=new String[]{"A","b","c","f","w"}; for(int i=0;i<s.length;i++) intmap.put(s[i],intList.get(i)); display(intList); display(intSet); display(intList.iterator()); System.out.println(intmap); System.out.println(intmap.keySet()); display(intmap.values()); display(intmap.values().iterator()); } }
Collection和Iterator均可以将display()方法与底层容器的特定实现解耦。
import java.util.AbstractCollection; import java.util.Iterator; public class CollectionSequence extends AbstractCollection<Integer> { private Integer[] ints=new Integer[]{1,4,2,5,1}; @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { private int index=0; @Override public boolean hasNext() { return index<ints.length; } @Override public Integer next() { return ints[index++]; } }; } @Override public int size() { return ints.length; } public static void main(String[] args){ CollectionSequence c=new CollectionSequence(); InterfaceVsIterator.display(c); InterfaceVsIterator.display(c.iterator()); } }
生成Iterator是将队列与消费队列的方法链接在一块儿耦合度最小的方式,而且与1实现Collection相比,它在序列类上所加的约束少得多。
import java.util.Iterator; public class NonCollectionSequence extends PetSequence { public Iterator<Integer> iterator() { return new Iterator<Integer>() { int index = 0; @Override public boolean hasNext() { return index < ints.length; } @Override public Integer next() { return ints[index++]; } }; } public static void main(String[] args){ NonCollectionSequence nc=new NonCollectionSequence(); InterfaceVsIterator.display(nc.iterator()); } } class PetSequence { protected int[] ints = new int[]{1, 4, 2, 5, 3}; }
foreach语法主要用于数组,但它也能够用于任何Collection对象。
Java SE5引入了新的被称为Iterable接口,该接口包含一个可以产生Iterator的iterator()方法,而且Iterable接口被foreach用来在序列中移动。所以,若是你建立了一个Iterable的类,均可以用于foreach。
import java.util.Iterator; public class IterableClass implements Iterable<String> { protected String[] words = ("a,d,fe,r,gd,v,g").split(","); @Override public Iterator<String> iterator() { return new Iterator<String>() { int index = 0; @Override public boolean hasNext() { return index < words.length; } @Override public String next() { return words[index++]; } }; } public static void main(String[] args){ for(String s:new IterableClass()) System.out.print(s+","); } }
在Java SE中,大量的类都是Iterable类型,主要包括全部Collection类(不包括各类Map)
foreach能够用于数组或其余任何Iterable,可是这并不意味着数组确定也是一个Iterable,二任何自动包装也不会发生。
import java.util.Arrays; public class ArrayIsMotIterable { static<T> void test(Iterable<T> ib){ for(T t:ib) System.out.print(t+" "); } public static void main(String[] args){ test(Arrays.asList(1,2,3,2)); String[] strings={"a","b","c"}; //test(strings);//转换失败 test(Arrays.asList(strings)); } }
尝试把数组转换成Iterable会失败,不存在任何数组到Iterable的自动转换,必须手工执行这种转换。
但愿在默认向前的迭代器基础上,添加产生反向迭代器的能力,所以,不能使用覆盖,须要添加一个可以产生Iterable对象的方法,该对象能够用于foreach语句。
mport java.util.Iterator; public class IterableClass implements Iterable<String> { protected String[] words = ("a,d,fe,r,gd,v,g").split(","); @Override public Iterator<String> iterator() { return new Iterator<String>() { int index =words.length-1 ; @Override public boolean hasNext() { return index > -1; } @Override public String next() { return words[index--]; } }; } public static void main(String[] args){ for(String s:new IterableClass()) System.out.print(s+","); } }
若是直接将ral对象置于foreach语句中,将获得向前迭代器。但若是在对象上调用产生向后迭代器的方法,就会产生不一样的行为了。 经过这种方式,能够添加两种适配器方法。