Java-Day-20( Collections 工具类 + 集合练习 )
Java-Day-20
Collections 工具类
介绍
- Collections 是一个操作 Set、List 和 Map 等集合的工具类 ( 仅有无参 )
- Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作
常用方法
排序操作 ( 均为 static 方法 )
- reverse(List):反转 List 中的元素顺序
- shuffle(List):对 List 集合元素进行随机排序
- sort(List):根据元素的自然顺序 ( 字符串 ) 对指定 List 集合元素按升序排序
- sort(List, Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- swap(List, int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
public static void main(String[] args) {
List list = new ArrayList();
list.add("zyz");
list.add("java");
list.add("duang");
// 反转
Collections.reverse(list);
System.out.println("list = " + list);
// 随机
Collections.shuffle(list);
// 字符串
Collections.sort(list);
// 指定
Collections.sort(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
// 可选择性加入 instanceof String 安全校验
// 按字符串长度大小
return ((String) o1).length() - ((String) o2).length();
}
});
System.out.println("list = " + list);
// 指定交换
Collections.swap(list, 0, 1);
System.out.println("交换后的 list = " + list);
查找、替换
public static void main(String[] args) {
List list = new ArrayList();
list.add("zyz");
list.add("java");
list.add("duang");
list.add("java");
// Object max(Collection)
System.out.println("返回自然顺序最大元素=" + Collections.max(list));
// Object max(Collection, Comparator)
Object maxObject = Collections.max(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
// 返回长度最大元素
return ((String) o1).length() - ((String) o2).length();
}
});
System.out.println("返回长度最大元素=" + maxObject);
// int frequency(Collection, Object)
System.out.println("java出现的次数=" + Collections.frequency(list, "java"));
// void copy(List dest, List src):将 src 内容复制到 dest 中
ArrayList dest = new ArrayList<>();
// 因为空间大小比较的是size,所以要给dest以size大小
// 注意:length 和 size 不同
for (int i = 0; i < list.size(); i++) {
dest.add("");
}
Collections.copy(dest, list);
// 若是拷贝空间不够存就会抛异常报错
System.out.println("拷贝list后的dest=" + dest);
// 替换 java 为 zyzjava
Collections.replaceAll(list, "java", "zyzjava");
System.out.println("替换操作后的list=" + list);
}
集合作业练习
一、
- 封装一个新闻类,包含标题和内容属性,提供 get、set 方法,重写 toString 方法,打印对象时只打印标题
- 只提供一个带参数的构造器,实例化对象时,只初始化标题,并实例化两个对象:新闻一标题:新冠确诊病例超千万,数百万印度教信徒赴恒河“圣浴”引民众担忧;新闻二标题:男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生
- 将新闻对象添加到 ArrayList 集合中,并且进行倒序遍历
- 在遍历集合过程中,对新闻标题进行处理,超过 15 字的只保留前 15 个,后面就加 " … ”
- 在控制台打印遍历出经过处理的新闻标题
public class test1 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add(new News("新冠确诊病例超千万,数百万印度教信徒赴恒河\"圣浴\"引民众担忧")); // 注意转义字符
arrayList.add(new News("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生"));
int size = arrayList.size();
for (int i = size - 1; i >= 0; i--) {
// System.out.println(arrayList.get(i));
News news = (News) arrayList.get(i);
System.out.println(processTitle(news.getTitle()));
}
}
// 写一个方法处理标题
public static String processTitle(String title) {
if (title == null) {
return "";
} else if (title.length() > 15) {
return title.substring(0, 15) + " ... "; // 前闭后开
} else {
return title;
}
}
}
class News {
private String title;
private String content;
public News(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
// 此处为简洁省略了全部的set和get方法
@Override
public String toString() {
return "News{" +
"title='" + title + '\'' +
'}';
}
}
二、
使用 ArrayList 完成对对象 Car { name, price } 的各种操作
Car car = new Car("宝马", 400000);
Car car2= new Car("宾利",5000000);
- add:添加单个元素
- remove:删除指定元素 ( 元素对象 )
- contains:查找元素是否存在
- size:获取元素个数
- isEmpty:判断是否为空
- clear:清空
- addAll:添加多个元素
- containsAll:查找多个元素是否都存在
- removeAll:删除多个元素 ( 接口实现类型 )
使用增强for和迭代器来遍历所有的car
public class test2 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
Car car = new Car("宝马", 400000);
Car car2= new Car("宾利",5000000);
Car car3= new Car("别克",80000);
arrayList.add(car);
arrayList.add(car2);
arrayList.add(car3);
arrayList.remove(0); // 删除索引:0 (第一个位置)处对象
arrayList.remove(car2); // 也可以指定删除某对象
System.out.println(arrayList.size()); // 1
System.out.println(arrayList.isEmpty()); // F
// arrayList.clear(); // 清空
arrayList.addAll(arrayList); // 集合可以自己放自己
System.out.println(arrayList.containsAll(arrayList)); // T 查找多个元素是否存在,放的是Collection接口实现类
// arrayList.removeAll(arrayList); // 删除多个元素,放的是 Collection接口实现类
System.out.println(arrayList);
for (Object o : arrayList) {
System.out.println(o);
}
Iterator iterator = arrayList.iterator(); // 勿忘前提获取
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
}
}
class Car {
private String name;
private double price;
public Car(String name, double price) {
this.name = name;
this.price = price;
}
// set、get 方法。。。
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
三、
- 使用 HashMap 类实例化一个 Map 类型的对象 m,键 ( String ) 和值 ( int ) 分别用于存储员工的姓名和工资,存入数据如下: jack-650 元;tom-1200 元;smith-—--2900 元;
- 将 jack 的工资更改为 2600元
- 为所有员工工资加薪 100 元
- 遍历集合中所有的工资
public class test3 {
public static void main(String[] args) {
Map m = new HashMap();
m.put("jack", 650); // 有自动装箱:int — Integer
m.put("tom", 1200);
m.put("smith", 2900);
System.out.println(m);
// 更新就可以理解为替换,直接输入同k不同v
m.put("jack", 2600);
// F1:T
// 利用keySet得到每个键,然后循环改值
Set keySet = m.keySet();
for (Object key : keySet) {
// 利用put的替换机制完成更新
m.put(key, (Integer)m.get(key) + 100);
}
// F2:F?
// 只获取每个值并不能对每个值进行根本上的修改,因为keySet、values本是为了方便遍历查看,修改还得是put替换
// Collection values = m.values();
// for (Object o : collection) {
// o = (Integer) o + 100;
// System.out.println(o);
//// 只是循环显示的改了,实际上原数并无变化
// }
// F3:T
// 或者是用entrySet直接拿到所有
// Set entrySet = m.entrySet();
// Iterator iterator = entrySet.iterator();
// while (iterator.hasNext()) {
// Map.Entry entry = (Map.Entry)iterator.next();
// entry.setValue((Integer)entry.getValue() + 100);
// }
Collection values = m.values();
for (Object value : values) {
System.out.println("遍历所有工资 = " + value);
}
System.out.println(m);
}
}
四、
HashSet 和 TreeSet 去重机制的
-
HashSet:hashCode() + equals(),底层运算得 hash 值来找索引处存放,若是有数据的话就进行 equals 遍历比较 ( 默认看字符串,最好由程序员来决定 ),比较后不相同就加入
-
TreeSet:传入 Comparator 匿名对象,就实现 compare 去重,返回 0 就表示重复不添加;没传入 Comparator 的话就以添加的对象 ( 常见 String ) 实现的 Comparable 接口内的 compareTo 完成去重
五、
分析下面代码是否会抛出异常
// main:
TreeSet treeSet = new TreeSet();
treeSet.add(new Person());
// 类中无任何操作
class Person { }
-
会抛出异常:ClassCastException
-
因为无参的话会调用 compare():
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2) : comparator.compare((K)k1, (K)k2);
,而(Comparable<? super K>)k1
中 k1 即 Person 类无法上转成 Comparable 接口,更无 compareTo(),则抛异常 -
解决方法之一为改写 Person:( 即便返回 0 也只会导致只能添加一个而不会再报错 )
class Person implements Comparator { @Override public int compare(Object o1, Object o2) { return 0; } }
六、
查看代码输出:( 已知 Person 类按照 id 和 name 重写了 hashCode 和 equals 方法 )
public class test6 {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
Person p1 = new Person(1001, "AA");
Person p2 = new Person(1002, "BB");
hashSet.add(p1);
hashSet.add(p2);
p1.name = "CC";
hashSet.remove(p1); // 1.
System.out.println(hashSet);
hashSet.add(new Person(1001, "CC")); // 2.
System.out.println(hashSet);
hashSet.add(new Person(1001, "AA")); // 3.
System.out.println(hashSet);
}
}
class Person {
private int id;
public String name;
public Person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
-
输出为:
- [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]
- [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}]
- [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
-
分析:
- 重写前:hash = 1020382489
- 重写后:hash = 34072
- 重写了 hashCode 方法,所以 map.put 后 hash() 计算操作 ( 根据 key.hashCode() )
- key.hashCode() 调用的就是 Person 里重写的方法
- 重写方法里返回 Object.hash 又是返回 Arrays.hashCode ...... 等完成哈希值的计算
- 这样就是根据对象的 " 属性值 " 计算哈希值,和对象地址就无关了
- 处因为重写,所以 remove 删的是 (1001, "AA") 索引处的值,(1001, "AA") 索引处还是存着 (1001, "CC")
- add 是把 (1001, "CC") 正确得放进了其索引处 ( 此时两个 CC,一个是因为更改值,一个是正确索引存储 )
- add 存放 (1001, "AA") 索引查找时有 CC 占位了,但两者 hash 不同所以 (1001, "AA") 直接放在了链尾
-
不重写 hashCode 和 equals 方法的话 ( 或只重写 equals 的话 ),输出为:
- [Person{id=1002, name='BB'}]
- 同地址,哈希值相同 remove 照样删
- [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]
- [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
- [Person{id=1002, name='BB'}]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App