一、Collections工具类
Collections
是一个提供对集合对象进行各种操作的静态方法的工具类,包括排序、搜索、线程安全化、同步控制等,Collections 工具类不能被实例化(构造函数私有化)。
Collections和Collection的区别:
Collection是接口,提供了对集合对象进行基本操作的通用接口方法,List、Set等多种具体的实现类
Collections是工具类,专门操作Collection接口实现类里面的元素
常见方法:
sort(List list):按自然排序的升序排序
sort(List list, Comparator c) :自定义排序规则,由Comparator控制排序逻辑,升序Comparator.naturalOrder()、降序Comparator.reverseOrder()
shuffle(List list):随机排序
reverse(List<?> list)
: 反转列表中元素的顺序。
max(Collection<? extends T> coll)
: 根据元素的自然顺序返回集合中的最大元素。
min(Collection<? extends T> coll)
: 根据元素的自然顺序返回集合中的最小元素。
二、Comparator排序接口
Collections工具类的获取最大元素 max(Collection coll)和获取最小元素 min(Collection coll)不适合对象比较,因为对象有多个属性,无法识别根据哪个属性来判断,需要自己自定义排序规则。
例如max方法:
Collections.max(list, new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return o1.getXX() - o2.getXX();
}
});
假设有个学生类,该学生类有属性姓名、年龄、身高,我们想要比较出哪个学生的年龄最大,我们可以实现一下:
public static void test(){
List<Student> list = new ArrayList<>();
list.add(new Student("张三",23,160));
list.add(new Student("李四",34,180));
list.add(new Student("王五",28,190));
list.add(new Student("小熊",16,170));
System.out.println(Collections.max(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//o1.getAge() 大于 o2.getAge(),那么返回值为正数,表示 o1 应该排在 o2 之后
//o1.getAge() 小于 o2.getAge(),那么返回值为负数,表示 o1 应该排在 o2 之前
return o1.getAge()-o2.getAge();
}
}));
}
运行结果:
Student{name='李四', age=34, height=180}
不止可以比较年龄,也可以实现比较身高的,其他的方法包括sort也可以自定义排序规则。
三、Comparable排序接口
Comparable是一个接口,定制排序规则,对实现它的每个类的对象进行整体排序,里面 compareTo 方法是实现排序的具体方法,String、Integer等类默认实现了这个接口,所以可以排序。
public interface Comparable<T> {
public int compareTo(T o);
}
compareTo方法:用于比较当前对象和传进来对象的大小,o为要比较的对象
返回int类型:
大于0, 表示this大于传进来的对象o ,则往后排,即升序
等于0,表示this等于传进来的对象o
小于0,表示this小于传进来的对象o
我们实战一下Comparable排序接口!
首先我们要先将Student类去实现一下Comparable接口,并实现Comparable接口的方法,我们比较的是身高属性:
@Override
public int compareTo(Student o) {
return this.getHeight()-o.getHeight();
}
接着在主函数方法中:
Set<Student> studentSet = new TreeSet<>();
studentSet.add(new Student("张三", 23, 180));
studentSet.add(new Student("李四", 34, 160));
studentSet.add(new Student("王五", 28, 150));
System.out.println(studentSet);
打印出来的结果是按照身高的升序来的:
[Student{name='王五', age=28, height=150}, Student{name='李四', age=34, height=160}, Student{name='张三', age=23, height=180}]
那么我们总结一下,如果类的自然排序逻辑就是所需要的排序方式,并且不会改变,那么应该实现Comparable
接口。而如果需要为类提供多种排序方式,那么应该使用Comparator
。因为Comparator
提供了更高的灵活性,它允许为同一个类定义多个不同的排序方式,并且可以用于比较任何对象。
四、JDK之重写HashCode和Equals
HashCode和Equals方法都于集合容器里面的对象比较,是 Object
类中的两个重要方法。
equals方法:默认情况下,Object
类中的 equals()
方法判断的是两个对象是否是同一个对象(即内存地址是否相同)。但在实际开发中,通常需要基于对象的属性值来判断对象是否相等,所以需要重写equals方法。
hashcode方法:
hashCode()
方法返回该对象的哈希码值。在哈希表结构中,hashCode()
用于确定对象的桶位置。
如果两个对象根据 equals(Object)
方法是相等的,调用这两个对象中任一对象的 hashCode
方法都必须产生相同的整数结果
如果两个对象根据 equals(Object)
方法是不相等的,那调用这两个对象中任一对象的 hashCode
方法不一定产生不同的整数(比如一个哈希函数是age%3,那么对于age是6跟9,它们的结果都是0)
当向集合中插入对象时,如何判别在集合中是否已经存在该对象,比如Set确保存储对象的唯一,并判断是不是同个对象呢?
依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法
判断两个对象是否一样,首先判断插入obj的hashcode值是否存在
hashcode值不存在则直接插入集合,值存在,比较完hashcode值,则还需判断equals方法判断对象是否相等