持有对象
为什么需要容器
有时候需要在程序运行的时候创建对象,这时候就无法通过一开始去new了,因此需要一个容器来动态的去保存在运行时候创建的对象,array类型是我们熟知的容器,数组将数字与对象联系起来:它保存类型明确的对象,查询对象时,不需要对结果做类型转换;它可以是多维的,可以保存基本类型的数据;但是,数组一旦生成,其容量不能改变。因此JAVA使用更多的集合类来处理这种情况。
添加一组元素
一般都是使用add方法向容器中一个一个的添加元素
如何一次性添加多个元素?
Collection(父类)中提供了接受其他容器来初始化它的构造器,只是这样的速度比较慢。
Collection(父类)还有一个addAll的方法,同样也是接受其他容器的参数一次性添加。1
2
3Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));
Integer[] moreInts = { 6, 7, 8, 9, 10 };
collection.addAll(Arrays.asList(moreInts));
上面两种方法都是接受另一个容器对象,可能我希望还可以参数是数组,甚至是 一串以逗号分开的数字。
那么如何将这串数组,或者数组转为容器呢?
util包里有一个Arrays的工具包,它有一个asList的方法,可以将数组,或者一串以逗号分开的数字,转成列表:1
2
3Integer[] moreInts = { 6, 7, 8, 9, 10 };
Arrays.asList(moreInts);
Arrays.asList(16, 17, 18, 19, 20);
还有一个Conllections的工具类,可以进一步的减少添加一组数组对象的中间过程:1
2
3
4Collection<Integer> collection = new ArrayList<Integer>();
Integer[] moreInts = { 6, 7, 8, 9, 10 };
Collections.addAll(collection, 11, 12, 13, 14, 15);
Collections.addAll(collection, moreInts);
推荐使用Collections来添加元素,为什么?
使用Collections結合空容器添加元素是最好的办法,因为直接使用Arrays.asList会有两个问题:
使用Arrays.asList的时候,需要注意一个问题:它转换后的容器是可以修改元素值,但是不能修改元素的长度的,为啥?
原因是Arrays.asList转换的容器基本底层形式是数组,它不能调整大小。
并且如果这个容器的元素和顺序被修改,直接会影响到原数组。使用Arrays.asList的时候,还需要注意另外的一个问题:它会对列表的结果类型进行最佳猜测,不管我们指定它是怎样的类型,如果有冲突,会报错。
案例:1
2
3
4
5
6
7
8
9class Snow {}
class Powder extends Snow {}
class Light extends Powder {}
class Heavy extends Powder {}
class Crusty extends Snow {}
class Slush extends Snow {}
List<Snow> snow2 = Arrays.asList(new Light(), new Heavy());//编译报错
List<Snow> snow1 = Arrays.asList(new Crusty(), new Slush(), new Powder());//编译成功
如何使用Collections防止出现这个问题?
直接上源码:1
2List<Snow> snow3 = new ArrayList<Snow>();
Collections.addAll(snow3, new Light(), new Heavy());
输入容器
在打印数组的使用,会打印数组的一个引用,因此需要使用Arrays.toString方法先将数组转为字符串。
容器呢?
抱歉,让你失望了。
容器很好的重写了toString方法。
因此直接打印即可输出里面的元素。
Map
HashMap:快速访问
TreeMap:“键”保持插入顺序
LinkedMap:保持插入顺序,并且提供快速访问。
迭代器
使用ListIterator可以实现双向迭代,需要注意的一点是迭代器的指向是两个元素之前的位置。
栈
栈是描述后进先出的,栈是用Linklist实现的。
队列
队列描述的是先进先出的元素弹出规则。
队列在并发编程里很重要,并且LinkedList实现了Quene接口。
优先级队列描述的是按优先级的元素弹出规则
如何定义这个优先级?
结合Comparator来定义,有一个构造器如下:1
PriorityQueue(int initialCapacity, Comparator<? super E> comparator);
Collection和Iterator
Collection是什么?
Collection接口是所有容器的共有接口,这个接口的表示是一个可以持有对象的容器。
他有一个AbstractCollection的子类,实现了Collection的绝大部分方法,
Iterator接口是迭代器模式,表示支持迭代。
Collection支持迭代吗?
1 | public interface Collection<E> extends Iterable<E> {} |
由上可见,是支持的。
为什么实现Iterable就支持迭代?
因为Iterable接口中有一个返回Iterator接口的方法:1
Iterator<T> iterator();
Iterator接口有何用?
这个接口中定义了next(),hasNext(),remove()三种方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
这是一种迭代器模式,可以让所有实现该接口的对象有一种遍历自己内部“元素”而无需暴露具体实现细节的方法。
为什么Collection不实现Iterator,而是实现Iterable?
Iterable是Iterator的一个封装,目前看来有两个好处:
- Iterator中是由“指针”来指向迭代的元素,这样的一个问题是,我下一次一个新的迭代无法从头开始。
- Iterable可以使用foreach操作来简化。
如何让新对象支持迭代?
要么实现Collection,要么实现Iterable。
不建议实现Collection,因为他需要实现的方法较多,可以继承AbstractCollection:只是还是需要实现size()和iterator()两个方法。
foreach和迭代器
什么情况下可以使用foreach?
实现了Iterable接口就可以。
基本上所有的Collection都可以,除了Map之外。
那Map如何迭代?
1 | public class EnvironmentVariables { |
entrySet获得Entry类型的Set,然后遍历这个Set即可。
foreach的迭代规则是如何的?
foreach()实际上就是:1
2
3for(Iterable i;i.hasNext();){
Object o = i.next();
}
因此,规则是由Iterable中的iterator()来制定的。
如何制定多个规则?
分析一下这个问题的本质:
- 这个类是现有的,我们不希望去更改它的源代码
- 本身有可能已经存在了一个规则,这时候不希望覆盖它。
- 实现的接口名和方法名一样
- 多个规则表示多重继承(接口)
1点指明需要使用适配模式,使用继承方法的适配模式即可。
2,3,4点都指明应该使用内部类,更好的是匿名内部类。
案例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41class ReversibleArrayList<T> extends ArrayList<T> {
public ReversibleArrayList(Collection<T> c) {
super(c);
}
public Iterable<T> reversed() {
return new Iterable<T>() {
public Iterator<T> iterator() {
return new Iterator<T>() {
int current = size() - 1;
public boolean hasNext() {
return current > -1;
}
public T next() {
return get(current--);
}
public void remove() {
// Not implemented
//throw new UnsupportedOperationException();
}
};
}
};
}
}
public class AdapterMethodIdiom {
public static void main(String[] args) {
ReversibleArrayList<String> ral =
new ReversibleArrayList<String>(Arrays.asList("To be or not to be".split(" ")));
// Grabs the ordinary iterator via iterator():
for(String s : ral)
System.out.print(s + " ");
System.out.println();
// Hand it the Iterable of your choice
for(String s : ral.reversed())
System.out.print(s + " ");
}
}
/* Output:
To be or not to be
be to not or be To
*///:~