集合框架
集合:简单的说,集合就是一种容器。
集合作为一种容器,里面可以存放内容,存放的每个内容称为是元素(element)。
在整个集合框架里一共有2个大类容器:Collection和Map
Collection容器(interface)
Collection是元素类容器的根接口。
什么是容器
容器是一个用于存放东西的物件。
容器应该具备什么功能呢?(什么样的物件叫容器)
-
可以存东西
add(E element) //往容器里添加一个元素。元素可以是任意类型(整数,字符串,自定义类,容器)
addAll(Collection c) //往容器里添加多个元素。参数是一个容器,这个方法会把容器里的元素逐一添加进来
-
查看
size() //查看容器中包含多少元素
contains(Object o) //查看是否包含某个元素
containsAll(Collection c) //查看是否包含某些元素
isEmpty() //是不是一个空容器
-
可以提取(删除)东西
clear() //清空容器
remove(Object o) //移除一个元素
removeAll(Collection c) //移除参数容器中包含的元素
-
其他
equals(Collection c) //判断是否个另外一个容器相等。
toArray() //把容器转换为数组
List(interface)
list的英文含义是:列表。
list用于定义什么是有序容器。有序容器是容器的一种。
List是一个接口,它有一个父接口Collection。List相比于Collection多了下标的概念。用标可以去访问元素。
围绕下标提供了一堆方法:
-
添加元素
add(int index, E element) //在指定的位置添加一个元素
addAll(int index, Collection c) //在指定的位置添加多个元素删除元素
remove(int index) //移除指定位置的元素
-
获得子列表
subList(int fromIndex, int toIndex) //获取一个子列表 [formIndex, toIndex)
-
更新元素
set(int index, E element)// 把指定下标的元素更新为指定内容
-
获取元素的位置
indexOf(Object o) //获取指定元素的下标(正着查)
lastIndexOf(Object o)//获取指定元素的下标(倒着查)
get(int index) //获取指定下标的元素
List的实现类
ArrayList
ArrayList是List的实现类。既然是实现类,说明ArrayList实现了List中定义的所有方法。
-
如何创建一个ArrayList对象
ArrayList() //创建一个初始容量为10的列表。列表里尚未存放任何元素。
ArrayList(int capacity) //创建一个指定初始容量的列表。列表里尚未存放任何元素
初始容量: 列表刚创建时给定的容量。
Collection是个容器,这个容器与之前学过的数组不同,数组是定长的容器,不能减少容量也不能增加容量。但是Collection是一个变长的容器,空间不够的时候可以扩容。
ArrayList(Collection c) //创建一个包含参数中全部元素的列表。
-
ArrayList的使用
增删改查(API参考 List)
在创建ArrayList的时候必须指定元素的类型。例如:ArrayList
一旦指定ArrayList存放什么类型的数据,以后取元素的时候,无需进行类型转换。
-
遍历ArrayList
假定ArrayList内容如下:
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
遍历ArrayList的方法有很多,常用方式如下:
一、使用for循环遍历
for(int i = 0; i < list.size(); i++){
String str = list.get(i);
System.out.println(str);
}
使用list.size()获取元素个数, 从下标0开始循环到结束。通过list.get(i) 获取每个元素,达到遍历的效果。
二、使用迭代器遍历(推荐)
Iterator<String> it = list.iterator();//获取迭代器(迭代器会包含list中所有的元素)
while(it.hasNext()){
String str = it.next();//获取迭代器中的元素,next执行完,迭代器会指向下一个元素。
System.out.println(str);
}
Iterator是一个接口,规定了迭代器应该具有什么功能(hasNext(), next(), remove())。
hasNext()方法:用于查看是否还有元素。如果迭代器中还有元素,返回true,如果没有元素了,返回false。
next():获取当前迭代的元素,迭代器指向下一个元素。
remove(): 删除当前迭代到的元素。
三、使用for…each遍历元素
for(String str : list){
System.out.println(str);//str就是被遍历到的元素。
}
for…each是for循环的增强版,有些语言叫for…in
for…each的本质是通过迭代器遍历元素。可通过XJad反编译工具反编译.class文件查看源码。
ArrayList的优势和劣势
ArrayList的底层实现是数组,数组最大特点:数据的内存空间是连续的,所以根据下标查找元素是非常非常快。
弊端增加和删除慢,如果要删除下标为0的元素,实际上是通过循环,把下标为1的赋值给下标为0,把下标为2的赋值给下标为1的,以此类推,直到所有元素位置正确。
如果要在下标为0的位置添加一个元素,它也是通过循环实现的,最大下标的元素赋值给最大下标加1的位置,第2大的下标的元素赋值给最大下标,以此类推第0个元素赋值给第1个元素,新元素覆盖下标为0的元素。
List的另外一个实现类 LinkedList
LinkedList使用方式同ArrayList。
LinkedList与ArrayList不同,LinkedList底层靠的是双向链表在存储数据。
链表的特点:增删快,查询慢(需要遍历)。
List的另外一个实现类 Vector
实现方式和ArrayList几乎一模一样,Vector所有的方法是线程安全的。在线程里,如果不同的线程在访问同一个List(Vector),不会出现数据紊乱(内部加了锁,一个方法执行的时候,其他的方法等待,执行完以后,其他方法才开始执行)。因为考虑的安全性,不断的加锁和解锁,所以效率很低,速度很慢。
如何选择使用哪个List实现类?
-
看是否在多线程环境下访问。
是:Vector
否:转到2
-
看增删多还是查询多?
增删多:LinkedList
查询多:ArrayList
不知道:ArrayList
List list = new xxxx();
Set(interface)
set是一个接口,用于描述一个元素不重复的容器。set里面的重复元素只会出现一次。
首先set是一个容器,既然是容器,那么容器所应该具有的功能它都有。也就说Collection接口中定义的方法,Set里都要有。
通过查阅API,发现Set没有自己独有的方法,Set里所有的方法来自于Collection。
Set的实现类
HashSet (普通set)
HashSet的特点:
- 不重复
- 无序
注意:如果要往HashSet中添加自定义类型的数据,你需要给自定义的类添加equals方法,HashSet在添加元素的时候,会拿现有元素逐一和要添加的元素比较(用equals比较),如果相等了,就不添加,比较一遍之后没有相等的,把元素加进来。
HashSet的创建
-
HashSet() //创建一个空的Set,初始容量为16
-
HashSet(int capacity) //创建一个空的Set,初始容量为指定的容量。
-
HashSet(Collection c) //创建一set,初始内容是c中的元素(会去重)。
HashSet的添加和删除元素API见Set
HashSet没有获取元素的方法,也没有设置元素的方法。
如何取元素呢?—通过遍历来读取。
思考?
能否使用for循环遍历Set?-----不能!因为没有下标
HashSet的遍历
假定有如下Set:
Set<String> s = new HashSet<>();
s.add("zhangsan");
s.add("lisi");
s.add("wangwu");
s.add("zhaoliu");
-
使用for…each遍历
for(String str : s){ System.out.println(str);//str就是我们set中每个元素 }
-
使用Iterator遍历
Iterator<String> it = s.iterator(); while(it.hasNext()){ String str = it.next(); System.out.println(str); }
Set另外一个实现类 LinkedHashSet
LinkedHashSet是一个有序的不重复的容器。
特点如下:
- 有序(存放顺序有序)
- 不重复
小节
Collection是什么?
答:它是一个接口。用来描述容器应该具有哪些功能。(add,addAll,clear,remove,contains,size,iterator)
List是什么?
答:它是一个接口,这个接口继承了Colletion。用来描述一个有序的容器。有序指的是存放顺序。提供了下标的概念(index),围绕下标提供了一堆方法。(add(index,object),addAll(index,collection), remove(index),indexOf(object), lastIndexOf(object), get(index),set(index,object))
List的实现类有哪些?
ArrayList:底层是数组(内存空间连续),查询快,增删慢。
LinkedList:底层是链表,增删快,查询慢。
Vector:线程安全。
List的遍历方法:
for循环
for each
迭代器
Set是什么?
答:set是一个接口,继承于Collection。用来描述不重复的容器。
Set的实现类有哪些?
HashSet:无序不重复。要求容器里的元素实现了equals方法。
LinkedHashSet:有序不重复。有序指的是存放顺序。也需要元素实现equals放法。
TreeSet:有序不重复。有序指的是内容有序。
TreeSet 是一个Set的实现类
TreeSet是一个不重复的容器,而且内容有序。靠Comparable或者Comparator来实现比较,确定是否重复以及谁大谁小。
TreeSet有2大类创建方式:
- 自然排序。 元素本身带有比较方法(本质是元素实现了Comparable接口)
- 比较器排序。元素本身不具备比较的能力,比较帮元素比较大小。
TreeSet底层靠的二叉树来实现内容有序。小的元素放在树的左分支上,大的放在右分支上。读取元素时,TreeSet使用中序遍历的方式读取元素。
TreeSet添加元素以及删除元素和HashSet一样。
小节
Collection描述一个容器
List:有序容器,可重复
ArrayList: 数组
LinkedList: 链表
Vector:数组
Set:不可重复,通常是无序的。
HashSet:普通集合
LinkedHashSet:存放顺序有序,不可重复
TreeSet:内容有序,不可重读
Map(接口)
Map是用来描述一个容器,用来描述一个键值对容器。
Map的特点:键不允许重复。
Map和Colletion是平级的。Map数据键值对接口中的根接口。
-
添加元素到Map中
put(key, value) //往Map中存放元素,如果Map中已经有这个key了,会覆盖。如果Map中没有这个key,会把这个键值对存入map
putAll(Map map) //把另外一个map中的元素全部添加到当前map中,如果有key已经存在了,会产生覆盖。
-
移除元素
remove(key) //根据key移除对应的键值对。
-
修改元素
put(key, value) //如果Map中已经有这个key了,会覆盖. 如果没有就是添加
-
查看Map
size() //查看里面有多少键值对
containsKey(key) //查看是否有某个key
containsValue(value) //查看是否有某个value
get(key) //获取key对应的值。
keySet() //获取所有的key
values() //获取所有的value
entrySet //获取键值对集合
Map的实现类
HashMap
HashMap是一个普通的Map。
创建HashMap
- HashMap() 创建一个空的Map,初始容量是16, 加载因子是0.75
- HashMap(int capacity) 创建一个空的Map, 初始容量为指定的容量,加载因子是0.75
- HashMap(int capacity, float loadFactor) 创建一个空的Map,初始容量和加载因子由参数指定。
- HashMap(Map map) 创建一个包含指定键值对的Map。
HashMap的使用
增删改查 见Map的API
Map的遍历
假定有如下Map:
Map<String, Integer> map = new HashMap<>();
map.put("one", 100);
map.put("two", 88);
map.put("three", 96);
map.put("four", 88);
for each遍历
Set<String> keys = map.keySet();
for(String key : keys) {
System.out.println(key+ "----" + map.get(key));
}
使用迭代器遍历
Iterator<String> it = keys.iterator();
while(it.hasNext()) {
String key = it.next();
int value = map.get(key);
System.out.println(key + "===" + value);
}
for each遍历键值对
Set<Entry<String, Integer>> entries = map.entrySet();
for(Entry<String, Integer> e : entries) {
System.out.println(e.getKey()+ "__"+ e.getValue());
}
Entry是专门服务于Map的类。它代表键值对对象,内部含有键和值。如果要取出键和值,使用getKey()以及getValue().
Entry本质上Map中内部类。
迭代器遍历键值对
Iterator<Entry<String,Integer>> it2 = entries.iterator();
while(it2.hasNext()) {
Entry<String, Integer> e = it2.next();
System.out.println(e.getKey()+" "+e.getValue());
}
LinkedHashMap
存放顺序有序的Map。特点:存放顺序有序,键不能重复。
TreeMap
key的内容有序的Map。特点:key的内容有序,键不能重复。
HashTable
它与HashMap非常类似,只不过HashTable是线程安全的。