Java内部比较器与外部比较器+匿名内部类详细讲解

文章目录

  • 一.比较器的定义
  • 二.什么是内部比较器与外部比较器?
  • 三.为什么需要两种比较器呢?
  • 四.Comparable内部比较器
    • 4.1 int类型比较:
    • 4.2 String类型比较:
    • 4.3 double类型比较
  • 五.Comparator外部比较器
  • 六.外部比较器与匿名内部类结合应用
  • 七.总结:

引言:在Java中提到比较二字,我们自然会想到equals()方法来比较两个数值是否相等,但这仅仅是对数值的操作,对其他数据类型就无法比较,因此用Comparator或者Comparable比较顺序(也就是排序)。

一.比较器的定义

确定两个对象之间的大小关系及排列顺序称为比较,能实现这个比较功能的类或方法称之为比较器

二.什么是内部比较器与外部比较器?

  • 内部比较器是comparable接口
  • 外部比较器是comparator接口

三.为什么需要两种比较器呢?


四.Comparable内部比较器

4.1 int类型比较:

首先,我们想要比较int类型的数,只需要两个数做差,如果差大于0,则a大于b;如果差小于0,则a小于b。

4.2 String类型比较:

接下来再看一下String类型如何比较:

public class ComparableTest
{

	public static void main(String[] args)
	{
		
       String a="A";
       String b="B";
       
       System.out.println(a.compareTo(b));

	}

}

String类型我们无法a-b,但是Java提供了compareTo()方法来比较两个字符ASCII码大小,如果比较的数比被比较的数小返回-1

Output:

-1

接下来我们一起从Java提供的String类型的comparaTo()方法来探究一下Java的内部比较器结构。
首先进入compareTo()方法的源码:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    
    public int compareTo(String anotherString) {  
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
}
  • 从该代码中可以看出,返回值是int类型,return len1 - len2; ,返回了字符串ASCII码的差值,如果如果比较的数比被比较的数小返回-1,否则返回1,即, a.comparaTo(b) a小,返回-1 ,a大返回1。
  • 该compareTo()方法是实现类中的方法,实现了Comparable< String>接口:
public interface Comparable<T> {
    public int compareTo(T o);
}

4.3 double类型比较

继续看double类型如何比较大小:

public class ComparableTest
{

	public static void main(String[] args)
	{
		
       double a=1.2;
       double b=2.4;
       
       System.out.println(((Double)a).compareTo((Double)b));

	}

}

Output:

-1

问题:为什么我们要把double类型的a和b要转化为Double类型才能调用compareTo()方法呢?
首先,什么是Double(注意首字母大小写)?

  • double是基本类型数据,Double是基本类型double的包装类,是一个对象。
  • 两者不可相加减,可以在Double类型上用.doubleValue()方法,可获取到double类型数。

我们知道了Double是一个类(包装类),那我们看一下源码:

public final class Double extends Number implements Comparable<Double> {

   public int compareTo(Double anotherDouble) {
        return Double.compare(value, anotherDouble.value);
    }
  }

本段代码中Comparable< Double>说明与String类型一样,它是实现类中的方法,实现了Comparable< Double>接口。

在double类型比较时,相当于,我们把a和b转化成一个类的对象,去调用compareTo()方法。

上述是Java写好的对于特定数据类型的比较器,那我们在自己定义数据类型时,应当重写比较器。

模版:

Class B implements Comparable{
    
    int comparaTo(B b){
    	//return的值按照需要排序的标准来写
        return 
    }
}

举例:

public class Student implements Comparable{	
	
	 String name;
	 int age;
	 
	public Student(){}
	
	public Student(String name, int age)
	{
		super();
		this.name = name;
		this.age = age;
	}

	@Override
	public int compareTo(Object o)
	{
		//按照年龄排序,即:a.ComparaTo(b)
		//a来调用comparaTo()方法,方法的调用者用this表示
		//b当作参数被传入compareTo(Object o),因此b为object类型,所以需要类型转换成student类才能使用age属性
		Student stu=(Student) o;
		return this.age - stu.age;
	}
	
}
class Test{
	public static void main(String []args) {
		Student a = new Student("Ahana",18);
		Student b = new Student("Babily",19);
		
		System.out.println(a.compareTo(b));
	}
}

Output:

-1

注意⚠️1:在写Student类时,要在public class Student 后加上implements Comparable,其中Comparable注意拼写!!!C为大写!!!!
注意⚠️2:在比较姓名时,直接用Java默认的compareTo()即可

return this.name compareTo( stu.name);

如果比较多不是一个属性该怎么办???比如我想先比较姓名,如果年龄一样,再比较年龄,该怎么办呐?

@Override
	public int compareTo(Object o)
	{
		Student stu=(Student) o;
		if( this.name.compareTo(stu.name) != 0) {  //如果两者姓名一样,比较姓名,不一样,则比较年龄。
			return this.name.compareTo(stu.name);
		}else {
				return this.age-stu.age;
			}
		}

OK,当我们的类实现了Comparable接口,那么类对象集合,或者数组可使用工具类进行排序。我们就可以使用Arrays.sort(数组,null),Collections.sort(集合,null)进行排序。

五.Comparator外部比较器

外部比较器常与匿名对象联系在一起
我们先看没有加入匿名对象的外部比较器

