集合框架和泛型
集合框架
前面我们学过数组,我们知道数组一旦确定了数组长度,是不能再进行变更的,如果要存储总数不确定的对象,使用数组就不方便了。数组长度太少空间不够,太多浪费空间。如果并不知道程序运行会需要多少对象,或者需要更复杂方式存储对象,就可以使用java的集合框架。
Java集合框架提供了一套性能优良、使用方便的接口和类,他们位于java.util包中。
如图所示,里面涉及到了Iterator、Collection、List、Set、Map五个接口以及ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap、Collections、Arrays等8个类。
可以将集合框架分作4部分来看,分别是
1、Iterator接口
2、Collection接口及其List、Set子接口和其分别的实现类ArraysList、LinkedList、HashSet、TreeSet类
3、Map接口及其实现类HashMap、TreeMap类
4、Collections和Arrays这两个对集合进行算法的工具类
Collections类与Collection接口的名字虽然差不多,但并没有什么关系。Collection是List和Set接口的父接口,是整个集合框架的顶级接口,而Collections是提供了对集合进行排序、遍历等多种算法实现的一个算法工具类。
Collection接口
Collection接口是整个集合框架的父接口,是用来存放一组不唯一(可以重复)、无序的对象。他拥有List和Set两个子接口。Collection接口中有一些常用通用方法,其所有子类都可以继承使用。
(1) clear() 清空集合
(2)isEmply() 判断集合是否空集合
(3)iterator() 返回集合迭代器
(4)toArray() 把集合变成数组序列
在集合中,不能添加基本数据类型的数据,系统会自动把添加的基本类型数据包装成包装类,再存进集合中。
List接口
List接口是Collection接口的一个子接口,继承Collection接口。List接口用来存储一组不唯一(可以重复)、有序的对象。
如图所示,List接口与数组相似,但长度可变,里面存放的数据也是可以重复的。
List接口并不能实例化对象,所以它有两个常用的实现类:ArrayList、LinkedList。
遍历List集合的方法有以下三种:
(1)for循环
(2)foreach(增强型for)
(3)Iterator迭代器
ArrayList
ArrayList类是List接口的一个实现类,它实现了长度可变的数组,在内存中分配连续的空间。它和数组相似,所以ArrayList集合遍历元素和随机访问元素的效率比较高。
ArrayList中常用的方法如下:
返回值类型 | 方法名 | 说明 |
---|---|---|
boolean | add(Object o) | 在列表的末尾顺序添加元素,起始索引位置从0开始 |
void | add(int index , Object o) | 在指定的索引位置添加元素。索引位置必须介于0和列表中元素个数之间 |
int | size() | 返回列表中的元素个数 |
Object | get(int index) | 返回指定索引位置处的元素。取出的元素是Object类型,使用前需要进行强制类型转换 |
boolean | contains(Object o) | 判断列表中是否存在指定元素 |
boolean | remove(Object o) | 从列表中删除元素 |
Object | remove(int index) | 从列表中删除指定位置元素,起始索引位置从0开始 |
此外,还有Collection接口通用的方法:clear()、isEmpty()、iterator()、toArray()等
LinkedList
LinkedList类是List接口的另一个实现类,它采用链表存储方式,前一个元素中存放着后一个元素的内存地址。在内存中分配的空间并不像ArrayList一样连续。LinkedList在插入、删除元素时效率比较高,因为它只影响前后两个位置的元素,只需要更改前一位元素的内存地址指向。
LinkedList中常用的方法如下:
返回值类型 | 方法名 | 说明 |
---|---|---|
void | addFirst(Object o) | 在列表的首部添加元素 |
void | addLast(Object o) | 在列表的末尾添加元素 |
Object | getFirst() | 返回列表中的第一个元素 |
Object | getLast() | 返回列表中的最后一个元素 |
Object | removeFirst() | 删除并返回列表中的第一个元素 |
Object | removeLast() | 删除并返回列表中的最后一个元素 |
同样,也继承了Collection接口通用的方法:clear()、isEmpty()、iterator()、toArray()等
ArrayList和LinkedList的异同点
相同点:
1、都是集合框架中List的两个实现类
2、存放的数据都是有序的,可以通过get(int index)拿出来
不同点:
1、ArrayList遍历集合元素、随机访问元素的效率比较高,在这种需求下优先使用ArrayList集合
2、LinkedList插入、删除元素的效率比较高,在这种需求下优先使用LinkedList集合
Set接口
Set接口是Collection接口的一个子接口,继承Collection接口。Set接口用来存储一组唯一(不能重复)、无序的对象。Set接口采用对象的equals()方法比较两个对象是否相等,如果结果是true就不让对象加进来。
因为Set是接口,所以不能被实例化,HashSet是Set接口常用的实现类,而Set中存放对象的引用(内存地址)。因为Set接口是无序的,所以Set接口也不存在get()方法。
Set newsTitleSet = new HashSet();
NewTitle car =new NewTitle(1,"汽车","管理员");
//增加元素
newsTitleSet.add(car);
//获取元素个数
System.out.println("新闻标题数目为:"+newsTitleSet.size()+"条");
遍历无序的Set集合的方法有以下两种:
(1)foreach(增强型for)
for(Object obj : set){
System.out.println(obj);
}
(2)Iterator迭代器
--通过Collection接口的iterator()方法获取Iterator
--再使用Iterator的两个方法:
(boolean) hasNext(); 判断是否存在另一个可访问的元素
(Object) next(); 返回要访问的下一个元素
Iterator itor =set.iterator();
while(itor.hasNext()){
NewsTitle title = (NewsTitle)itor.next();
System.out.println(title.getId()+"-"+title.getTitle());
}
Map接口
Map接口不是Collection的子接口,也是一个顶级父接口,用来存储一组键值对象,提供key(键)到value(值)的映射
Map接口专门处理键值映射数据的储存,可以根据键实现对值的操作.最常用的实现类是HashMap.
Map中常用的方法:
返回值类型 | 方法名 | 说明 |
---|---|---|
Object | put(Key,Value) | 添加键值对(往map集合中) |
int | size() | 返回map集合的元素组(对)数 |
Object value | get(Key) | 通过键获得对应的值(输入集合中没有的键则返回null) |
boolean | containsKey(Key) | 判断map中是否包含某个键 |
boolean | containsValue(value) | 判断map中是否包含某个值 |
Object value | remove(Key) | 删除特定键对应的键值对,返回该值 |
Set | keySet() | 显示Map中键的集合 |
Collection | values() | 显示Map中值得集合 |
直接写变量名 | 显示map中键值对的集合 | |
void | clear() | 清空集合 |
boolean | isEmpty() | 判断集合是否为空 |
Set | entrySet() | 获得Map中所有键值对的集合 |
遍历Map集合的方法有三种:
(1)通过迭代器Iterator实现遍历
(2)增强型for循环
(3)键值对(Map.Entry)
前两种方法原理是相同的,都是先将Map中的键(Key)或值(value)分别包装成Set集合(键集合)或者Collection集合(值集合),再通过增强型for循环或者迭代器来遍历键集合对应的值或直接遍历值集合.
第三种键值对方法则是先遍历整个键值对集合,获得其中的每一个键值对,再分别提取出每一个键值对中的键或者值.每个键值对的类型为May.Entry类型
(1)迭代器Iterator遍历
Iterator iter = map.keySet().iterator();
while(iter.hasNext()){
String s = (String)iter.next();
System.out.println(map.get(s));
}
(2)增强型for循环遍历
for(Object o : map.keySet())
String s =(String)o;
System.out.println(map.get(s));
(3)键值对
Set set =map.entrySet()
for(Object o : set){
Map.Entry me =(Map.Entry)o;
Object key = me.getKey(); //取出键值对的键
object value = me.getValue(); //取出键值对的值
}
泛型
泛型是将对象的类型作为参数,指定到其他类或方法上,从而保证类型转换的安全性和稳定性.本质上是参数化类型
泛型集合
强制类型转换时容易出现异常问题.如:
List的get(int index)方法获取元素
Map的get(Object key)方法获取元素
Iterator的next()方法获取元素
在这些情况下返回的元素为Object类型,需要强制转换才能使用方法.这时候如果用泛型来改写集合框架中所有接口和类,就能解决强制转换容易出错的问题.
泛型集合可以约束集合内的元素类型,其中比较典型的泛型集合如:ArrayList < E>、HashMap<K,V>等.,其中< E >,<K,V>表示该泛型集合中的元素类型.泛型集合中的数据不再转换为Object类型,而是转换为指定的参数类型.除此之外,泛型集合和之前学习的集合的用法完全一样.
public class mapdemo {
public static void main(String[] args) {
Map<String, Student> map =new HashMap<String, Student>();
map.put("Tony", new Student("张三","男"));
map.put("Jack", new Student("李四","男"));
map.put("Rose", new Student("小花","女"));
System.out.println("Size:"+map.size());
//遍历map中的values
for(String s :map.keySet()) {
System.out.println(map.get(s));
}
//判断map中是否包含某键值对
System.out.println(map.containsKey("Jack"));
//移除一个键值对
map.remove("Tony");
System.out.println(map.get("Tony"));
System.out.println("-------------------------------------");
System.out.println("Size:"+map.size());
//iterator遍历map中的values
Iterator<String> iter = map.keySet().iterator();
while(iter.hasNext()) {
System.out.println(map.get(iter.next()));
}
System.out.println("-------------------------------------");
//values方法获取map中的值
Collection<Student> co =map.values();
for(Student s :co) {
System.out.println(s);
}
System.out.println("-------------------------------------");
//遍历map中每一个键值对Map.Entry
for(Map.Entry<String, Student> me :map.entrySet()) {
String s =me.getKey();
Student stu =me.getValue();
System.out.println(s+"-"+stu);
}
System.out.println(map);
}
}
Collections算法
Java集合框架将针对不同数据结构算法的实现都保存在工具类中.Collections定义了一系列用于操作集合的静态方法.
虽然Collection和Collections类名相似,但两者并不相同,前者是集合的父接口,后者是集合的操作类.
Collections提供的常用静态方法有如下几种:
(1)sort(); 排序
(2)binarySearch(); 查找集合中元素的位置(下标).找不到则返回负数.
(3)max()\min(); 查找最大\最小值
public static void main(String[] args){
List<Interger> numList =Arrays.asList(6,5,9,1,10,7);
for(Integer i : numList){
System.out.println(i);
}
Collections.sort(numList);
for(Integer i : numList){
System.out.println(i);
}
System.out.println("最大值是:"+Collections.max(numList));
}
对于一些无法进行排序的对象的集合,要实现这个类型的对象之间比较大小,该类型的类要实现Comparable接口,并重写compareTo()方法.
public class Student implements Comparable{
.....
public int compareTo(Object obj){
Student student = (Student)obj;
if(this.number == student.number){
return 0;
}else if(this.number > student.number){
return 1;
}else{
return -1;
}
}
}
实现了Comparable接口的类的对象就可以比较大小了.