Java编程思想:第11章 持有对象
Java容器框架提供了多种不同特性的容器方便我们管理任意数量的对象。
11.1泛型和类型安全的容器
JavaSE5之前的容器允许我们向其中放入不同类型的对象,但是取出的时候需要进行类型强制转换,很容易出现问题。有了泛型之后需要我们只能向集合里添加指定类型及其子类,取出时也不需要类型转换,这个功能是编译器完成的。
11.2基本概念
Java中容器分为2个概念:
1)Collection:一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入顺序保存元素,Set不能有重复元素。Queue按照排队规则确定对象产生的顺序(通常与插入顺序相同)。
2)Map:映射表允许我们使用另一个对象来查找某个对象,它也被称为关联数组。
理想情况下在创建对象时向上转型成接口,方便切换实现,除非需要用到特有方法。
11.3添加一组元素
java.util包里Arrays和Collections类有很多实用方法,可以在一个Collection里添加一组元素。
Arrays.asList()接受一个数组或者可变长参数,转换成一个固定长度(不能add)的list。
Collections.addAll()接受一个Collection对象和一个可变长参数,向Collection里添加一组元素。
Collection.addAll()只能接收一个Collection对象,没有上面灵活。
首选:Collections.addAll()
注意Arrays.asList()对产生的List类型做了最理想的假设:即最近公共父类,这可能会产生问题。
比如:父类Person,一级子类Man,二级子类WhiteMan、BlackMan
List<Person> list = Arrays.asList(new WhiteMan(),new BlackMan());
这时会编译出错,因为编译器找到理想的类型是List<Man>而不是List<Person>,我们需要手动指定asList类型:
List<Person> list = Arrays.<Person>asList(new WhiteMan(),new BlackMan());
使用Collections.addAll()不需要指定类型,因为第一个参数里已经有类型了。
11.4容器的打印
容器类不需要做特殊处理即可直接打印,并且可以生成格式很好的输出。
11.5List
List可以把元素维护在特定的序列里,在Collection基础上添加了很多操作index的方法,如获取,设置,插入,删除。contains()/remove()/indexOf()等行为是根据equals()结果来的。
ArrayList提供高效访问,低效插入删除。LinkedList相反,一般情况使用ArrayList除非进行大量插入删除使用ArrayList影响性能了才改用LinkedList。
subList()可以返回大List里的一个子List,相当于对象引用copy了一份,所以list.containsAll(subList)是true,对subList元素的操作也会影响原来的list。
retainAll()交集操作,保留两个list里的共同元素,基于equals()。
其他方法...
11.6迭代器
任何容器都必须有某种方式可以插入元素并把它取回。对于List可以用get取出,如果从更高层次思考,会发现要使用容器,必须对容器的确切类型编程。如果我们可以使得对List使用的代码也可以对Set使用,就会非常方便。迭代器Iterator就是用于这种目的,使得我们不需要关心序列的底层结构就可以使用next()、hasNext()、remove()来遍历或删除序列中的元素。如果只是遍历不需要修改List,使用foreach更加方便。
remove()用了删除最后一次next()得到的元素,所以必须先使用next()取得元素,然后才能remove()
11.6.1ListIterator
是一个更加强大的Iterator子类型,但只能用于List类型的访问。允许进行双向(前后)访问,可以使用set替换被访问的最后一个元素,可以用listIterator(n)重载方法创建一个一开始就指向索引为n的ListIterator.
11.7LinkedList
LinkedList相比ArrayList除了某些操作性能不同之外,还添加了可以使其用作栈,队列或双端队列的方法。很多方法名称不同但是作用差不多,主要用于在不同上下文环境下使用。如element() getFirst(),remove(),removeFirst(),peek(),pop()等。
11.8Stack
后进先出,就像弹夹一样的储存装置。LinkedList有实现栈功能的所有方法,可以直接作为栈使用,但是有时候用一个真正的栈更可以把问题解决清楚优雅。
Java中提供了java.util.Stack类用于模拟一个Stack,但是设计的并不恰当:
1)Stack从Vector继承而来,多了很多不必要的方法,而且有的方法会破坏Stack的规则:如add(index,obj)
2)Vector是数组实现的,在push()pop()时候效率很低,应该使用链式结构
我们可以自己写一个:
public class Stack<T>{
private LinkedList<T> list = new LinkedList<>();
public void push(T t){list.addFirst(t);}
public T peek(){return list.getFirst();}
public T pop(){return list.removeFirst();}
public boolean empty(){return list.isEmpty();}
public String toString(){return list.toString();}
}
11.9Set
Set不保存重复的元素,最常用的功能就是测试是否包含对象,因此查找就成为了Set中最重要的操作,HashSet实现专门对快速查找进行了优化。
Set与Collection接口完全一致,只是行为不同(多态的特性)。Set是根据对象的值来决定归属性的。
11.10Map
把对象映射到其它对象的能力是解决很多问题的杀手锏。
遍历时可以返回键的set或者键值对的set
11.11Queue
队列是典型的先进先出FIFO容器,取出顺序与放入顺序一致。是一种可靠的把对象从程序的某个区域传输到另一个区域的途径。在并发编程中特别重要。
LinkedList提供了方法可以支持队列行为,并且也实现了Queue接口,所以它可以用作Queue的一种实现。
Queue<Integer> q = new LinkedList<>();
offer():插入队尾或返回false
peek()/element()返回队头,队列为空时peek返回null,element抛出NoSuchElementException
poll()/remove()返回队头并移除,队列为空时pool返回null,remove抛出NoSuchElementException
11.11.1PriorityQueue
队列规则:给定一组队列元素,确定下一个弹出元素的规则。先进先出是典型的一种队列规则。
优先级队列声明下一个弹出元素是优先级最高的元素。PriorityQueue在JavaSE5开始出现,默认元素顺序是按照自然顺序弹出,可以设置一个Comparator来控制这种优先级。
11.12Collection和Iterator
实现Collection接口就必须提供创建Iterator的方法,保证了通用能力。
11.13ForEach与迭代器
任何实现了Iterable接口的类,都可以在foreach中使用。数组和Collection类都可以使用。但Map不行。
11.13.1适配器方法惯用法
使用不同的方法产生不同的Iterator,用于不同的迭代方式。
11.14总结
Java提供了大量持有对象的方式:
1.数组,保存单一类型对象,可以是多维的,可以保存基本类型,但是容量不可变。
2.Collection保存单一元素,Map保存键值对。有了泛型不需要进行类型转换,不可持有基本类型但是会自动包装来处理,容量可变。
3.List也建立了数字和对象的关联,所以数组和List都是排序好的容器。List能自动扩容
4.大量随机访问用ArrayList,经常中间插入删除用LinkedList。
5.队列以及堆栈行为用LinkedList完成。
6.Map是一种将对象与对象相关联的设计。HashMap用于快速访问,TreeMap保持键始终处于排序状态,没有HashMap快。LinkedHashMap保持元素插入顺序,但是也通过散列提供了快速访问的能力。
7.Set不接受重复元素。HashSet提供最快查询速度,TreeSet保持元素处于排序状态,LinkedHashSet以插入顺序保存元素,查询也快。
8.不应该使用过时的Vector(同步效率慢,扩容时候翻倍ArrayList扩一半),HashTable(同步效率慢),Stack
集合框架图:
作者:superzhao
来源链接:https://www.cnblogs.com/superzhao/p/4820041.html
版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。
2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。