举例:

import java.util.Comparator;

public class Student {	
	
	 String name;
	 int age;
	 
	public Student(){}
	
	public Student(String name, int age)
	{
		super();
		this.name = name;
		this.age = age;
	}


}

class OutsideComparator implements Comparator{

	@Override
	public int compare(Object o1, Object o2)
	{
		Student a1 =((Student)o1);
		Student a2 =((Student)o2);
		//根据年龄比较
		return a1.age - a2.age;
	}
class OutsideComparator1 implements Comparator{

	@Override
	public int compare(Object o1, Object o2)
	{
		Student a1 =((Student)o1);
		Student a2 =((Student)o2);
		//根据名字比较
		return a1.name.compareTo(a2.name);
	}
	

}
class Test{
	public static void main(String []args) {
		Student a = new Student("Ahana",18);
		Student b = new Student("Babily",19);
		
		OutsideComparator oc = new OutsideComparator();
		int result = oc.compare(a, b);
		System.out.println(result);	
		
		OutsideComparator oc1 = new OutsideComparator();
		int result1 =oc1.compare(a, b);
		System.out.println(result1)
	}
}

Output:

-1
-1

注意事项⚠️:

  • 1.外部比较器应新建class,然后implements Comparator,注意 Comparator开头字母大写,并且导入包import java.util.Comparator;
  • 2.重写compare(Object o1, Object o2)方法时,传入的参数都为object类型,因此需要类型转化,再进行比较。上例中转化为Student类型。
  • 3.使用外部比较器比较时,要新建对象OutsideComparator oc = new OutsideComparator();
    使用oc来调用compare(Object o1, Object o2)方法。
  • 4.因为oc.compare(a, b);的结果时int类型,所以用int来接受返回的结果。
  • 5.外部比较器只要在不同的class写不同的比较方法,在测试类中建立不同的对象,并且调用各自的compare()方法即可实现比较。由此可见,外部比较器扩展性更好
  • 6.为了方便,在有多个外部比较器同时存在时,我们在创建对象时可以Comparator com = new OutsideComparator();Comparator com = new OutsideComparator1(); Comparator是接口,而OutsideComparator和OutsideComparator1则是实现类,com对象在调用compare()方法时,实际在调用实现类的方法,实则为多态的应用。
		Comparator bj = new OutsideComparator(); //这里可以根据需求任意更改,可改成Comparator bj = new OutsideComparator1();
		int result2 = bj.compare(a, b);
		System.out.println(result2);

六.外部比较器与匿名内部类结合应用

我们发现在写外部比较器时,对一个属性需要排序时要另外写一个class,还要创建对象,调用方法,相对比较麻烦,接下来介绍一种比较简单的方法:将匿名对象与外部比较器结合。

import java.util.Comparator;

class Test{
	public static void main(String []args) {
		Student a = new Student("Ahana",18);
		Student b = new Student("Babily",19);
		
		
		Comparator bj = new Comparator() { //匿名内部类需要通过父类或接口(Comparator)实现

			@Override
			public int compare(Object o1, Object o2)
			{
				Student a1 =((Student)o1);
				Student a2 =((Student)o2);
				//根据年龄比较
				return a1.age - a2.age;
			} 
		};
		
		int result = bj.compare(a, b);
		System.out.println(result);
		
			
	}
}

注意⚠️:格式
Comparator xxxx = new Comparator() {
public int compare(Object o1, Object o2)
{
return xxxxxx;
}
};

无需外加class了

升级版:

import java.util.Comparator;

class Test{
	public static void main(String []args) {
		Student a = new Student("Ahana",18);
		Student b = new Student("Babily",19);
		
		
		int res = new Comparator() {

			@Override
			public int compare(Object o1, Object o2)
			{
				Student a1 =((Student)o1);
				Student a2 =((Student)o2);
				//根据年龄比较
				return a1.age - a2.age;
				
			}
			
		}.compare(a, b);
		
		System.out.println(res);
		
			
	}
}

拆分解析一下

new Comparator() {

			@Override
			public int compare(Object o1, Object o2)
			{
				Student a1 =((Student)o1);
				Student a2 =((Student)o2);
				//根据年龄比较
				return a1.age - a2.age;
				
			}
			
		}

这段代码说,建立了一个Comparator的对象new Comparator() {……}

new Comparator() {

			@Override
			public int compare(Object o1, Object o2)
			{
				Student a1 =((Student)o1);
				Student a2 =((Student)o2);
				//根据年龄比较
				return a1.age - a2.age;
				
			}
			
		}.compare(a, b);

然后新建的对象调用compare(a, b);方法,new Comparator() {……}.compare(a, b);

int res = new Comparator() {

			@Override
			public int compare(Object o1, Object o2)
			{
				Student a1 =((Student)o1);
				Student a2 =((Student)o2);
				//根据年龄比较
				return a1.age - a2.age;
				
			}
			
		}.compare(a, b);

本段代码,int res = new Comparator() {……}.compare(a, b); ,用int 类型res来接受返回的结果。

七.总结:

使用外部比较器还是外部比较器,由需求所决定,总而言之,外部比较器比内部比较器更灵活,更易维护。

你可能感兴趣的:(Java之核心应用)