如果一个程序只包含固定数量的对象并且对象的生命周期都是已知的,那么这是一个非常简单的程序
泛型和类型安全的集合
- 使用ArrayList
get()取出对象时,得到的只是 Object 的引用。 - 使用泛型后,在编译期就可以检查集合中是否有错误类型对象。
- 向上转型也适用于泛型(即可插入指定类的子类)
基本概念
1.集合(collection): List按照插入顺序保存,Set不能包含重复,Queue按排队规则。
2.映射(Map): 按照键值对存储。
3.通常创建时,可以将他们向上转型为更通用的接口,但是如果需要使用子类额外的方法,就不能向上转型
添加元素组
语法: Arrays.asList() 接受数组并转换为List对象。Collections.addAll(Collection< ?extends E> c)
import java.util.*;public class AddingGroups {public static void main(String[] args) {Collection<Integer> collection =new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));Integer[] moreInts = { 6, 7, 8, 9, 10 };collection.addAll(Arrays.asList(moreInts));// Runs significantly faster, but you can't// construct a Collection this way:Collections.addAll(collection, 11, 12, 13, 14, 15);Collections.addAll(collection, moreInts);// Produces a list "backed by" an array:List<Integer> list = Arrays.asList(16,17,18,19,20);list.set(1, 99); // OK -- modify an element// list.add(21); // Runtime error; the underlying// array cannot be resized.}}
疑问:为何此处非继承Snow的两个类加入LIst
class Light extends Powder {}class Heavy extends Powder {}public class AsListInference {public static void main(String[] args) {List<Snow> snow2 = Arrays.asList(new Light(), new Heavy());//- snow2.add(new Slush()); // Exception}}
- 打印:数组(必须使用Arrays.toString()生成可打印模式,Colletions直接打印。
列表List
- ArrayList: 数组实现 —> 随机访问元素
- LinkedList:链表实现—>插入,删除元素
- 对于LinkedList,在列表中插入和删除为廉价操作,而对ArrayList,则为代价昂贵操作。此处提醒我们:若在ArrayList中有许多插入操作,程序开始变慢,则需要考虑性能问题。(采用profiler进行解决)
- 实际操作见博客:
迭代器Iterators
Iterators实现的是应用于不同类型集合的抽象,在一个序列中移动并选择该序列中的每个对象。
疑惑解答:
Iterator没有当前元素,它的光标位置始终位于previous()【前一个元素,仅ListIterator有】与next()【后一个元素】之间。如下述例子中的 ^ 位置:
^ Element(0) ^ Element(1) ^ Element(2) ^ … ^ Element(n-1) ^
因此n个列表的迭代器有n+1个可能的指针位置。
iterator()返回一个Iterator。第一次调用next()方法时,返回序列的第一个元素。next()获得序列中的下一个元素。hasNext()检查序列中是否还有元素。remove()将迭代器最近返回的元素删除。
迭代器统一了对于集合的访问方式:
public static void display(Iterator<Pet> it) {while(it.hasNext()) {Pet p = it.next();System.out.print(p.id() + ":" + p + " ");}System.out.println();}//对于该函数,我们仅需要传入迭代器即可完成遍历//而迭代器可由List<pet>,LinkedList<pet>,HashSet<pet>等类型产生。
进一步了解一下 Iterable 接口的用法:
public class CrossCollectionIteration2 {public static void display(Iterable<Pet> ip) {Iterator<Pet> it = ip.iterator();while(it.hasNext()) {Pet p = it.next();System.out.print(p.id() + ":" + p + " ");}System.out.println();}//此处的Iterable表示能生成Iterator的各种东西//故可以直接传入List<pet>,LinkedList<pet>等作为参数
ListIterator
特点: 双向移动,可指向位置前一个和后一个元素的索引。
更深入的分析见:Java集合中关于Iterator和ListIterator的详解
链表LinkedList
堆栈Stack
通过这个例子,入门泛型的类定义。
由于Java中使用 ArrayDeque 实现堆栈功能,因此若直接使用,需要声明为Deque类型。
而对于程序员而言,可以通过自己封装一个Stack类完成相应功能。
package onjava;import java.util.Deque;import java.util.ArrayDeque;public class Stack<T> {private Deque<T> storage = new ArrayDeque<>();public void push(T v) { storage.push(v); }public T peek() { return storage.peek(); }public T pop() { return storage.pop(); }public boolean isEmpty() { return storage.isEmpty(); }@Overridepublic String toString() {return storage.toString();}}
此处使用composition而非继承,创建类时,我们只需要栈的行为,而不需要ArrayDeque的其他方法。
- 若要在自己的代码中使用Stack类,需要完整指定包名或者更改这个类的名称;否则会与java.util包中的Stack冲突。
onjava.Stack<String> stk = new onjava.Stack<>(); - 由于 Java.util 中 Stack 采用 vector 实现,而 vector 底层又采用数组实现,push、pop性能大大降低,因而最好不用或者自己封装一个 Stack 类最佳。
集合Set
Java文档链接
特性:
- 元素不重复
- Set就是一个Colletion,没有额外的功能,只是行为不同
应用:
- 快速查询元素归属性(HashSet)
contains()
Trick:
- Treeset使用字典序排序,向构造器传入String.CASE_INSENSITIVE_ORDER 比较器。
Set words = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
映射Map
- Map可以扩展到多个维度,只需要创建一个值为Map的Map(这些Map值可以是其他集合甚至是其他Map)
- Map的一种遍历方法:
for(Person person : petPeople.keySet()) { //keySet()获取petPeople所有键组成的SetSystem.out.println(person + " has:");for(Pet pet : petPeople.get(person)) //用key遍历valueSystem.out.println(" " + pet);}
队列Queue
java文档链接
特性:
- FIFO(先进先出)
- LinkedList实现了Queue接口,可向上转型为Queue
常用函数:
- offer():在尾部插入一个元素。
- peek()、element():返回队头元素
- poll(),remove():删除并返回队头元素
PriorityQueue
优先级队列声明下一个弹出的元素是具有最高优先级的元素,可以提供自己的 Comparator 来修改这个顺序。stringPQ = new PriorityQueue<>(strings.size(), Collections.reverseOrder());
集合与迭代器
在Java中,遵循集合之间的所有共性都是通过迭代器实现的,而不是用Colletion 表示集合之间的共性。
理解下述两种实现方式:
public class InterfaceVsIterator {public static void display(Iterator<Pet> it) { //Iteratorwhile(it.hasNext()) {Pet p = it.next();System.out.print(p.id() + ":" + p + " ");}System.out.println();}public static void display(Collection<Pet> pets) { //Iterablefor(Pet p : pets)System.out.print(p.id() + ":" + p + " ");System.out.println();}}
- 如果实现了 Collection ,就必须实现
iterator()```java import typeinfo.pets.; import java.util.;
class PetSequence { protected Pet[] pets = Pets.array(8); }
public class NonCollectionSequence extends PetSequence {
public Iterator
<a name="cWZZb"></a>###<a name="UgAIF"></a>### for-in和迭代器- for-in 的实现是 Java中一个名为 **Iterable** 的接口,该接口包含一个能够生成 **Iterator** 的 `iterator()` 方法。所以只要创建了任意实现 **Iterable **的类,就可使用 for-in 语句。```javapublic class IterableClass implements Iterable<String> {protected String[] words = ("And that is how " +"we know the Earth to be banana-shaped.").split(" ");@Overridepublic Iterator<String> iterator() {return new Iterator<String>() {private int index = 0;@Overridepublic boolean hasNext() {return index < words.length;}@Overridepublic String next() { return words[index++]; }@Overridepublic void remove() { // Not implementedthrow new UnsupportedOperationException();}};}public static void main(String[] args) {for(String s : new IterableClass())System.out.print(s + " ");}}
- for-in 不会自动装箱。
适配器方法惯用法
如果已有一个接口,需要另外一个接口,编写适配器解决。
import java.util.*;public class MultiIterableClass extends IterableClass {public Iterable<String> reversed() {return new Iterable<String>() {public Iterator<String> iterator() {return new Iterator<String>() {int current = words.length - 1;public boolean hasNext() {return current > -1;}public String next() {return words[current--];}public void remove() { // Not implementedthrow new UnsupportedOperationException();}};}};}public Iterable<String> randomized() { //random()并没有创建自己的Iteraotrreturn new Iterable<String>() { //而是返回被打乱的List的Iteratorpublic Iterator<String> iterator() {List<String> shuffled =new ArrayList<String>(Arrays.asList(words));Collections.shuffle(shuffled, new Random(47));return shuffled.iterator();}};}public static void main(String[] args) {MultiIterableClass mic = new MultiIterableClass();for(String s : mic.reversed())System.out.print(s + " ");System.out.println();for(String s : mic.randomized())System.out.print(s + " ");System.out.println();for(String s : mic)System.out.print(s + " ");}}
理解并重写葫芦娃!


