Java 比较器 和 包装类

Java比较器

背景:

在Java中经常会涉及到多个对象的排序问题,那么就涉及到对象之间的比较

  • Java中的对象, 正常情况下, 只能进行比较

    == 比较对象地址值,是否相同

    != 比较对象地址值,是否相同,取反~

    不能使用 > 或 < 的

  • 但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小

    image-20211018155709517

  • 以 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));
    }
}
image-20211018173303424

自然排序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);
        }
    }
}
image-20211018234620209

定制排序: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);

    Collections.sort(T[],Comparator);

实现:

  • 可以将 Comparator 接口实现类传递给 sort(T[],Comparator) 方法,从而允许在排序顺序上实现精确控制。

  • 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));
    }
}
image-20211019002027715

两者的区别

  • 只要实现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);
    }
}

image-20211020003523942

总结:

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 发布!

你可能感兴趣的:(Java 比较器 和 包装类)