Java高级API—集合框架和泛型
API(Application Programming Interface):应用程序编程接口
集合类有哪些
List:元素是有顺序的,元素可以重复因为每个元素有自己的角标( 索引)
ArrayList:底层的数据结构是数组结构,特点是:查询很快,增删稍微慢点, 线程不同步
LinkedList:底层使用的是链表数据结构,特点是:增删很快,查询慢。
Set:元素是无序的,且不可以重复(存入和取出的顺序不一定一致), 线程不同步 。 常用于数据的去重
HashSet:底层是哈希表数据结构 。根据hashCode和equals方法来确定元素的唯一性
Map:这个集合是存储键值对的, 一对一对往里存, 而且要确保键的唯一性
HashMap:底层是哈希表数据结构, 可以存入null键和null值, 线程不同步,效率较高
TreeMap:底层是二叉树数据结构, 线程不同步, 可以用于个map集合中的键进行排序
集合框架
- Collection 接口存储一组不唯一,无序的对象
- List接口存储一组不唯一,有序(插入顺序)的对象
- Set 接口存储一组唯一,无序的对象
- Map接口存储一组键值对象,提供Key到value的映射
List接口的实现类
- ArrayList实现了长度可变的数组,在内存中分配连续的空间,遍历元素和随机访问元素的效率比较高
- LinkedList采用链表存储方式,插入、删除元素时效率比较高
Java集合框架包含的内容2-1
Java集合框架提供了一套性能优良、使用方便的接口和类,他们位于java.util包中
Java集合框架包含的内容2-2
- Collection接口存储一组不唯一,无序的对象
- List接口存储一组不唯一,有序(插入顺序)的对象
- Set接口存储一组唯一,无序的对象
- Map接口存储一组键值对象,提供key到value的映射
List接口的实现类
- List
- ArrayList
- LinkedList
- ArrayList实现了长度可变的数组,在内存中分配连续的空间,遍历元素和随机访问元素的效率比较高
- LinkedList采用链表存储方式,插入、删除元素时效率比较高
ArrayList集合类2-1
- 新闻管理系统,需求如下
- 可以存储各类新闻标题(包含ID、名称、创建者)
- 可以获取新闻标题的总数
- 可以逐条打印每条新闻标题的名称
ArrayList集合类2-2
- 确定存储方式
- ArrayList类是List接口的一个具体实现类
- ArrayList对象实现了可变大小的数组
- 随机访问和遍历元素时,它提供更好的性能
- 确定存储对象
- 创建类型:新闻标题
- 包含属性:ID、名称、创建者
- 具体实现
import java.util.ArrayList;
import java.util.List;
public class Test01 {
public static void main(String[] args) {
//ArrayList list=new ArrayList();
//父类的引用指向子类的对象 List接口
List list1 = new ArrayList();
News n1 = new News(1, "核废水", "张三");
News n2 = new News(2, "抢海鲜", "李四");
News n3 = new News(3, "抢盐", "王五");
News n4 = new News(3, "抢盐", "王五");
list1.add(n1);//通过add方法向arraylist 集合中添加数据
list1.add(n2);
list1.add(n3);
// list1.size() 表示返回list1集合的长度
for (int i = 0; i < list1.size(); i++) {
//list1.get(i) get方法通过下标获取集合中的元素 get方法返回的是Object类
Object obj = list1.get(i);
//需要将获取到的Object转换成News
News n=(News) obj;
System.out.println(n.getTitle());
}
//使用增强for循环遍历
for (Object obj : list1) {
//list1.get(i) get方法通过下标获取集合中的元素 get方法返回的是Object类
//需要将获取到的Object转换成News
News n = (News) obj;
System.out.println("增强for"+n.getTitle());
}
//添加泛型 写对应类型的类名 泛型的类型不能是基本数据类型
//泛型只能指定一个
List<News> l=new ArrayList<News>();
//添加泛型后可以限制集合存储元素的类型 要么跟泛型一致要么是泛型的子类
l.add(n1);
l.add(n2);
l.add(n3);
//2. 添加泛型后 遍历获取数据不再是object类型 而是泛型类型的对象
for (News news:l){
System.out.println(news.getTitle());
}
System.out.println("l集合里是否包含n4"+l.contains(n4));
List<String> strs=new ArrayList<>();
strs.add("a");
strs.add("b");
strs.add("c");
strs.add("d");
//contains("a") 判断一个元素是否出现在集合中
System.out.println(strs.contains("a"));
}
}
import java.util.HashSet;
import java.util.Set;
public class Test03 {
public static void main(String[] args) {
Set<News> set=new HashSet<>();
News n1 = new News(1, "核废水", "张三");
News n2 = new News(2, "抢海鲜", "李四");
News n3 = new News(3, "抢盐", "王五");
News n4=n3;
News n5 = new News(3, "抢盐", "王五");
set.add(n1);
set.add(n2);
set.add(n3);
set.add(n4);
set.add(n5);
for (News n:set){
System.out.println(n.getTitle());
}
//set集合去重原理
//1. 判断新增元素的hash值是否跟集合内元素的哈希值一样
//2.继续调用对象的equals方法进行比较
}
}
ArrayList常用方法
方法名 | 说明 |
---|---|
boolean add(Object o) | 在列表的末尾顺序添加元素,起始索引位置从0开始 |
void add(int index,Object o) | 在指定的索引位置添加元素。索引位置必须介于0和列表中元素个数之间 |
int size() | 返回列表中的元素个数 |
Object get(int index) | 返回指定索引位置处的元素。取出的元素是Object类型,使用前需要进行强制类型转换 |
set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
boolean contains(Object o) | 判断列表中是否存在指定元素 |
boolean remove(Object o) | 从列表中删除元素 |
Object remove(int index) | 从列表中删除指定位置元素,起始索引位置从0开始 |
Collection接口常用通用方法还有:char()、isEmpty()、iterator()、toArray() |
public class ArrayListDemo01 {
public static void main(String[] args) {
//创建集合
ArrayList<String> array = new ArrayList<>();
//添加元素
array.add("heelo");
array.add("world");
array.add("java");
//public boolean remove(Object o):删除指定的元素,返回删除是否成功
//System.out.println(array.remove("world"));
//public E remove(int index):删除指定索引处的元素,返回被删除的元素 删除时索引不要越界 IndexOutOfBoundsException
//System.out.println(array.remove(1));
//public E set (int index,E element):修改指定索引处的元素,返回被修改的元素 修改时索引不要越界 IndexOutOfBoundsException
//System.out.println(array.set(1,"javaee"));
//public E get(int index):返回指定索引处的元素
// System.out.println(array.get(0));
// System.out.println(array.get(1));
// System.out.println(array.get(2));
// System.out.println(array.get(3));//索引越界异常
//public int size():返回集合中的元素个数
System.out.println(array.size());
//输出集合
System.out.println("array:" + array);
}
}
案例:存储字符串并遍历
需求:创建一个存储字符串的集合,存储3个字符串元素,使用程序实现在控制台遍历该集合
思路:
① 创建集合对象
② 往集合中添加字符串对象
③ 遍历集合,首先要能够获取到集合中的每一个元素,这个通过get(int index)方法实现
④ 遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
⑤ 遍历集合的通用格式
for(int i=0;i<集合对象.size();i++){
集合对象.get(i)就是指定索引处的元素
}
public class ArrayListTest01 {
public static void main(String[] args) {
//① 创建集合对象
ArrayList<String> arr=new ArrayList<>();
arr.add("张三");
arr.add("李四");
arr.add("王五");
//③ 遍历集合,首先要能够获取到集合中的每一个元素,这个通过get(int index)方法实现
for (int i = 0; i <arr.size() ; i++) {
String s=arr.get(i);
System.out.println(s);
}
for (String s : arr) {
System.out.println(s);
}
}
}
案例:存储学生对象并遍历
需求: 创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合
思路:
① 定义学生类
② 创建集合对象
③ 创建学生对象
④ 添加学生对象到集合中
⑤ 遍历集合,采用通用遍历格式实现
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class ArrayListTest02 {
public static void main(String[] args) {
//② 创建集合对象
ArrayList<Student> arr=new ArrayList<>();
//③ 创建学生对象
Student s1=new Student("张三",30);
Student s2=new Student("李四",33);
Student s3=new Student("王五",18);
//④ 添加学生对象到集合中
arr.add(s1);
arr.add(s2);
arr.add(s3);
//⑤ 遍历集合,采用通用遍历格式实现
for (int i = 0; i < arr.size() ; i++) {
Student s = arr.get(i);
System.out.println(s.getName()+","+s.getAge());
}
}
}
案例:存储学生对象并遍历
需求:创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合学生的姓名和年龄来自于键盘录入
思路:
① 定义学生类,为了键盘录入数据方便,把学生类中的成员变量都定义为String类型
② 创建集合对象
③ 键盘录入学生对象所需要的数据
④ 创建学生对象,把键盘录入的数据赋值给学生对象的成员变量
⑤ 往集合中添加学生对象
⑥ 遍历集合,采用通用遍历格式实现
public class ArrayListTest03 {
public static void main(String[] args) {
//② 创建集合对象
ArrayList<Student> arr=new ArrayList<>();
/*
//③ 键盘录入学生对象所需要的数据
Scanner scanner=new Scanner(System.in);
System.out.print("请输入学生姓名:");
String name=scanner.nextLine();
System.out.print("请输入学生年龄:");
String age=scanner.nextLine();
//④ 创建学生对象,把键盘录入的数据赋值给学生对象的成员变量
Student s=new Student();
s.setName(name);
s.setAge(age);
arr.add(s);*/
//为了提高代码复用性 用方法来改进程序
addStudent(arr);
addStudent(arr);
addStudent(arr);
for (int i = 0; i <arr.size() ; i++) {
Student student=arr.get(i);
System.out.println(student.getName()+","+student.getAge());
}
}
/*
两个明确:
返回值类型: void
参数: ArrayList<Student> array
*/
public static void addStudent(ArrayList<Student> arr){
//③ 键盘录入学生对象所需要的数据
Scanner scanner=new Scanner(System.in);
System.out.print("请输入学生姓名:");
String name=scanner.nextLine();
System.out.print("请输入学生年龄:");
String age=scanner.nextLine();
//④ 创建学生对象,把键盘录入的数据赋值给学生对象的成员变量
Student s=new Student();
s.setName(name);
s.setAge(age);
arr.add(s);
}
}
public class Student {
//① 定义学生类,为了键盘录入数据方便,把学生类中的成员变量都定义为String类型
private String name;
private String age;
public Student() {
}
public Student(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
LinkedList集合类2-1
- 新闻管理系统,需求如下
- 可以添加头条新闻标题
- 获取头条和最末条新闻标题
- 可以删除末条新闻标题
- 确定存储方式
- LinkedList类是List接口的一个具体实现类
- LinkedList类用于创建链表数据结构
- 插入或者删除元素时,它提供更好的性能
LinkedList常用方法
方法名 | 说明 |
---|---|
void addFirst(Object o) | 在列表的首部添加元素 |
void addLast(Object o) | 在列表的末尾添加元素 |
Object getFirst() | 返回列表中的第一个元素 |
Object getLast() | 返回列表中的最后一个元素 |
Object removeFirst() | 删除并返回列表中的第一个元素 |
Object removeLast() | 删除并返回列表中的最后一个元素 |
Set接口3-1
- Set接口存储一组唯一,无序的对象
- HashSet是Set接口常用的实现类
- Set中存放对象的引用
Set set=new HashSet();
String s1=new String("java");
String s2=s1;
String s3=new String("JAVA");
set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set.size());
Set接口3-2
- Set接口如何判断加入对象是否已经存在
- 采用对象的equals()方法比较两个对象是否相等
Set set=new HashSet(); String s1=new String("java"); String s2=new s1; String s3=new String("java"); set.add(s1); set.add(s2); set.add(s3); System.out.println(set.size());
Set接口3-3
- HashSet是Set接口常用的实现类
Set newsTitleSet=new HashSet();
NewTitle car=new NewTitle(1,"汽车","管理员");
//增加元素
newsTitleSet.add(car);
//获取元素个数
System.out.println("新闻标题数目为:"+newsTitleList.size()+"条");
Set接口不存在get()方法
newsTitleSet.get(0); //错误的
public class Test01 {
public static void main(String[] args) {
Set<String> set=new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
//ser.for 快捷生成
for (String s:set){
//冒号右边是要遍历集合的名字
// 左边声明一个变量接收遍历出来的元素
//变量类型和被遍历的集合的泛型一致 或是其子类
System.out.println(s);
}
}
}
迭代器Iterator (遍历各种集合)
- 如何变量Set集合?
- 方法1:通过迭代器Iterator实现遍历
- 获取Iterator:Collection接口的iterator()方法
- Iterator的方法
- boolean hasNext():判断是否存在另一个可访问的元素
- Object next():返回要访问的下一个元素
- 方法2:增强型for循环
- 方法1:通过迭代器Iterator实现遍历
public class Test01 {
public static void main(String[] args) {
Set<String> set=new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
//使用迭代器变量set集合
//创建迭代器
Iterator<String> i=set.iterator();//创建接口对象 set是创建的set集合的名字
// i.hasNext();//判断是否有值 返回值是布尔类型
// System.out.println(i.hasNext());
// i.next();//如果有值就使用次方法获取该值
//System.out.println(i.next());
while (i.hasNext()){
String str=i.next();
System.out.println(str+"这是使用迭代器的");
}
}
}
Map接口
- 建立国家英文简称和中文全名间的键值映射,并通过key对value进行操作,应该如何实现数据的存储和操作?
- Map接口专门处理键值映射数据的存储,可以根据键实现对值的操作
- 最常用的实现类是HashMap
Map接口常用方法
方法名 | 说明 |
---|---|
Object put(Object key,Object val) | 以"键-值"对的方式进行存储 |
Object get(Object key) | 根据键返回相关联的值,如果不存在指定的键,返回null |
Object remove(Object key) | 删除由指定的键映射的"键-值对" |
int size() | 返回元素个数 |
Set keySet() | 返回键的集合 |
Collection values() | 返回值的集合 |
boolean containsKey(Object key) | 如果存在由指定的键映射的"键-值对",返回true |
遍历Map集合
- 方法1:通过迭代器Iterator实现遍历
- 方法2:增强型for循环
- 方法3:键值对
练习1:根据学员英文名找到学员对象
- 需求说明
- 学员应聘至外企工作,每个学员都会有一个英文名称,对应该学员对象。2请实现通过英文名称,获得该成员对象的详细信息
- 学员属性包括姓名以及性别
- 学员应聘至外企工作,每个学员都会有一个英文名称,对应该学员对象。2请实现通过英文名称,获得该成员对象的详细信息
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;
}
}
public class Test04 {
public static void main(String[] args) {
Map<String,Student> map=new HashMap<>();
Student s1=new Student("狗胜","男");
map.put("Jack",s1);
System.out.println("Jack对应的学员姓名是"+map.get("Jack").getName()+map.get("Jack").getSex());
}
}
泛型集合
- 如何解决以下强制类型转换时容易出现的异常问题
- List的get(int index)方法获取元素
- Map的get(Object key)方法获取元素
- Iterator的next()方法获取元素
- 通过泛型
- JDK5.0使用泛型改写了集合框架中的所有接口和类
泛型
-
将对象的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性
- 本质是参数化类型
-
泛型集合可以约束集合内的元素类型
-
**典型泛型集合
ArrayList<E>
、HashMap<K,V>
<E>
、<K,V>
表示该泛型集合中的元素类型- 泛型集合中的数据不再转换为Object
除了指定了集合中的元素类型外,泛型集合和之前学习的集合的用法完全一样
Collections算法类
- Java集合框架将针对不同数据结构算法的实现都保存在工具类中
- Collection类定义了一系列用于操作集合的静态方法
Collections类常用方法
- Collections和Collection不同、前者是集合的操作类,后者是集合接口
- Collections提供的常用静态方法
- sort():排序
- binarySearch():查找
- max()\min():查找最大\最小值
Collections排序
- Collections类可以对集合进行排序、查找和替换操作
- 实现一个类的对象之间比较大小,该类要实现Comparable接口
- 重写compareTo()方法