如果一个程序只包含固定数量的且生命周期都是已知的对象,那么这是个非常简单的程序
1、泛型和类型安全的容器
根据多态,集合类如果不使用泛型就会装任何类,因为所有类都是Object的子类,所以一个集合类的实例是可以装不同类的实例的。不过在取出这些实例时必须强制类型转换,不然会在编译时报错!看如下实例:
import java.util.ArrayList; public class First { @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(int i = 0; i < apples.size(); i++){ System.out.println(((Apple) apples.get(i)).id()); } } } class Apple{ private static long counter; private final long id = counter++; public long id(){ return id; } } class Orange{ }
ArrayList的实例能同时装Apple与Orange的实例,因为它们都是Object的子类。
把Orange类型强制转为Apple类型会在运行时报错。
2、基本概念
集合类分为两种
(1)Collection
包括List(按照插入顺序保存数据,按照索引查找元素,可理解为长度可变的数组),Set(不能有重复元素),Queue(队列)。
(2)Map
以键值对的形式存在。
3、添加一组元素
添加一个元素可以用add这里是添加一组,刚刚读的时候也很奇怪,为什么没有讲add。
可以用 Collections.addAll();来进行添加 例如:
Collections.addAll(collection,11,12,13,14,15); 里面传递一个collection参数,指明是哪个数组。
也可以使用Array.asList(),将Array变为list类型 ,不过要注意这样生成出来的数据结构是数组类型,不能调整尺寸。如果试图用add() delete()会获得“”Unsupported Operation“”
4 容器的打印
你必须使用Arrays.toString()来产生数组的可打印表示,但是打印容器无需任何帮助。看一个例子:
import java.util.*; public class Seven { 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>())); } static Collection fill(Collection<String> collection){ collection.add("rat"); collection.add("cat"); collection.add("dog"); collection.add("dog"); return collection; } static Map fill(Map<String,String> map){ map.put("rat","Fuzzy"); map.put("cat","Rags"); map.put("dog","Bosco"); map.put("dog","sqot"); return map; } } /* 输出: [rat, cat, dog, dog] [rat, cat, dog, dog] [rat, cat, dog] [cat, dog, rat] [rat, cat, dog] {rat=Fuzzy, cat=Rags, dog=sqot} {cat=Rags, dog=sqot, rat=Fuzzy} {rat=Fuzzy, cat=Rags, dog=sqot} */
从中可以看出,set不允许重复,map的键不允许重复,带Tree字符串的类还将元素进行了排序!!!
5 List
有两种类型的List
基本的ArrayList 它长与随机访问元素,但是在List中间插入和移除元素时较慢。
LinkedList,它通过代价较低的在List中间进行的插入和删除操作,提供了优化的访问顺序。随机访问比较慢。
(1)contains()方法来确定某个对象是否在对象中。
(2)remove()方法用来移除某个对象。
(3)如果你有一个对象的引用,可以使用indexOf()来确定该对象在List中所处的位置的索引编号。
(4)subList()方法用来从较大的列表中创建出一个片段。
(5)retainAll()方法用来求交集。
(6)removeAll()方法用来移除在参数List中的所有元素。
(7)addAll()方法用来在初始List的中间插入新的列表。
6、迭代器
迭代器是一个对象,它的工作是遍历并选择序列中的对象。从而做到了只是使用容器而不关心容器的类型。
在我看来,Java中的Iterator类似于数据结构中的单向链表,只能单向移动。只能用来:
(1)使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。
(2)使用next()获得序列中的下一个元素。
(3)使用hasNext()检查序列中是否还有元素。
(4)使用remove()将迭代器新近返回的元素删除。
iterator()只能向前遍历,而不能想后遍历。使用listIterator()方法能够实现向后遍历:
7、LinkedList
LinkedList添加了使其可以作栈、队列或双端队列的方法。
getFirst() element() peek() 都是获取第一个元素,不过getFirst() 和 element() 在LinkedList为空时抛出NoSuchElementException 而poll则是在列表为空时返回null.
addFirst()将某个元素插入到列表的头部。而offer()、add()和addLast()作用类似,将某个元素插入到列表的尾部。
remove()、removeFirst()和poll()都是将某个元素从列表的头部移除。
8、Stack
"栈"通常是指“”后进先出“”(LIFO)的容器。
import java.util.*; public class Stack<T> { private LinkedList<T> storage = new LinkedList<T>(); public void push(T v){ storage.addFirst(v); } public T peek(){ return storage.getFirst(); } public T pop(){ return storage.removeFirst(); } public boolean empty(){ return storage.isEmpty();} public String toString(){ return storage.toString(); } }
9、Set
Set集合不允许有重复的元素,Set最常用的就是测试归属性,可以很容易的询问某个对象是否在某个Set中。正因如此,查找就成了Set最重要的操作。 Set具有与Collection完全一样的接口,因此没人任何额外的功能。
HashSet用散列维护存储顺序。TreeSet将元素存储在红-黑树中。
10、Map
import java.util.HashMap; import java.util.Map; import java.util.Random; public class Statistics { public static void main(String[] args) { Random rand = new Random(47); Map<Integer,Integer> m = new HashMap<Integer,Integer>(); for(int i = 0; i < 10000;i++){ int r = rand.nextInt(20); Integer freq = m.get(r); m.put(r, freq == null?1:freq+1); } System.out.println(m); } } /* 输出: {0=481, 1=502, 2=489, 3=508, 4=481, 5=503, 6=519, 7=471, 8=468, 9=549, 10=513, 11=531, 12=521, 13=506, 14=477, 15=497, 16=533, 17=509, 18=478, 19=464} */
11、Queue
队列是一个典型的先进先出的容器。队列常常被当做一种可靠的将对象从程序的某个区域传输到另一个区域的途径,在并发编程中特别重要。
队列中的方法可以总结为:1 offer队尾加 2 peek 和element 返回对头。3 poll和remove 移除对头并且返回。
11.1 PriorityQueue
优先级队列则表明返回的是一个最需要的队列。
12、Collection和Iterator
import java.util.*; public class InterfaceVsIterator { public static void display(Iterator<Integer> ints){ while(ints.hasNext()){ int i = ints.next(); System.out.print(i+" "); } System.out.println(); } public static void display(Collection<Integer> col){ for(int i:col){ System.out.print(i+" "); } System.out.println(); } public static void main(String[] args) { List<Integer> list = Arrays.asList(25,22,20,18); Set<Integer> set = new HashSet<>(list); Map<String,Integer> map = new LinkedHashMap<String,Integer>(); String[] name = "a b c d".split(" "); for(int i = 0; i < name.length; i++){ map.put(name[i], list.get(i)); } display(list); display(set); display(list.iterator()); display(set.iterator()); System.out.println(map); System.out.println(map.keySet()); display(map.values()); display(map.values().iterator()); } }
13、 Foreach与迭代器
foreach可以用于数组和任何其他Iterable.
但是数组不是Iterable
适配器方法惯用法 看懂了以后再来总结。