文章目录
- 元素的比较
- 基本类型的比较
- 对象的比较
- 如何进行对象比较
- 重写`equals`方法
- 基于`Comparble.compareTo`的比较
- 基于`Comparator.compare`的比较
- 区分`Comparator`和`Comparable`
- 在`PriorityQueue`中比较的体现
元素的比较
基本类型的比较
在Java
中,基本类型可以直接进行大小的比较
//1.基本元素的比较
int a=10;
int b=20;
System.out.println(a>b);
System.out.println(a<b);
System.out.println(a==b);
System.out.println("=============================");
char ch1='A';
char ch2='a';
System.out.println(ch1==ch2);
System.out.println(ch1>ch2);
System.out.println(ch1<ch2);
System.out.println("==========================");
boolean b1=true;
boolean b2=false;
System.out.println(b1==b2);
System.out.println(b1!=b2);
运行结果:
对象的比较
//2.对象的比较
Student s1=new Student();
Student s2=new Student();
Student s3=s2;
System.out.println(s1==s2);
//System.out.println(s1<s2);//编译报错
System.out.println(s3==s2);
运行结果:
结论:
Java
的引用类型不能直接进行>
或者<
的比较.那么为什么可以进行==
的比较呢?
因为:对于用户实现自定义类型,都默认继承自Object
类,而Object
类中提供了equals
方法,而==
默认情况下调用的就是equals
方法.
equal
的比较原则是:默认情况下,直接比较引用变量的地址**
如何进行对象比较
重写equals
方法
这里在Student
类中重写equals
方法
class Student{
String name;//姓名
Integer age;//年龄
public Student(String name,Integer age){
this.name=name;
this.age=age;
}
//重写equals方法
@Override
public boolean equals(Object o) {
if(o==null || !(o instanceof Student)) return false;
Student obj=(Student)o;
return this.name.equals(obj.name)?true:false;
}
}
//2.对象的比较
Student s1=new Student("zhangsan",11);
Student s2=new Student("zhangsan",12);
Student s3=s2;
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
//System.out.println(s1<s2); ------编译报错
System.out.println(s3==s2);
重写
equals
方法虽然可以进行比较,但是只能进行相等比较,不能按照大于,小于的方式进行比较
基于Comparble.compareTo
的比较
在类的内部重写compareTo
方法:
class Student implements Comparable<Student>{
String name;//姓名
Integer age;//年龄
public Student(String name,Integer age){
this.name=name;
this.age=age;
}
@Override
public int compareTo(Student o) {
if(o==null) return 1;
return age-o.age;
}
}
进行比较:
public class CompareTest {
public static void main(String[] args) {
Student s1=new Student("zhangsan",11);
Student s2=new Student("lisi",16);
Student s3=new Student("zhangsan",12);
System.out.println(s1.compareTo(s2));
System.out.println(s2.compareTo(s1));
System.out.println(s3.compareTo(s2));
}
}
运行结果:
基于Comparator.compare
的比较
在类的外部构造一个比较器Comparator
:
/**
* 在外部构造一个比较器
* */
class StudentComparator implements Comparator<Student>{
@Override
public int compare(Student s1, Student s2) {
return s1.age-s2.age;
}
}
class Student implements Comparable<Student>{
String name;//姓名
Integer age;//年龄
public Student(String name,Integer age){
this.name=name;
this.age=age;
}
}
调用比较器进行比较
Student s1=new Student("zhangsan",11);
Student s2=new Student("lisi",16);
Student s3=new Student("zhangsan",12);
//调用比较器
StudentComparator stuComparator=new StudentComparator();
System.out.println(stuComparator.compare(s1, s2));
运行结果:
区分Comparator
和Comparable
Comparator
和Comparable
都是Java
中用于比较的对象,但它们的作用场景和使用方式有所不同:
-
Comparable
接口:- 它是一个内置接口,通常由类自身实现,用于提供自定义类型的自然顺序。如果一个类实现了
Comparable
接口,那么它的实例就可以直接通过compareTo()
方法与其他同类实例进行比较。比如,String
类就是实现了Comparable<String>
,可以直接比较两个字符串的大小。 - 所以,
Compareable
接口需要手动实现,且代码的侵入性比较强,一旦实现,每次用该类都有顺序,属于内部顺序
- 它是一个内置接口,通常由类自身实现,用于提供自定义类型的自然顺序。如果一个类实现了
-
Comparator
接口:- 它是另一个独立于对象本身的接口,它允许你在运行时动态地改变比较规则。当需要对列表或其他集合进行排序,但不想修改类本身或者不知道对象内部如何排序时,可以使用
Comparator
。 - 需要实现一个比较器对象,对待比较类的侵入性弱.
- 它是另一个独立于对象本身的接口,它允许你在运行时动态地改变比较规则。当需要对列表或其他集合进行排序,但不想修改类本身或者不知道对象内部如何排序时,可以使用
在PriorityQueue
中比较的体现
由于PriorityQueue
底层使用的堆结构,因此其内部的元素必须要能够比大小,PriorityQueue
采用了两种比较方式的实现:
Comparable
:是类默认的内部比较方式,如果用户插入自定义类型的对象时,该类对象必须要实现Comparable
接口,并且重写了CompareTo
方法Comparator
:用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现Comparator
接口并且重写了compare
方法
接下来我们通过源码来进行理解:
当我们进行插入操作时:
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
siftUp(i, e);//向上调整
size = i + 1;
return true;
}
这里我们看到,调用了关键方法siftUp
向上调整方法.
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x, queue, comparator);
else
siftUpComparable(k, x, queue);
}