-
Notifications
You must be signed in to change notification settings - Fork 14
Description
参考:
https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html
http://docs.oracle.com/javase/8/docs/api/
http://www.javatpoint.com/collections-in-java
http://www.runoob.com/java/java-collections.html
为什么使用集合框架?
开发应用程序中,如果想储存多个不同类型的数据,可以用数组来实现,但采用数组存在一些明显的缺陷:
- 数组长度固定不变,不能很好适应元素数量动态变化的情况;
- 可通过
数组名 .length获取数组长度,却无法直接获取数组中实际储存的元素个数;- 数组采用在内存中分配连续空间的储存方式,根据元素信息查找时效率低,需要多次比较。
Java 集合框架提供了一套性能优良、使用方便的接口和类,它们位于 java.util 包中。
- 虚线框表示接口(或者抽象类),实线框表示实现类,粗实线框表示开发中常用的类。
Java 的集合类主要由 Collection 接口和 Map 接口派生而来,其中 Collection 接口有两个常用的子接口( List 和 Set )。所以通常说 Java 集合框架由三大类接口构成( List 接口、 Set 接口、 Map接口)。 - 其中, Iterator 接口表示对集合进行迭代的迭代器。 Iterator 接口为集合而生,专门实现集合的遍历。
- 除了集合,该框架也定义了 Map 接口及其实现类。Map 里存储的是键/值对。尽管 Map 不是 Collections,但是它们完全整合在集合中。
- 为了方便的对 Collection 对象、 Array 对象进行操作,Java中提供了 Collections 工具类(集合操作工具类)和 Arrays 工具类对其进行操作。
其中 Arrays 和 Collections 中所有的方法都为静态的,以方便直接传入对象引用,执行相应的功能。http://blog.csdn.net/qq_29663071/article/details/51377334
Java 集合框架
List 接口存储一组不唯一,有序 (插入顺序)的对象:
| 0 | 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|---|
| aaaa | dddd | cccc | aaaa | eeee | dddd |
Set 接口存储一组唯一,无序的对象
eeee
aaaa
dddd cccc
Map 接口存储一组键值对象,提供 key 到 value 的映射
------- -------- -------
| CHN | | USA | | JPN |
------- ------- -------
| China | |America| | Japan |
------- ------- -------
- Collection 接口
- List 接口
- ArrayList 集合类(实现类):遍历元素和随机访问元素的效率比较高
- LinkedList 集合类(实现类):插入、删除元素时效率比较高
ArrayList 实现了长度可变的数组,在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高
| 0 | 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|---|
| aaaa | dddd | cccc | aaaa | eeee | dddd |
LinkedList 采用链表存储方式。插入、删除元素时效率比较高
ArrayList 集合类
参考:
http://docs.oracle.com/javase/8/docs/api/
http://tool.oschina.net/apidocs/apidoc?api=jdk-zh
实例一:展现 ArrayList 常用方法
/*(1)导入 ArrayList 集合类*/
import java.util.ArrayList;
public class ArrayList_Demo {
public static void main(String[] args){
/*(2)创建 ArrayList 对象,并添加数据。
使用 boolean add(Object o) 方法添加元素(注意:添加到集合中的数据将转换成 Object 类型)*/
ArrayList list = new ArrayList();
list.add("张三丰");
list.add("郭靖");
list.add("杨过");
list.add("Fatli");
/*(3)判断集合中是否包含“李莫愁”。
使用 boolean contains(Object o) 判断列表中是否存在指定元素*/
System.out.println(list.contains("李莫愁")); //输出 false
/*(4)把索引为 0 的数据移除;把 Fatli 移除。
使用 Object remove(int index) 从列表中删除指定位置的元素;
使用 boolean remove(Object o) 从列表中删除元素*/
list.remove(0);
list.remove("Fatli");
/*(5)把索引为 1 的元素替换为"黄蓉"。
使用 void set(int index,Object obj) 将index 索引位置的元素替换为 obj 元素;*/
list.set(1,"黄蓉");
/*(6)输出集合中所有的元素。
使用 Object get(int index) 返回指定索引位置处的元素(取出的元素是 Object 类型,使用前需要进行强制类型转换)
还使用 int size() 返回列表中的元素个数;*/
for(int i = 0;i < list.size();i++){
String name = (String)list.get(i);
System.out.print(name+" "); //输出:郭靖 黄蓉
}
/*使用增强 for 循环比普通 for 循环更加简单方便,而且不用考虑下标越界的问题。
for(Object obj:list){
String name = (String)obj;
System.out.println(name);
}
*/
/*(7)输出“小龙女”所在的索引位置。
使用 int indexOf(Object obj) 返回元素在集合中出现的索引位置*/
System.out.println(list.indexOf("小龙女")); //因集合中没有该元素,输出: -1
/*(8)清空 ArrayList 集合中的数据。
使用 void clear() 移除此列表中的所有元素*/
list.clear();
/*判断 ArrayList 集合中是否包含数据。
使用 boolean isEmpty() 判断 ArrayList 集合是否为空*/
System.out.println(list.isEmpty()); //输出: true
}
}多态:
上面(2)处ArrayList list = new ArrayList();也可以写成List list = new ArrayList();并导入 java.util.List 工具包。
这是将接口 List 的引用指向实现类 ArrayList 的对象,在编程中将接口的引用指向实现类的对象是 Java 实现多态的一种形式,也是软件开发过程中实现低耦合的方式之一。
实例二(实体类+实现类):新闻管理系统:1.可以储存各类新闻标题(包含 ID、名称、创建者);2.可以获取新闻标题总数;3.可以逐条打印新闻标题
package entity;
/**
* 实体类(同下 LinkedList_Demo 的实体类)
* @author Fatli
*/
public class NewsTitle {
private int id; //ID
private String titleName; //名称
private String creater; //创建者
public NewsTitle() { //无参构造方法
}
public NewsTitle(int id, String titleName, String creater) {//有参构造方法(构造方法重载)
this.id = id;
this.titleName = titleName;
this.creater = creater;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitleName() {
return titleName;
}
public void setTitleName(String titleName) {
this.titleName = titleName;
}
public String getCreater() {
return creater;
}
public void setCreater(String creater) {
this.creater = creater;
}
}package test;
import java.util.ArrayList;
import java.util.List;
import entity.NewsTitle;
public class ArrayList_Demo2 {
public static void main(String[] args) {
// 具体实现步骤
// 1、创建多个各类新闻标题对象
NewsTitle politics = new NewsTitle(1, "政治", "管理员");
NewsTitle economy = new NewsTitle(2, "经济", "管理员");
// 2、创建存储各类新闻标题的集合对象
List newsTitleList = new ArrayList();
// 3、按照顺序依次添加各类新闻标题
newsTitleList.add(politics);
newsTitleList.add(economy);
// 4、获取新闻标题的总数
System.out.println("新闻标题数目为:" + newsTitleList.size() + "条"); //输出:新闻标题数目为:2条
// 5、根据位置获取相应新闻标题、逐条打印每条新闻标题的名称,也就是我们常说的遍历集合对象
for (int i = 0; i < newsTitleList.size(); i++) {
NewsTitle title = (NewsTitle) newsTitleList.get(i);
System.out.print(i + 1 + ":" + title.getTitleName()+" "); //输出:1:政治 2:经济
}
}
}LinkedList 集合类
LinkedList 类是 List 接口( Collection 接口的子接口)的一个具体实现类
LinkedList 类用于创建链表数据结构
插入或者删除元素时,它提供更好的性能
LinkedList 常用方法:
| 方法名 | 说明 |
|---|---|
| void addFirst(Object o) | 在列表的首部添加元素 |
| void addLast(Object o) | 在列表的末尾添加元素 |
| Object getFirst() | 返回列表中的第一个元素 |
| Object getLast() | 返回列表中的最后一个元素 |
| Object removeFirst() | 删除并返回列表中的第一个元素 |
| Object removeLast() | 删除并返回列表中的最后一个元素 |
实例:增、删、获取头条/末条新闻标题
package entity;
/**
* 实体类(同上 ArrayList_Demo2 的实体类)
* @author Fatli
*/
public class NewsTitle {
private int id; //ID
private String titleName; //名称
private String creater; //创建者
public NewsTitle() { //无参构造方法
}
public NewsTitle(int id, String titleName, String creater) {//有参构造方法(构造方法重载)
this.id = id;
this.titleName = titleName;
this.creater = creater;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitleName() {
return titleName;
}
public void setTitleName(String titleName) {
this.titleName = titleName;
}
public String getCreater() {
return creater;
}
public void setCreater(String creater) {
this.creater = creater;
}
}package test;
import java.util.LinkedList;//util工具包
import entity.NewsTitle; //entity实体包
public class LinkedList_Demo {
public static void main(String[] args) {
/*(1)创建多个新闻标题。*/
NewsTitle politics = new NewsTitle(1,"政治","管理员");
NewsTitle economy = new NewsTitle(2,"经济","管理员");
NewsTitle technology = new NewsTitle(3,"科技","管理员");
NewsTitle entertainment = new NewsTitle(4,"娱乐","管理员");
/*(2)创建储存新闻标题的集合对象,并添加数据。
使用 boolean add(Object o) 方法添加元素(注意:添加到集合中的数据将转换成 Object 类型)*/
LinkedList newsTitleList = new LinkedList();
newsTitleList.add(politics); //政治
newsTitleList.add(economy); //经济
/*(3)添加头条新闻标题 和 末条新闻标题。
使用 void addFirst(Object o) 在列表的首部添加元素
使用 void addLast(Object o) 在列表的末尾添加元素 */
newsTitleList.addFirst(technology); //科技
newsTitleList.addLast(entertainment); //娱乐
/*(4)获取头条 及 最末条新闻。
使用 Object getFirst() 返回列表中的第一个元素
使用 Object getLast() 返回列表中的最后一个元素 */
NewsTitle first = (NewsTitle) newsTitleList.getFirst();
NewsTitle last = (NewsTitle) newsTitleList.getLast();
/*(5)删除头条和最末条新闻。
使用 Object removeFirst() 删除并返回列表中的第一个元素
使用 Object removeLast() 删除并返回列表中的最后一个元素*/
newsTitleList.removeFirst();
newsTitleList.removeLast();
/*遍历所有新闻标题。使用增强 for 循环。*/
for(Object obj : newsTitleList){
NewsTitle nt = (NewsTitle)obj;
System.out.print(nt.getTitleName()+" ");//输出:政治 经济
}
}
}Set 接口
Set 接口存储一组唯一(不重复),无序的对象
HashSet 是 Set 接口常用的实现类
Set 中存放对象的引用
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set set=new HashSet();
String s1=new String("java");
String s2=s1;
// String s3=new String("java"); //输出:1
String s3=new String("JAVA"); //输出:2
set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set.size());
}
}HashSet 集合类
HashSet 是 Java 集合框架提供的一个查找效率高的集合类。HashSet 是 Set 接口常用的实现类。
HashSet 集合类的常用方法:
| 方法 | 说明 |
|---|---|
| boolean add(Object o) | 如果此 Set 中尚未包含指定元素(因为 Set 存储的是唯一不重复的对象),则添加指定元素 |
| void clear() | 从此 Set 中移除所有元素 |
| int size() | 返回 Set 中的元素数量( Set 的容量) |
| boolean isEmpty() | 如果此 Set 不包含任何元素,则返回 true |
| boolean contains(Object o) | 如果此 Set 包含指定元素,则返回 true |
| boolean remove(Object o) | 如果指定元素存在于此 Set 中,则将其移除 |
Set newsTitleSet = new HashSet();
NewTitle car = new NewTitle(1, "汽车", "管理员");
// …… 继续增加元素
newsTitleSet.add(car);
// …… 继续获取元素个数
System.out.println("新闻标题数目为:" + newsTitleList.size() + "条");Set 接口不存在
get()方法,错误示范:newsTitleSet.get(0);思考为什么,以及怎样实现元素输出?——使用 Iterator 迭代器或者 for 循环遍历输出。
附:Java集合框架_hashCode() & equals()
Iterator 迭代器
Iterator 接口表示对集合进行迭代的迭代器。 Iterator 接口为集合而生,专门实现集合的遍历。
Iterator 接口的两个主要方法:
- boolean hasNext(): 判断是否存在下一个可访问的元素,如果仍有元素可以迭代,则返回 true。
- Object next(): 返回要访问的下一个元素。
另外,凡是由 Collection 接口派生而来的接口或者实现类,都实现了 iterate() 方法, iterator() 方法返回一个 Iterator 对象。
package entity;
/**
* 实体类(同上 ArrayListDemo2 、 LinkedList_Demo 一样的实体类)
* @author Fatli
*/
public class NewsTitle {
private int id; //ID
private String titleName; //名称
private String creater; //创建者
public NewsTitle() { //无参构造方法
}
public NewsTitle(int id, String titleName, String creater) {//有参构造方法(构造方法重载)
this.id = id;
this.titleName = titleName;
this.creater = creater;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitleName() {
return titleName;
}
public void setTitleName(String titleName) {
this.titleName = titleName;
}
public String getCreater() {
return creater;
}
public void setCreater(String creater) {
this.creater = creater;
}
}package test;
import java.util.HashSet;
import java.util.Iterator; //导入 Iterator 接口
import java.util.Set;
import entity.NewsTitle;
public class IteratorDemo {
public static void main(String[] args) {
// 1. 创建多个各类新闻标题对象
NewsTitle politics = new NewsTitle(1, "政治", "管理员");
NewsTitle economy = new NewsTitle(2, "经济", "管理员");
// 2. 创建存储各类新闻标题的集合对象
Set newsTitleList = new HashSet();
// 3. 按照顺序依次添加各类新闻标题
newsTitleList.add(politics);
newsTitleList.add(economy);
// 4. 获取新闻标题的总数
System.out.println("新闻标题数目为:" + newsTitleList.size() + "条"); //2
// 5. 使用 iterator() 方法获取 Iterator 对象
//凡是由 Collection 接口派生而来的接口或者实现类,都实现了 iterate() 方法, iterator() 方法返回一个 Iterator 对象
Iterator it = newsTitleList.iterator();
// 6. 使用 Iterator 遍历集合
//使用 Iterator 的 hasNext() 方法判断是否存在下一个可访问的元素;使用 Iterator 的 next() 方法返回要访问的下一个元素。
while(it.hasNext()){
NewsTitle title = (NewsTitle) it.next();
System.out.print(title.getTitleName()+" "); //输出:政治 经济(也可能输出:经济 政治。因为 Set 存储的是一组无序的对象 )
}
System.out.println("");
// 7. 方法二:使用增强型 for 遍历集合
for(Object obj:newsTitleList){
NewsTitle title = (NewsTitle)obj;
System.out.print(title.getTitleName()+" "); //输出:政治 经济(也可能输出:经济 政治。因为 Set 存储的是一组无序的对象 )
}
}
}Map 接口
Map 接口专门处理键值映射数据的存储,可以根据键实现对值的操作。
最常用的实现类是 HashMap
Map 接口的常用方法
| 方法名 | 说明 |
|---|---|
| Object put(Object key, Object value) | 以 “键-值” 对的方式进行存储 |
| Object get(Object key) | 根据键返回相关联的值,如果不存在指定的键,返回 null |
| Object remove(Object key) | 删除由指定的键映射的 “键-值对” |
| int size() | 返回元素个数 |
| Set keySet() | 返回键的集合 |
| Collection values() | 返回值的集合 |
| boolean containsKey(Object key) | 如果存在由指定的键映射的 “键-值对”,返回 true |
实例:建立国家英文简称和中文全名间的键值映射,并通过 key 对 value 进行操作
package test;
import java.util.HashMap;
import java.util.Map;
public class MapDemo {
public static void main(String[] args) {
// 1、使用 HashMap 存储多组国家英文简称和中文全称的键值对
Map countries = new HashMap();
countries.put("CHN", "中华人民共和国");
countries.put("USA", "美利坚合众国");
countries.put("JPN", "日本国");
// 2、显示"CHN"对应国家的中文全称
String country = (String) countries.get("CHN");
System.out.println("CHN 对应的国家是:" + country);
// 3、显示集合中元素个数
System.out.println("Map 中共有"+countries.size()+"组数据"); // 3
/*4、两次判断 Map 中是否存在 "USA" 键*/
System.out.println("Map 中包含 USA 的 key 吗?" +
countries.containsKey("USA")); //输出:Map 中包含 USA 的 key 吗?true
countries.remove("USA");
System.out.println("Map 中包含 USA 的 key 吗?" +
countries.containsKey("USA")); //输出:Map 中包含 USA 的 key 吗?false
/* 5、分别显示 键集、值集和键值对集*/
System.out.println(countries.keySet()); //输出:[CHN, JPN]
System.out.println(countries.values()); //输出:[中华人民共和国, 日本国]
System.out.println(countries); //输出:{CHN=中华人民共和国, JPN=日本国}
/* 3、清空 HashMap 并判断*/
countries.clear();
if(countries.isEmpty())
System.out.println("已清空Map中数据!");//输出:已清空Map中数据!
}
}泛型
将对象的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性,这就是泛型。泛型的本质就是参数化类型。
泛型的本质就是参数化类型,也就是说所操作的数据类型都被指定为一个参数,使代码可以应用于多种类型。简单来说, Java 语言引入泛型的好处是安全简单,且所有的强制转换都是自动和隐式的,提高代码的重用率。
泛型的定义语法:
类1或者接口<类型实参> 对象 = new 类2<类型实参>();实例一:
ArrayList<String> list = new ArrayList<String>();实例二:
//创建学员集合
ArrayList<Student> students = new ArrayList<Student>();
//创建学员类对象
Student student = new Student();
//创建诗类对象
Poem poem = new Poem();
//将两个对象添加到list集合中
students.add(student); //由于创建时已指定 Student 类型,所以这里会报错
students.add(poem); 泛型集合
JDK5.0 使用泛型改写了集合框架中的所有接口和类
泛型在集合中的应用:
例如在 List 接口中的 add() 方法的参数是 Object 类型,在通过 get() 方法取出集合中的元素时必须进行强制类型转换,还可能出现 ClassCastException 异常。另外, Map 接口中使用 put() 和 get() 方法存取对象时,使用 Iterator 接口的 next() 方法取元素时存在同样的问题。
使用泛型集合在创建集合对象时指定集合中元素的类型,从集合中取出时无需进行类型强制转换。如果把非指定类型对象放入集合,会出现编译错误。
List 和 ArrayList 的泛型形式是
List<E>和ArrayList<E>。<E>表示该泛型集合中的元素类型。
//省略 NewsTitle 实体类。 关键代码:
//使用泛型
List<NewsTitle> newsTitleList = new ArrayList();
//添加集合元素
newsTitleList.add(politics);
newsTitleList.add(economy);
//遍历输出新闻标题
for(NewsTitle nt : newsTitleList){
System.out.print(nt.getTitleName());
}
/*不再需要类型强制转换:
for(Object obj : newsTitleList){
NewsTitle nt = (NewsTitle)obj;
System.out.print(nt.getTitleName()+" ");//输出:政治 经济
}*/Map 于 HashMap 的泛型形式是
Map<K,V>和HashMap<K,V>。因为它们的每个元素都包含两个部分,即 key 和 value ,所以,在应用泛型时,要同时指定 key 的类型和 value 的类型。<K,V>表示该泛型集合中的元素类型,其中, K 表示 key 的类型, V 表示 value 的类型。
package entity;
public class Student {
private String name; // 学员姓名
private String sex; // 学员性别
public Student() {
}
public Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
//重写 toString() 方法
public String toString() {
return "Student [name=" + name + ", sex=" + sex + "]";
}
}package test;
import java.util.HashMap;
import java.util.Map;
import entity.Student;
public class HashMapDemo {
public static void main(String[] args) {
// 1.创建学员对象
Student student1 = new Student("权权", "男");
Student student2 = new Student("坪坪", "女");
// 2.创建保存“键-值对”的集合对象
Map<String,Student> students = new HashMap<String,Student>();
// 3.把英文名称与学员对象按照“键-值对”的方式存储在 HashMap 中
students.put("Fatli", student1);
students.put("Xenia", student2);
// 4.打印键集
System.out.println("键集:"+students.keySet()); //键集:[Fatli, Xenia]
// 5.打印值集
System.out.println("值集:"+students.values()); //值集:[Student [name=权权, sex=男], Student [name=坪坪, sex=女]]
//如果不在实体类 Student 添加(重写) toString() 方法,输出的是哈希值: [entity.Student@2e7227a8, entity.Student@48899e6a]
// 6.打印键-值对集合
System.out.println("键-值对集合:"+students); //键-值对集合:键-值对集合:{Fatli=Student [name=权权, sex=男], Xenia=Student [name=坪坪, sex=女]}
//如果不在实体类 Student 添加(重写) toString() 方法,输出的是哈希值:{Fatli=entity.Student@2e7227a8, Xenia=entity.Student@48899e6a}
// 7.判断是否存在“Fatli”这个键
String key = "Fatli";
if(students.containsKey(key)){
// 8.如果存在,根据键获取相应的值
Student student = students.get(key);
System.out.println("学员姓名:"+student.getName()); //学员姓名:权权
}
}
}泛型类、泛型接口、泛型方法
在集合中使用泛型只是泛型应用的其中一种,在类、接口、方法中也有着广泛的应用。
泛型类
泛型类,就是具有一个或者多个类型变量的类。
定义泛型类的的语法:
[访问修饰符] class className<TypeList>泛型接口
泛型接口,就是具有一个或者多个类型变量的接口。
定义泛型接口的的语法:
[访问修饰符] interface interface<TypeList>泛型方法
泛型方法,实际上就是带有类型参数的方法。
定义泛型方法的语法:
访问修饰符 <类型参数> 返回值 方法名 (类型参数列表)实例:
public <String> void showName (String s) {}