目录
- 程序场景
- 分析
- Java集合框架包含的内容
- List接口
- ArrayList
- LinkedList
- List接口的常用方法
- ArrayList
- 案例背景
- 分析
- 代码示例
- 扩展以下功能
- 代码示例
- LinkedList
- 案例背景
- 分析
- 代码示例
- LinkedList的特殊方法
- ArrayList与LinkedList对比
- Set接口
- HashSet 集合的特点
- 常用方法
- 案例背景
- 分析
- 代码示例
- 遍历Set集合
- 迭代器
- 增强型for循环
- 语法
- 代码示例
- Map接口
- HashMap类的特点
- 常用方法
- 代码示例
- 集合在存取值时的类型转换问题
- 泛型
- Collections算法类
- 常用方法
- 排序
- 案例:
- 代码示例
- 新写法,学生类不需要实现接口
程序场景
- 问题1:程序中存储一个班的学员信息,假定一个班容纳20名学员?
答:Student[] student = new Student[20]; - 问题2:程序中如何存储每天的新闻信息?
News[] news = new News[?];
分析
- 分析以上问题,发现数组在存储对象数据时存在一些明显的缺陷:
- 数组长度固定不变,不能很好地适应元素数量动态变化的情况。
- 通过数组名.length获取数组的长度,却无法直接获取数组中实际存储的元素个数。
- 数组采用在内存中分配连续空间的方式存储,根据元素信息查找时效率比较低,需要多次比较。
- 针对数组的缺陷,Java提供了比数组更灵活、更实用的集合框架,可大大提高软件的开发效率,并且不同的集合可适用于不同的应用场合。
- 如果并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象——可以使用Java的集合框架
——可以使用Java的集合框架
Java集合框架包含的内容
List接口
ArrayList
ArrayList实现了长度可变的数组,在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高
打个比方:大家买票都排好队了,突然有个人要插队,插到前面去,那么后面所有的人都要向后退;同样中途有一个人走了,那么后面的人都要往前进,因此插入和删除的操作比较麻烦,但是查询比较简单,每人都有对应的一个号(索引),寻找的时候直接叫号就可以了。
LinkedList
LinkedList采用链表存储方式。插入、删除元素时效率比较高
这个跟自行车链条长了或者短了进行截断和添加是一样的原理,比较方便,但是找其中某一个结就麻烦了。
List接口的常用方法
ArrayList
案例背景
在电子宠物系统中如何存储多条狗子信息,获取狗子总数,逐条打印出各条狗子信息
分析
- 确定存储方式
- ArrayList类是List接口的一个具体实现类
- ArrayList对象实现了可变大小的数组
- 随机访问和遍历元素时,它提供更好的性能
- 确定存储对象
- 创建类型:狗狗类
- 包含属性: 昵称、健康值、亲密度、品种
代码示例
//创建四个狗子对象
… …
List<Dog> dogs = new ArrayList<>();
dogs.add(ououDog);
dogs.add(yayaDog);
dogs.add(meimeiDog);
dogs.add(2, feifeiDog); // 添加feifeiDog到指定位置
System.out.println("共计有" + dogs.size() + "条狗子。");
System.out.println("分别是:");
for (int i = 0; i < dogs.size(); i++) {
Dog dog = dogs.get(i);
… …
}
扩展以下功能
删除指定位置的狗狗,如第一个狗狗
删除指定的狗狗,如删除feifeiDog对象
判断集合中是否包含指定狗狗
代码示例
…
dogs.remove(0);
dogs.remove(feifeiDog);
…
if(dogs.contains(meimeiDog)){
System.out.println("集合中包含美美的信息");
} else
System.out.println("集合中不包含美美的信息");
}
LinkedList
案例背景
在电子宠物系统中,如何在任何位置(头部、中间、尾部)添加、获取、删除狗狗对象
分析
- 确定存储方式
- LinkedList类是List接口的一个具体实现类
- LinkedList 类用于创建链表数据结构
- 插入或者删除元素时,它提供更好的性能
- 确定存储对象
- 创建类型:狗狗类
- 包含属性: 昵称、健康值、亲密度、品种
代码示例
// 创建多个狗狗对象
… …
LinkedList<Dog> dogs = new LinkedList<>();
dogs.add(ououDog);
dogs.add(yayaDog);
dogs.addLast(meimeiDog);
dogs.addFirst(feifeiDog);
Dog dogFirst= (Dog)dogs.getFirst();
System.out.println("第一条狗狗昵称是"+dogFirst.getName() );
Dog dogLast= (Dog)dogs.getLast();
System.out.println("最后一条狗狗昵称是"+dogLast.getName());
dogs.removeFirst();
dogs.removeLast();
LinkedList的特殊方法
ArrayList与LinkedList对比
Set接口
Set 接口存储一组唯一,无序的对象,Set 接口常用的实现类:HashSet
HashSet 集合的特点
- 集合内的元素是无序排列且不允许重复。
- HashSet集合的查找效率高。
- 允许集合元素值为null。
常用方法
案例背景
电子宠物系统中,使用HashSet存储狗狗信息
分析
- 创建HashSet对象,并添加数据。
- 获取狗狗对象的总数。
- 判断集合中是否包含指定的对象。
- 移除指定对象。
- 判断集合是否为空。
- 遍历集合
代码示例
// 1、创建四个狗狗对象
Dog ououDog = new Dog("欧欧", "雪娜瑞");
Dog yayaDog = new Dog("亚亚", "拉布拉多");
Dog meimeiDog = new Dog("美美", "雪娜瑞");
Dog feifeiDog = new Dog("菲菲", "拉布拉多");
// 2、创建HashSet集合对象并把四个狗狗对象放入其中
Set<Dog> dogs = new HashSet<>();
dogs.add(ououDog);
dogs.add(yayaDog);
dogs.add(meimeiDog);
dogs.add(feifeiDog);
// 3、输出集合中狗狗的数量
System.out.println("共计有" + dogs.size() + "条狗狗");
System.out.println("美美是否存在:"+dogs.contains(meimeiDog));
dogs.remove(meimeiDog);
System.out.println("美美对象已经删除");
System.out.println("删除后,还有" + dogs.size() + "条狗狗");
System.out.println("集合是否为空:" + dogs.isEmpty());
遍历Set集合
迭代器
// 1、创建四个狗狗对象
// 省略创建狗狗对象的代码
// 2、创建HashSet集合对象并把四个狗狗对象放入其中
Set<Dog> dogs = new HashSet<>();
dogs.add(ououDog);
dogs.add(yayaDog);
dogs.add(meimeiDog);
dogs.add(feifeiDog);
// 3、使用iterator()获取Iterator对象
Iterator<Dog> iterator = dogs.iterator();
// 4、使用Iterator遍历集合
while (iterator.hasNext()) {
Dog dog = iterator.next();
System.out.println(dog.getName() + "\t" + dog.getStrain());
}
增强型for循环
语法
for(元素类型t 元素变量x : 数组或集合对象){
引用了x的java语句
}
代码示例
// 1、创建四个狗狗对象
Dog ououDog = new Dog("欧欧", "雪娜瑞");
Dog yayaDog = new Dog("亚亚", "拉布拉多");
Dog meimeiDog = new Dog("美美", "雪娜瑞");
Dog feifeiDog = new Dog("菲菲", "拉布拉多");
// 2、创建HashSet集合对象并把四个狗狗对象放入其中
Set<Dog> dogs = new HashSet<>();
dogs.add(ououDog);
dogs.add(yayaDog);
dogs.add(meimeiDog);
dogs.add(feifeiDog);
// 3、使用for增强语法遍历HashSet
for (Dog dog: dogs) {
System.out.println(dog.getName()+"\t"+dog.getStrain());
}
Map接口
Map接口存储一组键值对象,提供key到value的映射,Map接口常用的实现类HashMap
HashMap类的特点
- 不保证映射的顺序,特别是不保证顺序恒久不变
- 数据添加到HashMap集合后,所有数据的数据类型将转换为Object类型,所以从其中获取数据时需要进行强制类型转换
常用方法
代码示例
public class Animal {
public static void main(String[] args) {
Map<String,String> pet= new HashMap<>();
pet.put("丫丫","Q妹");
pet.put("菲菲","Q妹");
pet.put("欧欧","Q仔");
pet.put("美美","Q妹");
// 使用增强型for循环遍历Map
System.out.println("使用增强型for循环遍历,所有企鹅的昵称和品种分别是:");
for (Map.Entry<String,String> entry : pet.entrySet()) {
System.out.println(entry.getKey() + "\t\t" + entry.getValue() );
}
System.out.println("----------------------------------------------------");
// 使用Lambda表达式遍历Map
System.out.println("使用Lambda表达式遍历,所有企鹅的昵称和品种分别是:");
pet.forEach( (k, v) -> {
System.out.println(k + "\t\t" + v);
});
System.out.println("----------------------------------------------------");
//使用迭代器遍历Map
System.out.println("使用迭代器遍历,所有企鹅的昵称和品种分别是:");
Set<String> keys = pet.keySet(); //获取map集合中所有的key
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()){
System.out.println(pet.get(iterator.next()));
}
}
}
集合在存取值时的类型转换问题
如何解决以下强制类型转换时容易出现的异常问题
- List的get(int index)方法获取元素
- Map的get(Object key)方法获取元素
- Iterator的next()方法获取元素
泛型
- 泛型是JDK1.5的新特性。
- 泛型的本质是参数化类型:将所操作的数据类型指定为一个参数,使代码可以应用于多种类型。
- 泛型的定义:将对象的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性。
- 优点:
所有强制转换都是自动和隐式进行的,安全简单。
提高了代码的重用率
在集合中存储数据时进行严格类型审查,确保只有合适类型的对象才能存储在集合中。
从集合中检索对象时,减少了强制类型转换
Collections算法类
- Collections类是Java提供的一个集合操作工具类。
- Collections类定义了一系列用于操作集合的静态方法,用于实现对集合元素的排序、查找和替换等操作。
- Collections和Collection是不同的,前者是集合的操作类,后者是集合接口
常用方法
sort():排序
binarySearch():查找
max()\min():查找最大\最小值
…
排序
实现一个类的对象之间比较大小,该类要实现Comparable接口
- 重写 public int compareTo(T o)方法。
- 如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
案例:
学生类Student实现了Comparable接口,重写 compareTo(Student o)方法,通过比较学号实现对象之间的大小比较
代码示例
学生类实现接口
public class Student implements Comparable<Student>{
private String name;
private int age;
private int high;
... 省略setter/getter、toString和构造方法
@Override
public int compareTo(Student o) {
int result;
if(this.age == o.age){
result = o.high - this.high;
}else {
result = this.age - o.age;
}
return result;
}
}
测试
public class UserComparto {
static List studentList = new ArrayList<>();
static{
Student wanghao = new Student("王浩",24,175);
...创建多个对象
studentList.add(wanghao);
...添加多个
}
public static void main(String[] args) {
Collections.sort(studentList);
studentList.forEach(System.out::println);
}
}
新写法,学生类不需要实现接口
public class UserComparto {
static List<Student> studentList = new ArrayList<>();
static{
Student wanghao = new Student("王浩",24,175);
...
studentList.add(wanghao);
...
}
public static void main(String[] args) {
Collections.sort(studentList,new Comparator<Student>(){
@Override
public int compare(Student o1, Student o2) {
int result;
if(o1.getAge() == o2.getAge()){//优先按年龄排序,年龄相等就按身高
result = o2.getHigh() - o1.getHigh();
}else {
result = o1.getAge() - o2.getAge();
}
return result;
}
});
studentList.forEach(System.out::println);
}
}