Collection与Map
20145217 《Java程序设计》第5周学习总结(2)
教材学习内容总结
程序中常有收集对象的需求
9.1collection架构
收集对象的行为,像是新增对象的add()
方法、移除对象的remove()
方法等,都是定义在java.util.collection
中。既然可以收集对象,也要能逐一取得对象,这就是java.lang.Iterable
定义行为,它定义了Iterator()
方法返回java.util.Iterator
操作对象。收集对象共同定义在Collection中
,然而根据收集对象会有不同的收集需求。Collection
继承架构设计图如下:
java.util.Set
:记录每个对象的索引顺序,并可依索引取回对象。java.util.List
:收集对象不重复,具有集合的行为。java.util.Queue
:收集对象时以队列方式,收集的对象加入至尾端,取得对象时从前端。java.util.Deque
:对Queue
的两端进行加入、移除等操作。
9.2具有索引的List
List
是一种Collection
,作用是收集对象,并以索引形式保留收集对象顺序。其操作类有java.util.ArrayList
和java.util.LinkedList
。ArrayList
和LinkedList
在性能上各有优缺点,都有各自所适用的地方,总的说来可以描述如下:
1.对
ArrayList
和LinkedList
而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList
而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList
而言,这个开销是统一的,分配一个内部Entry
对象。2.在
ArrayList
的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList
的中间插入或删除一个元素的开销是固定的。3.
LinkedList
不支持高效的随机元素访问。4.
ArrayList
的空间浪费主要体现在在list
列表的结尾预留一定的容量空间,而LinkedList
的空间花费则体现在它的每一个元素都需要消耗相当的空间
可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList
会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList
了。
Guest.java
:用的是ArryList
package cc.openhome;
import java.util.*;
import static java.lang.System.out;
public class Guest {
public static void main(String[] args) {
List names = new ArrayList();
collectNameTo(names);
out.println("访客名单");
printUpperCase(names);
}
static void collectNameTo(List names){
Scanner console =new Scanner(System.in);
while(true){
out.println("访客名称:");
String name=console.nextLine();
if(name.equals("quit")){
break;
}
names.add(name);
}
}
static void printUpperCase(List names){
for(int i=0;i<names.size();i++){
String name =(String)names.get(i);
out.println(name.toUpperCase());
}
}
}
运行结果:输入Tom
和Jack
9.3内容不重复的Set
同样是收集对象,在收集对象过程中若有相同对象则不再收集,若有这类需求可以用Set
接口的操作对象。Word.java
:
package word;
import java.util.*;
public class Word {
public static void main(String[] args) {
Scanner console=new Scanner(System.in);
System.out.println("请输入英文:");
Set words =tokenSet(console.nextLine());
System.out.printf("不重复的单子有%d个:%s%n",words.size(),words);
}
static Set tokenSet(String line){
String[] tokens=line.split(" ");
return new HashSet(Arrays.asList(tokens));
}
}
运行结果:
String
的split()
方法,可以指定切割字符串的方式,在这里指定空切割,split()
会返回String[]
,包括切割的每个字符串。
Students.java
:
package students;
import java.util.*;
class Student{
private String name;
private String number;
Student(String name,String number){
this.name=name;
this.number=number;
}
@Override
public String toString(){
return String.format("(%s,%s)", name,number);
}
}
public class Students {
public static void main(String[] args) {
Set students=new HashSet();
students.add(new Student("Justin","B835031"));
students.add(new Student("Monica","B835032"));
students.add(new Student("Justin","B835031"));
System.out.println(students);
}
}
由于没有告诉Set
什么样的students
实例才算重复的,所以显示结果为:
所加入hashCode()
与equals()
具体方法,重复的students
将不会收集。
即加入下片段:
@Override
public int hashCode(){
int hash=7;
hash=47*hash+Objects.hashCode(this.name);
hash=47*hash+Objects.hashCode(this.number);
return hash;
}
@Override
public boolean equals(Object obj){
if(obj==null){
return false;
}
if(getClass()!=obj.getClass()){
return false;
}
final Student other=(Student)obj;
if(!Objects.equals(this.name, other.name)){
return false;
}
if(!Objects.equals(this.number, other.number)){
return false;
}
return true;
}
运行结果:
Hashset
的操作概念是,在内存中开辟空间,每个空间会有一个哈希编码,这些空间成为哈希桶,如果对想要加入Hashset
,则会调用对象的hashCde()
取得哈希码,并尝试放入桶中,如果同中没有对象直接放入,如果有则调用对象的equals()
进行比较。比较结果为false
则收集,比较结果为true
则不予收集。
9.4队列操作Queue
如果希望收集对象时以队列方式,收集的对象加入至尾端,取得对象时从前端,则可使用Queue接口的操作对象。队列是一种特殊的线性表,它只允许在表的前端front
进行删除操作,而在表的后端rear
进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。在队列这种数据结构中,最先插入的元素将是最先被删除的元素;反之最后插入的元素将是最后被删除的元素,因此队列又称为“先进先出”FIFO—first in first out
的线性表。若对象有操作Queue
,并打算一队列的方式使用,且队列长度受限,通常建议使用offer()
、poll()
、peek()
等方法。
offer()
:用来在队列后端加入对象,成功返回true
,失败返回false
。poll()
:用来取出队列前端的对象,若队列为空则返回null
。peek()
:用来取得但不取出队列前端对象。
LinkedList
不仅操作了List
接口,也操作了Queue
的行为,所以可以将LinkedList
当队列来使用,Requetqueue.java
:
package requestqueue;
import java.util.*;
interface Request{
void execute();
}
public class Requestqueue {
public static void main(String[] args) {
Queue requests=new LinkedList();
offerRequestTo(requests);
process(requests);
}
static void offerRequestTo(Queue requests){
for(int i= 1;i<6;i++){
Request request =new Request(){
public void execute(){
System.out.printf("数据处理%f%n", Math.random());
}
};
requests.offer(request);
}
}
static void process(Queue requests){
while (requests.peek()!=null){
Request request=(Request) requests.poll();
request.execute();
}
}
}
运行结果为:
Deque
是Queue
的子接口,定义了在前端加入对象取出对象,在尾端加入对象取出对象。Queue
的行为与Deque
的行为有所重复,有几个操作是等义的:
二者对于offer()
、poll()
、peek()
等方法操作失败返回特定值,对于add()
、remove()
、element()
等方法操作失败会抛出异常。
课本第274页程序运行结果为:
堆栈结构是先进后出,所以最后才显示Justin
。
9.5使用泛型
泛型语法在设计API
时可以指定类或者方法支持泛型,而使用API
的客户端在语法上也会更简洁,并得到编译时期检查。这类API
在运用时,没有指定类型参数实际类型,程序代码中出现类型参数的地方,都会回归为使用Object
类型。
- 名称类旁出现角括号
<E
>,这表示支持泛型。E
是类型代号表示Element
,也可以用T
、K
、V
等代号。 - 由于使用
<E>
定义类型,在需要编译程序检查类型的地方,都可以使用E
,像是add()
方法必须传入的对象类型是E
。
9.6Lambda
表达式
Lambda
表达式虽然看着很先进,其实Lambda
表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。因为这就和某些很高级的黑客写的代码一样,简洁,难懂,难以调试。
9.7Iterable
与Iterator
iterator()
方法会返回java.util.Iterator
的接口操作对象,这个对象包括了Collection
收集的所有对象。Iterator
是迭代器类,而Iterable
是接口。 好多类都实现了Iterable
接口,这样对象就可以调用iterator()
方法,一般二者都是结合着用。
- 为什么一定要实现
Iterable
接口,为什么不直接实现Iterator
接口呢? - 看一下
JDK
中的集合类,比如List
一族或者Set
一族,都是实现了Iterable
接口,但并不直接实现Iterator
接口。 仔细想一下这么做是有道理的。
ForEach.java
:
package cc.openhome;
import java.util.*;
public class ForEach {
public static void main(String[] args) {
List names = Arrays.asList("Justin","monica","Irene");
forEach(names);
forEach(new HashSet(names));
forEach(new ArrayDeque(names));
}
static void forEach(Iterable interable){
for(Object o:interable){
System.out.println(o);
}
}
}
运行结果如下图:
9.8Comparable
与Comparator
Comparable & Comparator
都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator
是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义Comparator
接口的方法或在集合内实现Comparable
接口的方法。Comparator
位于包java.util
下,而Comparable
位于包java.lang
下。Comparable
是一个对象本身就已经支持自比较所需要实现的接口;Comparator
是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
9.9Map操作类
Map
提供了一个更通用的元素存储方法。Map
集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。从概念上而言,您可以将 List
看作是具有数值键的Map
。而实际上,除了List
和Map
都在定义java.util
中外,两者并没有直接的联系。Map设计架构:
- HashMap:在HashMap中建立键值对应后,键是无序的。
- TreeMap:键的部分会排序,条件是作为键的对象必须操作Comparable接口,或者创建TreeMap时指定操作Comparator接口对象。
- Properties:主要用于读取Java的配置文件,各种语言都有自己所支持的配置文件。
代码调试中的问题和解决过程
上传代码到git:
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第三周 | 300/600 | 2/6 | 20/50 | |
第四周 | 300/900 | 2/8 | 16/66 | |
第五周 | 300/1200 | 3/10 | 16/82 |
参考资料
Collection与Map的更多相关文章
- Java特性-Collection和Map
创建博客的目的主要帮助自己记忆和复习日常学到和用到的知识:或有纰漏请大家斧正,非常感谢! 之前面试,被问过一个问题:List和Set的区别. 主要区别很明显了,两者都是数组形式存在的,继承了Colle ...
- Java Collection或Map的同步
新集合也提供了能防止多个进程同时修改一个容器内容的机制.若在一个容器里反复,同时另一些进程介入,并在那个容器中插入.删除或修改一个对象,便会面临发生冲突的危险.我们可能已传递了那个对象,可能它位于我们 ...
- 【转】java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别
原文网址:http://www.360doc.com/content/15/0427/22/1709014_466468021.shtml java 容器类使用 Collection,Map,Hash ...
- Collection和Map
(1)Collection和Map的继承体系. (2)ArrayList(数组).LinkedList(链表).Vector(线程同步).Stack(继承Vector先进后出的栈).PriorityQ ...
- Java集合类根接口:Collection 和 Map
前言 在前文中我们了解了几种常见的数据结构,这些数据结构有着各自的应用场景,并且被广泛的应用于编程语言中,其中,Java中的集合类就是基于这些数据结构为基础. Java的集合类是一些非常实用的工具类, ...
- spark提示Caused by: java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Lscala.collection.immutable.Map;
spark提示Caused by: java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot b ...
- 初识Java集合框架(Iterator、Collection、Map)
1. Java集合框架提供了一套性能优良.使用方便的接口和类,它们位于java.util包中 注意: 既有接口也有类,图中画实线的是类,画虚线的是接口 使用之前须要到导入java.util包 List ...
- JAVA集合详解(Collection和Map接口)
原文地址http://blog.csdn.net/lioncode/article/details/8673391 在JAVA的util包中有两个所有集合的父接口Collection和Map,它们的父 ...
- Java集合框架(Collection Framework)学习之 Collection与Map概貌
写过Java的人都知道Java集合类,也用过Java集合类.Java集合类位于 java.util 这个包下,就像它的包名暗示的那样,Java集合类就是一套工具.它就像工匠的工具箱一样,它能给使用它的 ...
- 【Java】集合概述Collection、Map
Java集合分为Collection和Map,Collection又分为List.Set. List中有ArrayList.LinkedList和Vector:Set中又分为HashSet和TreeS ...
随机推荐
- iOS键盘监听的通知
#pragma mark - 键盘通知回调方法 // 监听键盘的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector: ...
- oracle两时间相减得到相差的时间
1.months_between(date1,date2);date1和date2相减得到相差的月份. select months_between(to_date('2015-05-11','yyyy ...
- 安装jdk源码
step1:打开选择Window->Preference step2:选择Java->Installed JREs step3:选中你所安装的jre,点击Edit,进入Edit JRE,如 ...
- python基础——偏函数
python基础——偏函数 Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function).要注意,这里的偏函数和数学意义上的偏函数不一样. 在介绍函 ...
- Innodb之表空间转移
我们可以将数据表转移到其他磁盘,以减弱单个磁盘的IO. 如 1创建一个表空间: 2修改表以使用新的表空间,如果表有大量数据,则会需要一些时间重建:所以会锁表一段时间: Note:会将原有的表空间删除, ...
- tomcat和apache区别联系
tomcat和apache区别联系 Apache是普通服务器,本身只支持html即普通网页.不过可以通过插件支持php,还可以与Tomcat连通(单向Apache连接Tomcat, 就是说通过Apac ...
- 【转】C语言快速幂取模算法小结
(转自:http://www.jb51.net/article/54947.htm) 本文实例汇总了C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速 ...
- Javaweb---Servlet过滤器
Servlet过滤器从字面上的字意理解为景观一层次的过滤处理才达到使用的要求,而其实Servlet过滤器就是服务器与客户端请求与响应的中间层组件,在实际项目开发中Servlet过滤器主要用于对浏览器的 ...
- iOS开发-正则表达式的使用方法
前言:在表单验证中,我们经常会使用到正则,因为我们需要用它来判断用户输入的字符是否为合法的,如果是不合法的,那么应该提示用户输入错误,并不让提交至服务器.我们也可以通过正则表达式,从用户输入的字符串中 ...
- git 提交代码的流程
[root@ok-T IT-DOC]# ls hx-海星-wifi.rd web收藏.txt [root@ok-T IT-DOC]# git status -s ?? "web\346\22 ...