集合框架
集合框架: 看成是学习一些Java中设计好的容器(装东西的)类;
- 如何创建容器对象;
- 如何把数据装到容器中—》 调用方法;
- 如何把容器中的数据取出—>还是调用方法;
下面是集合的整体框架图
List
ArrayList
语法特点
- 内部基于数组实现的一个集合类。查询比较快,添加和删除相对比较慢
- 猜ArrayList中会有哪些功能(方法): 添加、删除、查询、插入、修改。。。
- 不是同步的(存在线程安全问题),如何解决:敬请期待… 用Vector
基本使用
- 参考api一个一个写
- 三个构造函数
- 增删改查
- 数组和List相互转化
遍历方式
- 使用普通的for循环
ArrayList bag = new ArrayList();
bag.add("电脑");
bag.add(200);
bag.add("鼠标");
bag.add("小人书");
bag.add("教材");
bag.add("牛奶");
for(int i=0;i<bag.size();i++){
System.out.println(bag.get(i));
}
- 增强for循环(foreach)
语法:
for(源中的数据类型 变量名 : 源){
}
注意:源可以是数组或者集合(Iterable的实例)
- 使用迭代器进行遍历
Iterator 就是一个迭代器(也是一个接口)
其中的方法如下:
//boolean hasNext() 判断是否有下一个元素,如果返回true表示有下一个;
//Object next() 调用一次获得一个元素(每调用一次指针会向后移动一个);
//void remove() 会从迭代器指向的结合容器中删除一个元素
ArrayList bag = new ArrayList();
bag.add("电脑");
bag.add(200);
bag.add("鼠标");
bag.add("小人书");
bag.add("教材");
bag.add("牛奶");
//使用迭代器遍历集合ArrayList bag
// 获得一个迭代器
Iterator it = bag.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
- 双向迭代器
Iterator 单向的迭代器接口,从左到右依次获得数据,判断是否有下一个;获得下一个
|-- ListIterator 双向的迭代器接口,它的主要方法如下:
//Iterator中有的它也有;
//boolean hasPrevious() 判断是否有上一个;
//Object previous() 获得上一个元素;
ArrayList bag = new ArrayList();
bag.add("电脑");
bag.add(200);
bag.add("鼠标");
bag.add("小人书");
bag.add("教材");
bag.add("牛奶");
// 获得双向的迭代器
ListIterator iterator = bag.listIterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("------------------------------------------");
while(iterator.hasPrevious()){
System.out.println(iterator.previous());
}
LinkedList
语法特点
内部是基于双向链表结构实现的。添加和删除比较快,查询相对ArrayList比较慢
- 内部相对于ArrayList而言多了一些操作头和尾的方法
- 可以充当队列,堆栈
- 不是线程安全的(同步的)
总结:LinkedList底层是基于双向链表容器类,添加和删除比较快。查找和修改较慢。
基本使用
参照ArrayList 把ArrayList 改成 LinkedList
c. 遍历方式
参照ArrayList 把ArrayList 改成 LinkedList
Set
HashSet
语法特点:不重复,无序(不保证和添加顺序一致)
不能够添加重复元素
是否重复判断规则
-
判断重复的方式
a. 通过添加进去的元素的hashCode+eqauls 两者进行比较
b. 如果两个对象的hashCode相等 并且 两个对象调用equals结果是true 才认为两个元素重复 -
验证上面的规则
a. 打印上面示例中的元素的hashCode和equals的结果
b. 2 尝试自定义类,覆写hashCode 和 equals 这两个方法中的代码随便写
-
实际开发情况分析(重点)
a. 从上面的示例来看,结果两个都添加进去了,原因:hashCode不等,equals为false
b. 从业务上来看(需要向源码时代学生管理系统中添加两个学生信息),觉得这两天数据是同一个人
c. 应该怎么做: 在Student中覆写hashCode 和equals方法
d. 怎么覆写?
覆写的时候应该参考实际业务中的比较规则,例如姓名,年龄等(还得看Student类中有哪些字段,并且这些字段是业务人员判断的标准)
自动生成:
TreeSet
语法特点
无序:不保证(不记录)我们的添加顺序;但是可以保证添加里面元素是有序的。
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("catepillar");
set.add("momor");
set.add("bush");
set.add("cateprillar");
System.out.println(set);
}
不重复:不能够添加重复元素(多个心眼)如何判断重复的呢?
简单体验
-
体验1
结果: 虽然打印结果的顺序和添加顺序可能不一致,但是感觉结果是有某种规则排序的
说明String类也实现了Comparable接口,String对象可以调用compareTo方法 -
体验2
结果:居然不能够放不同的类型,但是编译没有错 -
体验3: 添加自定义的类的对象 Student对象
结果:
疑问1:上面的代码添加的都是同种类型的数据,为什么还报错;
疑问2:为什么提示要把Student转成Comparable
正常情况 ----》 TreeSet 或者 Comparable的文档
TreeSet的结构(存储原理)分析
自然排序与定制排序(比较器)
-
自然排序 Comparable
从TreeSet的API文档中点击 “自然排序” —》 Comparable接口中
文档中的描述:
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法理解:
如果一个类实现了Comparable接口,可以认为这个类的对象具有自然排序的能力(本质就是这个对象可以调用比较的方法compareTo),这种比较和排序的规则就是自然排序
-
定制排序(比较器)Comparator
根据上面的分析,如果我们的对象没有实现Comparable接口,感觉就无法添加到TreeSet中去;(这些对象就没有自然排序的能力);
上面的示例设计有点问题:Student类中覆写的compareTo方法按照年龄从小到大排列的,万一有的人也是用我们的Student,希望年龄从大到小进行排列,怎么办?
不管Student里面使用何种规则都不能满足所有的人
解决办法: 可以给TreeSet单独的提供一个比较器(理解为比较的一个工具)
Comparator 是一个比较器的接口(标准),必须得有进行比较的方法 :compare(Object o1,Object o2);
自定义一个类实现Comparator接口,其中写比较规则 —》 比较器的模板
我们现在需要的是一个具体的比较器对象
示例:
判断重复的标准
1、如果采用的是自然排序调用对象的compareTo方法,如果返回0 表示相等;
2、如果使用的定制排序(比较器),调用比较器的方法compare 返回0 表示相等;
Map
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map方法和存储结构
Map方法介绍
put(K key, V value) 在此映射中关联指定值与指定键。
如果key不存在,直接添加进去
如果key相同,value值使用最新的值替换key对应的老值.
put方法会返回 对应key对应的老值
boolean containsKey(Object key) 如果此映射包含对于指定键的映射关系,则返回 true。
boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true。
get(Object key) 返回指定键所映射的值。(通过键得到值)
Map特点
Map特点:
一个Map对象中不能有重复的键。
Map怎么判断重复?
-
通过put方法,put一次的时候,就是放两个参数,一个key,一个value,put方法相等于添加方法,在put的时候,判断当前放的这对(key-value)是否和里面已经存在的对(key-value) 是否已经重复, 只是在put的时候,放了两个参数,一个key和value,它判断重复,使用哪个参数?
-
使用key作为判断重复的标准.只拿key 和已经存在的一对一对key进行比较;就少拿了一个value而已;这个原理和HashSet,TreeSet一样。设计Map的时候,并没有说具体按照什么进行判断重复,而是通过实现类进行判断;
Map存储方式
Map的存储原理:
利用封装的,如果要封装,首先有个类型,这个类型是Entry,
Entry类型作用:Entry用来封装用户添加的一对数据.Entry类型有两个字段,添加的时候,使用Entry把两个值封装成一个对象,然后放到Map容器里面。对于Map而言,看到的只有Entry对象。
由于Entry的存在,只是对于Map来讲才有意义. 因此它使用封装,把Entry类型设计到Map里面。相当于内部类。
Map 里面的方法
entrySet() 返回Set,(返回当前Map中所有的entry对象,使用Set存储起来。)
keySet() 返回Map当中所有的key,存储到一个Set集合当中。
values() 返回所有的values,存储到一个Collection。
get(Object key) 返回Collection,通过key查找对应的值。
这里get方法为什么返回Collection?
因为values 有重复,如果返回Set,就不能含有重复的元素.
values方法
示例:利用Map来存储各位的姓名和年龄,比如
“小鹏鹏” – 18 ,最后计算本班级的平均年龄。
实现代码:
Map两种遍历方式
遍历Map 之 keyset方式
先得到所有key, 通过keySet方法取到;
然后遍历keySet,依次通过key来查找value。
通过Object get(Object key)方法;
遍历Map 之 Entry对象方式
先得到所有的Entry对象,Entry对象就包装了key,values;
遍历Entry对象的集合,然后依次从Entry对象中调用方法:getKey(),getValue()