Java比较器
背景:
在Java中经常会涉及到多个对象的排序问题,那么就涉及到对象之间的比较
-
Java中的对象, 正常情况下, 只能进行比较
==
比较对象地址值,是否相同!=
比较对象地址值,是否相同,取反~不能使用 > 或 < 的
-
但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小
-
以 JD 商城举例场景: 查询商品可以对商品进行:
价格 销量 评论 购买数...排序
实际上这里面是查询每一个商品都是一个个
商品对象
对象属性:
商品名 评论数 价格 销量 店铺 图片地址...
-
根据用户点击,从数据库中查询到一个
商品对象/数组
进行排序,返回数据给前端进行排序展示~当然, 一个功能可以有很多种实现方式, 也有直接在数据库中根据传过来的类型, 动态sql 直接在数据库中查询返回排好序的数据!
Java实现对象排序:
这里主要介绍,以Java方式实现的对象排序...
-
Java实现对象排序的方式有两种:
自然排序:Java.lang.Comparable
定制排序:Java.util.Comparator
自然排序:Java.lang.Comparable 看牌啊爆
Java Comparable接口强行对实现它的每个类的对象进行整体排序 这种排序被称为:自然排序
Java类, 实现
implements
Comparable接口,重写compareTo(Object o); 的方法;
-
两个对象即通过
compareTo(Object o)
方法的返回值来比较大小如果当前对象 this 大于形参对象 o ,则返回正整数 1
如果当前对象 this 小于形参对象 o ,则返回负整数 -1
如果当前对象 this 等于形参对象 o ,则返回零 0
实现
Comparable
接口的类的对象数组(和有序集合)可以通过 Arrays.sort(和 Collections.sort )进行自动排序-
Comparable的典型实现
**String、包装类等实现了Comparable接口,重写了compareTo(obj)方法 **
默认都是从小到大排序
String:按照字符串中字符的Unicode值进行比较
Character:按照字符的Unicode值来进行比较
数值类型对应的包装类以及BigInteger、BigDecimal:按照它们对应的数值大小进行比较
Boolean:true 对应的包装类实例大于 false 对应的包装类实例
true.compareTo( false); —返回—> 1
Date、Time等:后面的日期时间比前面的日期时间大
2021.compareTo( 2020 ); —返回—> 1
String、包装类实现 Comparable接口 Demo
ComparaTest.Java
package com.wsm.comparatest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ComparaTest {
//Java String、包装类等实现了Comparable接口
public static void main(String[] args) {
//String 类实现了, Comparable 接口!并且实现Comparable 接口!可以直接使用: Arrays.sort Collections.sort 进行排序!
String[] arr = new String[]{"AA","cc","ac","dd","aa","FF","ff"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); //[AA, FF, aa, ac, cc, dd, ff]
//Char 的包装类, Character 实现Comparable 接口!按照字符的Unicode值来进行比较;
char a = 'a';
char b = 'b';
System.out.println("a="+(int)a+"\n"+"b="+(int)b);
Character aC = 'a';
Character bC = 'b';
System.out.println(aC.compareTo(bC)); // a false:"+ok.compareTo(no));
//int 等基本数据类型的包装类实现了, Comparable 接口!
Integer one = 1;
Integer two = 2;
System.out.println("基本数据类型包装类比较,直接根据值进行比较:"+one.compareTo(two));
//Data 日期类型实现, Comparable 接口!
SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
Date thisYear = null;
Date lastYear = null;
try {
thisYear = sdf.parse("2021");
lastYear = sdf.parse("2020");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("日期类型比较,最近的日期最大:"+thisYear.compareTo(lastYear));
}
}
自然排序Demo
Commodity.Java
定义一个商品类:
/**
* 创建一个商品类;
*/
public class Commodity implements Comparable {
//商品名
private String name;
//商品价格
private int price;
//商品销量
private int sales;
//点赞数
private int like;
//...更多不举例子了...
/** 实现implements Comparable接口,重写 compareTo(Object o)类 */
/** 指明商品比较大小的方式:按照价格从低到高排序,再按照产品名称从高到低排序 */
@Override
public int compareTo(Object o) {
// instanceof: 判断传入参数类型是否是 商品类型,进入if 进行比较!
if(o instanceof Commodity){
// Object 类型强制转换,父类向下转换!
Commodity o1 = (Commodity) o;
if(this.price > o1.price){ //如果当前对象 大于> 传入对象返回 1;
return 1;
}else if(this.price < o1.price){ //如果当前对象 小于< 传入对象返回 -1;
return -1;
}else { //相等则在进行判断...移此类推返回 0;
//return 0; //相等,应该返回0 但我们还需要进行判断商品名称从高到底~
//因为商品名称是 String类型, String 本身已经实现了 comparable 所以
return -this.name.compareTo(o1.name);//默认都是从小到大排序,加个 - 号取反~
}
}
throw new RuntimeException("传入的数据类型不一致!");
}
//有参构造
public Commodity(String name, int price, int sales, int like) {
this.name = name;
this.price = price;
this.sales = sales;
this.like = like;
}
//重写toString 不然打印地址值!
@Override
public String toString() {
return "Commodity{" +
"name='" + name + '\'' +
", price=" + price +
", sales=" + sales +
", like=" + like +
'}';
}
//省略 get/set..
}
上面的 compareTo(Object o) 方法中,如果只是根据对象的一个属性进行排序... 可以直接使用一个基本数据类型包装类,进行 campareTo()
CommodityTest.Java
import java.util.Arrays;
/** 测试类 */
public class CommodityTest {
public static void main(String[] args) {
Commodity[] commodities = new Commodity[5];
commodities[0] = new Commodity("a",1,1,1);
commodities[1] = new Commodity("b", 1,1,1 );
commodities[2] = new Commodity("c", 2,1,1 );
commodities[3] = new Commodity("d", 3,1,1 );
commodities[4] = new Commodity("a", 4,1,1 );
System.out.println("第一次遍历数组:");
for (Commodity commodity : commodities) {
System.out.println(commodity);
}
//调用方法,给数组排序...
Arrays.sort(commodities);
System.out.println("Arrays.sort排序后遍历数组:");
//name 从大到小~
System.out.println("a="+(int)'a');
System.out.println("b="+(int)'b');
for (Commodity commodity : commodities) {
System.out.println(commodity);
}
}
}
定制排序:Java.Util.Comparator 看牌啊特
当元素没有实现 Comparable接口, 而不方便修改代码
或者实现了 Comparable 接口, 但其排序的操作,并不符合当前操作
- String 默认从大小排,而我想要从小到大排序……
而可以考虑 Comparator 类型对象来排序
Compartor
-
Comparator
接口中只有两个抽象方法int compare(Object o1, Object o2);
boolean equals(Object obj);
接口实现类默认继承了Object
类的equals
方法, 间接实现了方法。因此只需实现
int compare(Object o1, Object o2);
-
Arrays.sort 和 Collections.sort 存在多态方法
Arrays.sort(T[],Comparator super T>);
Collections.sort(T[],Comparator super T>);
实现:
可以将
Comparator
接口实现类传递给 sort(T[],Comparator super T>) 方法,从而允许在排序顺序上实现精确控制。Comparator
当作内部类,直接传递给方法,内部类中重写int compare(Object o1, Object o2)方法
比较o1和o2的大小
定制排序Demo
ComparatorTest.Java
import java.util.Arrays;
import java.util.Comparator;
/** ComparatorTest测试Demo */
public class ComparatorTest {
//直接拿String 类进行操作, String类本身实现了 comparable接口;
public static void main(String[] args) {
/** 混乱的String[] */
String[] arr = new String[]{"CC","MM","KK","AA","DD","GG","JJ","EE"};
//默认从小到大排序
System.out.println("默认从小到大排序");
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
System.out.println("按照字符串从大到小的顺序排列");
//按照字符串从大到小的顺序排列, new Comparator(){ ... } 内部类操作;
Arrays.sort(arr,new Comparator(){
//重写compare(Object o1, Object o2) 方法
@Override
public int compare(Object o1, Object o2) {
//类型判断全栈类型转换
if(o1 instanceof String && o2 instanceof String){
String s1 = (String) o1;
String s2 = (String) o2;
return -s1.compareTo(s2);
}
throw new RuntimeException("输入的数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));
}
}
两者的区别
只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码
-
用Comparator 的好处是不需要修改源代码
而是在待比较对象的类的外部实现一个比较器
当某个自定义的对象需要作比较的时候,把待比较对象和比较器一起传递过去就可以实现排序功能。
-
像String类、包装类等JDK内置类实现了Comparable接口默认是升序排序
如果要降序排序或指定其他排序规则只能使用Comparator接口。
扩展:
instanceof
- instanceof 是 Java 的一个二元操作符,类似于 ==,>,< 等操作符
- instanceof 是 Java 的保留关键字
它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型
Java 遵循 -- 得正~
System.out.println("Java遵循‘负负得正’ 数学公式:"+(-(-1)));
Java包装类
什么是包装类型
Java 设计当初就提供了 8种基本数据类型
-
int byte short long
float double
boolean
char
及对应的 包装类
-
Integer Byte Short Long
Float Double
Boolean
Character
位于Java.lang包下
基本数据类型 和 包装类基本一致, 首字母大写类名首字母大写, 本就是规范
就是 int 和 char 有点不一样... 基本使用都一致,这里就以 int 举例:
包装类应用场景
-
集合类泛型只能是包装类
List
list1 = new ArrayList<>(); 编译报错
List
list2 = new ArrayList<>(); 正常
包含了每种基本类型的相关属性,如最大值,最小值,所占位数等常用方法()...
-
作为基本数据类型, 有时候我们想要进行一些对象的操作,
基本数据类型
无法直接完成!在Java中,一切皆对象,但八大基本类型却不是对象
基本数据类型-----包装类-----String 的转换
包装类通过 Integer.toString() 将整型转换为字符串
Object 的方法~
包装类通过 Integer.parseInt("123") 将字符串转换为int类型
包装类通过valueOf()方法, 将
字符/数值
转换换成包装类对象.虽然和基本数据类型存在
自动装箱/拆箱~
自动 装箱
拆箱
Java5.0 之后新增的两个功能: 自动装箱
自动拆箱
-
自动装箱:
装箱就是将: 基本数据类型 ——转换—— 为对象类型
Integer a = 100;
-
自动拆箱:
拆箱就是将:对象类型 ——转换为—— 基本数据类型
int b = a;
PackClass.Java
/** 包装类Demo */
public class PackClass {
public static void main(String[] args) {
//Integer 是int 类型的包装类, 内置了大量的方法操作
System.out.println("int 的最大值:"+Integer.MAX_VALUE);
System.out.println("int 的最小值:"+Integer.MIN_VALUE);
//...
//构造方法:
// new Integer(int); new Integer(String);
// 将int 和 String 转换成Integer对象; (JDK8已过时 ~)
//创建一个Integer
//1.构造函数
Integer c1 = new Integer("540");
//2.自动装箱
Integer c2 = 540;
//3.使用提供的 valueof( int/String );
// 构造函数方式已经被淘汰了... 使用String 注意String必须满足是数字符, 不可以是 abc...
Integer c3 = Integer.valueOf("540");
//因为 Integer 是对象了,每一个对象都会又一个对应栈地址, == 比较地址所以返回false
System.out.println(c1==c2);
System.out.println(c1==c3);
System.out.println(c2==c3);
//即使这样也不例外!
Integer c22 = 540;
System.out.println(c2==c22);
//但 Integer 和 int 进行比较是直接比较值, 底层会进行 "自动拆箱"
int c33 = 540;
System.out.println(c3==c33);
//Integer 和 int 可以进行,数值计算/比较~
System.out.println(c3+c33);
//自动装箱 拆箱
Integer w = 123;
System.out.println("自动装箱:"+w);
int w1 = new Integer("123");
System.out.println("自动拆箱:"+w1);
System.out.println("自动装箱拆箱就是: 基本数据类型 和 引用类型(包装类), 之间的相互转换~");
//String 包装类 基本数据类型 相互转换
/** 基本类型转换为字符串(3) */
int c = 10;
//使用包装类的 toString() 方法
String str1 = Integer.toString(c);
//使用String类的 valueOf() 方法
String str2 = String.valueOf(c);
//用一个空字符串加上基本类型,得到的就是基本类型数据对应的字符串
String str3 = c + "";
/** 字符串转换为基本类型 */
String str = "8";
//调用包装类的parseXxx()静态方法
int d = Integer.parseInt(str);
//调用包装类的valueOf()方法转换为基本类型的包装类,会自动拆箱
int e = Integer.valueOf(str);
/** 字符串转换为包装类 */
//通过构造函数 字符参数
//通过valueof("");
Integer integer = Integer.valueOf("8");
System.out.println(integer);
}
}
总结:
Java八大基本数据类型都有对应的包装类,使基本数据类型也具有对象的操作...
- 并且内部定义了一些方法,方便使用..
- 结合: 自动装箱/拆箱 基本数据类型,使用起来更加的心用手~
Integer与int的区别
int是java提供的8种原始数据类型之一
Java为每个原始类型提供了封装类,Integer是java为int提供的封装类
int的默认值为0
-
Integer的默认值为null
**即Integer可以区分出未赋值和值为0的区别 **
int则无法表达出未赋值的情况
判断一个人考试,
0分
和缺考
则只能使用Integer -
在JSP开发中,Integer的默认为null
所以用el表达式在文本框中显示时,值为空白字符串
int默认的默认值为0,所以用el表达式在文本框中显示时,结果为0
int不适合作为web层的表单数据的类型
-
Integer提供了多个与整数相关的操作方法
将一个字符串转换成整数,Integer中还定义了表示整数的最大值和最小值的常量
本文由博客一文多发平台 OpenWrite 发布!