java 集合框架
集合框架的介绍
我们在超市买东西的时候,如果没有购物车是不是会很麻烦呢?Java 中集合类是一种工具类,就是像购物车一样的容器,存储任意数量的具有共同属性的对象。
我们为什么要用集合呢?一个类的内部有许多相同类型的属性,并且他们的作用与意义是一样的,我们最好用一个类似容器的东西去盛放他们,在类的内部就变得井然有序。所以集合便是在类的内部,对数据进行组织的作用。这样我们便可以简单而快速地搜索大量的条目。有的集合接口,提供了一系列排列有序的元素,并且可以在序列中快速地插入或者删除有关元素。还有一些集合接口,提供了映射关系,可以通过关键字(key)去快速查找到对应的唯一对象,而这个关键字可以是任意类型。
集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大内容:对外的接口、接口的实现和对集合运算的算法。
Collection 接口
因为集合框架中的很多类功能是相似的,所以我们用接口来规范类。
Collection接口是java集合框架里的一个根接口。他也是List、Set和Queue 接口的父接口。Collection接口中定义了可用于操作List、Set和Queue的方法--增删改查
方法 | 返回值 | 说明 |
---|---|---|
add(E e) | boolean | 向collection的尾部追加指定的元素(可选操作) |
addAll(Collection<? extend E> c) | boolean | 将指定collection 中的所有元素都添加此collection中(可选操作) |
clear() | void | 移除此collection中的所有元素(可选操作) |
contains(Object o) | boolean | 如果此collection包含指定元素,则返回true |
containsAll(Collection<?> c) | boolean | 如果此collection包含指定collection的所有元素,则返回true |
equals(Object o) | boolean | 比较此collection与指定对象是否相等 |
hashCode() | int | 返回此collection的哈希码值 |
isEmpty() | boolean | 如果此collection不包含元素 则返回true |
iterator() | Iterator<E> | 返回在此collection的元素上进行迭代的迭代器 |
remove(Object o) | boolean | 移除此collection中出现的首个指定元素(可选操作) |
removeAll(Collection<?> c) | boolean | 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作) |
retainAll(Collection<?> c) | boolean | 仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作) |
size() | int | 返回此collection中的元素数 |
toArray() | Object[] | 返回包含此collection中所有元素的数组 |
toArray(T[] a) | <T> T[] | 返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同 |
List 接口 与 ArrayList 类
List是一个接口,不能实例化,需要一个具体类来实现实例化。List集合中的对象按照一定的顺序排放,里面的内容可以重复。List接口实现的类有:ArrayList(实现动态数组),Vector(实现动态数组), LinkedList(实现链表),Stack(实现堆栈).
List在Collection 基础上的方法
方法 | 返回值 | 说明 |
---|---|---|
add(int index, E element) | void | 在列表的指定位置插入指定元素(可选操作) |
addAll(int index, Collection<? extends E> c) | boolean | 将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作) |
get(int index) | E | 返回列表中指定位置的元素 |
indexOf(Object o) | int | 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1 |
lastIndexOf(Object o) | int | 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1 |
listIterator() | ListIterator<E> | 返回此列表元素的列表迭代器(按适当顺序) |
listIterator(int index) | ListIterator<E> | 返回此列表元素的列表迭代器(按适当顺序),从列表的指定位置开始 |
remove(int index) | E | 移除列表中指定位置的元素(可选操作) |
set(int index, E element) | E | 用指定元素替换列表中指定位置的元素(可选操作) |
subList(int fromIndex, int toIndex) | List<E> | 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图 |
今天我们主要来学习 java.util.ArrayList,ArrayList 类实现一个可增长的动态数组,它可以存储不同类型的对象,而数组则只能存放特定数据类型的值。
我们通过实际的例子来学习 ArrayList 吧!学校的教务系统会对学生进行统一的管理,每一个学生都会有一个学号和学生姓名,我们在维护整个系统的时候,大多数操作是对学生的添加、插入、删除、修改等操作。
先创建一个学生类:
/*
* 学生类
*/
public class Student {
public String id;
public String name;
public Student(String id, String name){
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
管理学生类:
import java.util.*;
public class ListTest {
//集合后面的<>代表泛型的意思
//泛型是规定了集合元素的类型
//我们以后会详细讲到
/**
* 用于存放学生的 List
*/
public List<Student> students;
public ListTest() {
this.students = new ArrayList<Student>();
}
/**
* 用于往 students 中添加学生
*/
public void testAdd() {
// 创建一个学生对象,并通过调用 add 方法,添加到学生管理 List 中
Student st1 = new Student("1", "张三");
students.add(st1);
// 取出 List 中的 Student 对象
Student temp = students.get(0);
System.out.println("添加了学生:" + temp.id + ":" + temp.name);
Student st2 = new Student("2", "李四");
students.add(0, st2);
Student temp2 = students.get(0);
System.out.println("添加了学生:" + temp2.id + ":" + temp2.name);
// 对象数组的形式添加
Student[] student = {new Student("3", "王五"), new Student("4", "马六")};
// Arrays 类包含用来操作数组(比如排序和搜索)的各种方法,asList() 方法用来返回一个受指定数组支持的固定大小的列表
students.addAll(Arrays.asList(student));
Student temp3 = students.get(2);
Student temp4 = students.get(3);
System.out.println("添加了学生:" + temp3.id + ":" + temp3.name);
System.out.println("添加了学生:" + temp4.id + ":" + temp4.name);
Student[] student2 = {new Student("5", "周七"), new Student("6", "赵八")};
students.addAll(2, Arrays.asList(student2));
Student temp5 = students.get(2);
Student temp6 = students.get(3);
System.out.println("添加了学生:" + temp5.id + ":" + temp5.name);
System.out.println("添加了学生:" + temp6.id + ":" + temp6.name);
}
/**
* 取得 List 中的元素的方法
*/
public void testGet() {
int size = students.size();
for (int i = 0; i < size; i++) {
Student st = students.get(i);
System.out.println("学生:" + st.id + ":" + st.name);
}
}
/**
* 通过迭代器来遍历
*/
// 迭代器的工作是遍历并选择序列中的对象,Java 中 Iterator 只能单向移动
public void testIterator() {
// 通过集合的 iterator 方法,取得迭代器实例
Iterator<Student> it = students.iterator();
System.out.println("有如下学生(通过迭代器访问):");
while (it.hasNext()) {
Student st = it.next();
System.out.println("学生" + st.id + ":" + st.name);
}
}
/**
* 通过 for each 方法访问集合元素
*
*/
public void testForEach() {
System.out.println("有如下学生(通过 for each):");
for (Student obj : students) {
Student st = obj;
System.out.println("学生:" + st.id + ":" + st.name);
}
//使用 java8 Steam 将学生排序后输出
students.stream()//创建 Stream
//通过学生 id 排序
.sorted(Comparator.comparing(x -> x.id))
//输出
.forEach(System.out::println);
}
/**
* 修改 List 中的元素
*
*/
public void testModify() {
students.set(4, new Student("3", "吴酒"));
}
/**
* 删除 List 中的元素
*
*/
public void testRemove() {
Student st = students.get(4);
System.out.println("我是学生:" + st.id + ":" + st.name + ",我即将被删除");
students.remove(st);
System.out.println("成功删除学生!");
testForEach();
}
public static void main(String[] args) {
ListTest lt = new ListTest();
lt.testAdd();
lt.testGet();
lt.testIterator();
lt.testModify();
lt.testForEach();
lt.testRemove();
}
}
上面的代码中,用到了 Arrays 类, Arrays 包含用来操作数组(比如排序和搜索)的各种方法,asList() 方法用来返回一个受指定数组支持的固定大小的列表。
List 有两种基本的类型,除了ArrayList外,还有LinkedList,LinkedList类用于创建链表数据结构,两者的对比如下:
- ArrayList:它擅长于随机访问元素,但是插入和移除元素很慢
- LinkedList: 它通过代价较低的在List中进行插入和删除操作,提供了优化的顺序访问,它在随机访问方面相对较慢,但是它的特性集较ArrayList更大。
Set接口 和 HashSet 类
Set接口也是Collection接口的子接口,它有一个很重要也是很常用的实现类————HashSet,Set是元素无序并且不包含重复元素的collection(List可以重复),被称为集。
HashSet由哈希表(实际上是一个HashMap实例)支持。它不保证set的迭代顺序;特别是它不保证该顺序恒久不变。
接下来我们同样通过代码的形式来详细看一看吧!
在上面我们实现了学生的管理,现在学生要做项目,每一个项目有一个组长,由组长来组织组员,我们便来实现项目组的管理
因为项目组的组长由一个老师担任,首先我们来创建一个 PD 类
import java.util.HashSet;
import java.util.Set;
/*
* 项目组长类
*/
public class PD {
public String id;
public String name;
//集合后面的<>代表泛型的意思
//泛型是规定了集合元素的类型
//我们以后会详细讲到
public Set<Student> students;
public PD(String id, String name){
this.id = id;
this.name = name;
this.students = new HashSet<Student>();
}
}
接下来我们便创建一个 SetTest 类,用来管理项目成员
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class SetTest {
public List<Student> students;
public SetTest() {
students = new ArrayList<Student>();
}
/*
* 用于往 students 中添加学生
*/
public void testAdd() {
//创建一个学生对象,并通过调用 add 方法,添加到学生管理 List 中
Student st1 = new Student("1", "张三");
students.add(st1);
//添加到 List 中的类型均为 Object,所以取出时还需要强转
Student st2 = new Student("2","李四");
students.add(st2);
Student[] student = {new Student("3", "王五"),new Student("4", "马六")};
students.addAll(Arrays.asList(student));
Student[] student2 = {new Student("5", "周七"),new Student("6", "赵八")};
students.addAll(Arrays.asList(student2));
}
/**
* 通过 for each 方法访问集合元素
* @param args
*/
public void testForEach() {
System.out.println("有如下学生(通过 for each):");
for(Object obj:students){
Student st = (Student)obj;
System.out.println("学生:" + st.id + ":" + st.name);
}
}
public static void main(String[] args){
SetTest st = new SetTest();
st.testAdd();
st.testForEach();
PD pd = new PD("1","张老师");
System.out.println("请:" + pd.name + "选择小组成员!");
//创建一个 Scanner 对象,用来接收从键盘输入的学生 ID
Scanner console = new Scanner(System.in);
for(int i = 0;i < 3; i++){
System.out.println("请输入学生 ID");
String studentID = console.next();
for(Student s:st.students){
if(s.id.equals(studentID)){
pd.students.add(s);
}
}
}
st.testForEachForSer(pd);
// 关闭 Scanner 对象
console.close();
}
//打印输出,老师所选的学生!Set 里遍历元素只能用 foreach 和 iterator
//不能使用 get() 方法,因为它是无序的,不能想 List 一样查询具体索引的元素
public void testForEachForSer(PD pd){
for(Student s: pd.students) {
System.out.println("选择了学生:" + s.id + ":" + s.name);
}
}
}
HashMap类
HashMap 是基于哈希表的 Map 接口的一个重要实现类。HashMap 中的 Entry 对象是无序排列的,Key 值和 value 值都可以为 null,但是一个 HashMap 只能有一个 key 值为 null 的映射(key 值不可重复)。
下面我们通过代码来学习 Map 中的方法吧。都有过选课经历吧,我们就用 Map 来管理课程吧
创建一个Course类
public class Course {
public String id;
public String name;
public Course(String id, String name){
this.id = id;
this.name = name;
}
}
创建一个MapTest类:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
public class MapTest {
/**
* 用来承装课程类型对象
*/
public Map<String, Course> courses;
/**
* 在构造器中初始化 courses 属性
* @param args
*/
public MapTest() {
this.courses = new HashMap<String, Course>();
}
/**
* 测试添加:输入课程 ID,判断是否被占用
* 若未被占用,输入课程名称,创建新课程对象
* 并且添加到 courses 中
* @param args
*/
public void testPut() {
//创建一个 Scanner 对象,用来获取输入的课程 ID 和名称
Scanner console = new Scanner(System.in);
for(int i = 0; i < 3; i++) {
System.out.println("请输入课程 ID:");
String ID = console.next();
//判断该 ID 是否被占用
Course cr = courses.get(ID);
if(cr == null){
//提示输入课程名称
System.out.println("请输入课程名称:");
String name = console.next();
//创建新的课程对象
Course newCourse = new Course(ID,name);
//通过调用 courses 的 put 方法,添加 ID-课程映射
courses.put(ID, newCourse);
System.out.println("成功添加课程:" + courses.get(ID).name);
}
else {
System.out.println("该课程 ID 已被占用");
continue;
}
}
}
/**
* 测试 Map 的 keySet 方法
* @param args
*/
public void testKeySet() {
//通过 keySet 方法,返回 Map 中的所有键的 Set 集合
Set<String> keySet = courses.keySet();
//遍历 keySet,取得每一个键,在调用 get 方法取得每个键对应的 value
for(String crID: keySet) {
Course cr = courses.get(crID);
if(cr != null){
System.out.println("课程:" + cr.name);
}
}
}
/**
* 测试删除 Map 中的映射
* @param args
*/
public void testRemove() {
//获取从键盘输入的待删除课程 ID 字符串
Scanner console = new Scanner(System.in);
while(true){
//提示输出待删除的课程 ID
System.out.println("请输入要删除的课程 ID!");
String ID = console.next();
//判断该 ID 是否对应的课程对象
Course cr = courses.get(ID);
if(cr == null) {
//提示输入的 ID 并不存在
System.out.println("该 ID 不存在!");
continue;
}
courses.remove(ID);
System.out.println("成功删除课程" + cr.name);
break;
}
}
/**
* 通过 entrySet 方法来遍历 Map
* @param args
*/
public void testEntrySet() {
//通过 entrySet 方法,返回 Map 中的所有键值对
Set<Entry<String,Course>> entrySet = courses.entrySet();
for(Entry<String,Course> entry: entrySet) {
System.out.println("取得键:" + entry.getKey());
System.out.println("对应的值为:" + entry.getValue().name);
}
}
/**
* 利用 put 方法修改 Map 中的已有映射
* @param args
*/
public void testModify(){
//提示输入要修改的课程 ID
System.out.println("请输入要修改的课程 ID:");
//创建一个 Scanner 对象,去获取从键盘上输入的课程 ID 字符串
Scanner console = new Scanner(System.in);
while(true) {
//取得从键盘输入的课程 ID
String crID = console.next();
//从 courses 中查找该课程 ID 对应的对象
Course course = courses.get(crID);
if(course == null) {
System.out.println("该 ID 不存在!请重新输入!");
continue;
}
//提示当前对应的课程对象的名称
System.out.println("当前该课程 ID,所对应的课程为:" + course.name);
//提示输入新的课程名称,来修改已有的映射
System.out.println("请输入新的课程名称:");
String name = console.next();
Course newCourse = new Course(crID,name);
courses.put(crID, newCourse);
System.out.println("修改成功!");
break;
}
}
public static void main(String[] args) {
MapTest mt = new MapTest();
mt.testPut();
mt.testKeySet();
mt.testRemove();
mt.testModify();
mt.testEntrySet();
}
}