持有对象
11.1 泛型和类型安全的容器
tips:
- 如果一个类没有显式的声明继承自哪个类,那么它自动地继承自Object;
- 泛型的作用:可以在 编译器 防止将错误类型的对象放置到容器中;
- 如果不需要使用每个元素的索引,可以使用foreach语法来选择List中的每个元素;
11.2 基本概念
一共可以分为两大类
- Collection
a. ArrayList
b. LinkedList
c. Set
d. Queue - Map
a. HashMap
11.3 添加一组元素
- Arrays.asList()
- Collection.addAll()
- Collections.addAll()
public class AddingGroups {
public static void main(String[] args) {
//首先构建一个Collection对象,并对其进行初始化
//Arrays.asList()接受一个数组或者逗号分隔的元素列表,转换成一个List对象
Collection<Integer> collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Integer[] moreInts = {6, 7, 8, 9, 10}; //定义一个数组
collection.addAll(Arrays.asList(moreInts)); //将一个数组转换为List对象
//然后调用Collections.addAll()方法,接受一个Collection对象,然后用后面的参数填充这个Collection对象
Collections.addAll(collection, 11, 12, 13, 14, 15);
Collections.addAll(collection, moreInts);
//看似返回一个List,实际底层是一个数组,不可以调整数组的大小
List<Integer> list = Arrays.asList(16, 17, 18, 19, 20); //底层表示的是数组,不能调整尺寸大小
list.set(1, 99);
//list.add(0, 100); 报错Exception in thread "main" java.lang.UnsupportedOperationException
for (int i = 0; i < collection.size(); i++) {
System.out.print(((ArrayList<Integer>) collection).get(i) + " ");
}
}
}
11.4 容器的打印
- 打印数组需要使用Arrays.toString() ,否则只会打印内存地址
- ArrayList和LinkedList
相同点:
a. 两者都按照插入的顺序保存元素;
不同点:
a. ArrayList随机查询的速度比LinkedList快;
b. LinkedList的随机增删元素的速度比ArrayList快;
c. LinkedList包含的操作比ArrayList多; - HashSet、TreeSet、LinkedHashSet
相同点:
a. 存储的元素都是唯一不可重复的;
不同点:
a. HashSet存储元素没有顺序,是 随机 的;
b. TreeSet存储元素自动按照 升序排列;
c. LinkedHashSet存储元素按照 添加的顺序 排列; - HashMap、TreeMap、LinkedHashMap
相同点:
a. Map对于每一个键,只能够存储一次,后面的会覆盖前面的;
b. 不必指定Map的尺寸,它自己会自动地调整尺寸;
不同点:
a. HashMap存储元素没有顺序,是 随机的;
b. TreeMap按照比较结果的 升序 保存键;
c. LinkedHashMap按照 插入的顺序 保存键,同时保留了HashMap的查询速度;
11.5 List
- contains()
用来确定某个对象是否在列表中,没有则返回false; - remove()
想移除一个对象,可以将这个对象的引用传递给remove()方法,如果没有则返回false; - indexOf()
发现该对象在List中所处的位置,索引从0开始计数; - subList()
允许从较大的列表中创建出一个片段,区间是 左闭右开 的; - containsAll()
将4的结果应用到containsAll()中自然是true; - Collections.sort()、Collections.shuffle()
如果将4的结果进行随机排序或者按照某个规则排序,不会影响containsAll()的结果; - retainAll()
去两个集合的交集,但比较的结果取决于equals()方法是如何定义的; - removeAll()
移除参数中的所有元素,同样比较的结果取决于equals()方法是如何定义的; - addAll(index, list)
在位置index处把list插入,其余后面的元素后移,区别于Collection.addAll()只能将元素添加到List的结尾处; - isEmpty() 和 clear()
判断list是否为空和清空整个List; - toArray() ★★★★
可以将 任意的 的Collection转换为一个数组,如果没有参数则返回Object数组,如果传递目标数据,将产生指定类型的数组,如果参数数组太小,toArray()方法将创建一个具有合适尺寸的数组;
Object[] objects = pets.toArray(); //toArray();方法将集合变为数组
System.out.println("22: " + objects[3]);
//这里传递了目标类型的数据,但是数组大小开辟为0,
Pet[] pa = pets.toArray(new Pet[0]); //根据参数数组的类型构造数组
//对于参数数组太小的情况,toArray()方法将创建一个具有合适尺寸的数组
System.out.println("23: " + pa[3].id());
11.6 迭代器
- 迭代的优势:统一了容器类的访问方式,有以下几个核心的方法:
- 使用方法iterator()要求容器返回一个Iterator,Iterator将准备好返回序列的第一个元素;
- 使用next()获得序列中的下一个元素;
- 使用hasNext()检查序列中是否还有元素;
- 使用remove()将迭代器新返回的元素删除(会改变原来的容器内容);
public class CrossContainerIteration {
public static void main(String[] args) {
ArrayList<Pet> pets = Pets.arrayList(8);
LinkedList<Pet> pets1 = new LinkedList<>(pets);
HashSet<Pet> pets2 = new HashSet<>(pets);
// TreeSet<Pet> pets3 = new TreeSet<>(pets); //Pet类想先实现Comparable才可以执行比较方法
display(pets.iterator());
display(pets1.iterator());
display(pets2.iterator());
}
/**
* 如果不用iterator那么需要定义三个display方法,参数类型分别
* 为ArrayList<Pet>、LinkedList<Pet>、HashSet<Pet>
* @param iterator iterator统一了容器的类型
*/
private static void display(Iterator<Pet> iterator) {
while (iterator.hasNext()){
Pet p = iterator.next();
System.out.print(p.id() + ":" + p + " ");
}
System.out.println();
}
}
11.6.1 ListIterator
Iterator只能向前移动,而ListIterator可以双向移动