Java 比较器 和 包装类

Java比较器

背景:

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

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

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

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

    不能使用 > 或 < 的

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

    <img src="https://wsm540.oss-cn-beijing.aliyuncs.com/Java/比较器和包装类image-20211018155709517.png" alt="image-20211018155709517" style="zoom:50%;" />

  • 以 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<b = -1

        //Boolean 包装类实现了, Comparable 接口!
        Boolean ok = true;
        Boolean no = false;
        System.out.println("Boolean类型: true > 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<? 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));
    }
}
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<int> list1 = new ArrayList<>(); 编译报错

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容