近日开发任务时间充裕一些,于是有时间回顾一下项目。

我关注到了项目中使用的七牛云的对象存储服务。

作为测试需要上传了一些图片,但七牛的控制台却无法将内容按照上传时间排序或者是按照日期查询,由于bucket当中内容较多,我无法看到今日上传的图片记录。

点开控制台给出的帮助文档,没怎么找到控制台的说明,却在下一行中看到了这样一个小句,由愣而转笑。

又参考了segmentfault等问答,不知是自身算法实力强大还是怎样,反正七牛的确就是由一个【快】字拒绝提供一切排序和筛选服务。。

包括控制台、包括API。

因为存储使用key-value按照key的ascii排序,性能最好,展示时也决意不肯做任何变通,这是哪门子逻辑?

端详了好一会快字,又到api的文档中遨游,迫不得已结合了服务端的sdk才摸清了该使用哪个域名、以及api的验证token逻辑。

终于我可以借助api获取到一个bucket底下的所有文件列表。(当然也只能按key的字母排序)

没有排序自己排吧。

由于七牛记录的上传时间单位是100纳秒。。(醉了,下面放一张珍藏的图,可能是为了匹配内存的处理速度吧,转为毫秒要除以10000)毫无疑问会用long来表示了

先开始为了降序排序直接把compare方法直接重写为return (int)o2.putTime - o1.putTime,结果排序结果颠三倒四。

由于习惯上compare的结果都类比数学符号函数返回1/0/-1,试着修改,排序结果正常。

我慌了。印象中sort源码没有去判断1/0/-1啊。。查阅了一下,的确无论是mergeSort还是TimSort源码中只做了compare方法的结果< 0和>= 0的判断。

遂开始意识到是强转出了问题。不过,long强转为int时超过了int的范围,你们猜会怎么样?变为0?一开始我确实认为是变为0导致比较器认为很多对象相等,进而导致排序结果混乱。

实际上呢,放一些例子给大家感受一下:

原始long794056495088 强转int-512454672
原始long889116247210 强转int58016938
原始long-42421670980704 强转int-278998112
原始long-13603247092059 强转int-1085665627
原始long-42159956036917 强转int-557059381
原始long1150831190997 强转int-220044331
原始long-15560683307530 强转int-16794122
原始long-10186805000959 强转int857425153
原始long6059356417962 强转int-842436694
原始long16453936148484 强转int-83562492
原始long631537897167 强转int177704655
原始long17343052395694 强转int-25545554
原始long-9434266088448 强转int1777060864
原始long-3033381814 强转int1261585482
原始long4651744348343 强转int294766775
原始long-13649116168272 强转int289898416

出乎意料,没有0,但是有一些强转后维持了原符号,另一些正负颠倒。

是时候学习一下强转原理了。

java中long为8字节64位,int为4字节32位。

如果long强转为int:直接取低位32位作为值,但是看做补码。

在计算机中,数值以补码形式存储,正数的补码为其二进制表示。负数的补码为其模的二进制表示取反加一(或者记为符号位不变,剩余数位取反+1)。

负数的补码转原码时:符号位不变,剩余数位取反+1。和负数原码转补码的操作步骤相同哟,这里列出百度百科补码的三个特性方便理解:

1、一个负整数(或原码)与其补数(或补码)相加,和为模。
2、对一个整数的补码再求补码,等于该整数自身。
3、补码的正零与负零表示方法相同。

例1:

原始long 794056495088

原始long转为二进制 1011100011100001011101001000111111110000

取低位32位作为补码(结果是负数):11100001011101001000111111110000

符号位不变,剩余数位取反+1:10011110100010110111000000010000

转为带符号10进制:-512454672

再看一个强转后符号不改变的,这种事不多练两遍记不住。

例2:

原始long 889116247210

原始long转为二进制 1100111100000011011101010100010010101010

取低位32位作为补码(结果是正数):00000011011101010100010010101010

转为带符号10进制:58016938

所以,原始long低32位上的那个数字很重要,但是人家原来不是表示符号的(不一定会跟原始long的符号位数字相同啊),强转后就按符号位处理了,大概率要出问题。

当然,明白原理后程序上做处理就可以了。不要直接反强转结果,要么自己写下,要么使用Long.compare这个静态方法。

另外说到long,我就想到Long这些包装类,虽然本次问题与包装类无关。

写了一些测试代码,结论与大家分享:

Long l1=12345l;
Long l2=12345l;
Long l3=1234l;
System.out.println(l1>l2);
System.out.println(l1>=l2);
System.out.println(l1==l2);
System.out.println();
System.out.println(l1>l3);
System.out.println(l1>=l3);
System.out.println(l1==l3);

运行结果:

false
true
false

true
true
false

1、如果使用包装类进行等于(==)的比较,比较的是Long对象的地址,故可以使用equals或者.longvalue比较数值。

2、如果使用包装类进行包含大于小于(>、<、>=、<=)的比较,比较时jvm会进行自动拆箱,因此直接比就好了。

打破砂锅不是为了吹毛求疵,而是为了不受【常识】所限的、更好的定位问题。

最后,感谢不完善、感谢未完成,让我每日都有动力去打破砂锅、进步一点。

参考资料:

https://developer.qiniu.com/kodo/kb/1336/upload-download-instructions

https://blog.csdn.net/gdhgr/article/details/79604250

https://baike.baidu.com/item/%E8%A1%A5%E7%A0%81/6854613?fr=aladdin

自力更生Collections.sort发现比较结果混乱?Comparator的锅还是强转类型导致?的更多相关文章

  1. Java—集合框架 Collections.sort()、Comparable接口和Comparator接口

    Collentions工具类--java.util.Collections Collentions是Java集合框架中,用来操作集合对象的工具类,也是Java集合框架的成员,与List.Map和Set ...

  2. list集合的排序Comparator和Collections.sort

    一个例子 package sortt; import java.util.ArrayList; import java.util.Collections; import java.util.Compa ...

  3. Collections.sort(List<T> Comparator) 自定义排序

    Collections.sort(basicinfoList, new Comparator<MlisBasicinfo>() { @Override public int compare ...

  4. 十五、Collections.sort(<T>, new Comparator<T>() {})针对字符串排序

    1.排序对象全是字母组成,可以根据ASCII编码表排序 package com.abcd; public class Person{ private String name; private int ...

  5. Comparable和Comparator的区别&Collections.sort的两种用法

    在Java集合的学习中,我们明白了: 看到tree,可以按顺序进行排列,就要想到两个接口.Comparable(集合中元素实现这个接口,元素自身具备可比性),Comparator(比较器,传入容器构造 ...

  6. Java中Collections的sort方法和Comparable与Comparator的比较

    一.Comparable 新建Student1类,类实现Comparable接口,并重写compareTo方法 public class Student1 implements Comparable& ...

  7. ht-8 对arrayList中的自定义对象排序( Collections.sort(List<T> list, Comparator<? super T> c))

    package com.iotek.set; import java.util.ArrayList; import java.util.Collections; import java.util.Co ...

  8. Java8 Collections.sort()及Arrays.sort()中Lambda表达式及增强版Comparator的使用

    摘要:本文主要介绍Java8 中Arrays.sort()及Collections.sort()中Lambda表达式及增强版Comparator的使用. 不废话直接上代码 import com.goo ...

  9. Arrays.sort和Collections.sort实现原理解析

    Arrays.sort和Collections.sort实现原理解析 1.使用 排序 2.原理 事实上Collections.sort方法底层就是调用的array.sort方法,而且不论是Collec ...

随机推荐

  1. CODESYS添加target

    1.主界面进入Tools 2.Install,选择安装包

  2. Tomcat类加载器体系结构

    <深入理解java虚拟机>——Tomcat类加载器体系结构 标签: java / 虚拟机 / tomcat Tomcat 等主流Web服务器为了实现下面的基本功能,都实现了不止一个自定义的 ...

  3. SpringCloud学习笔记(7):使用Spring Cloud Config配置中心

    简介 Spring Cloud Config为分布式系统中的外部化配置提供了服务器端和客户端支持,服务器端统一管理所有配置文件,客户端在启动时从服务端获取配置信息.服务器端有多种配置方式,如将配置文件 ...

  4. 30 道 Vue 面试题

    前言 本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性.框架的原理以问题的形式进行整理汇总,意在帮助作者及读者自测下 Vue 掌握的程度. 本文章节结构以从易到难进行组织,建议读者按章节顺 ...

  5. 软件测试的分类&软件测试生命周期

    软件测试的分类: 按测试执行阶段:单元测试.集成测试.系统测试.验收测试.(正式验收测试,Alpha 测试-内侧,Beta 测试-公测) 按测试技术分类:黑盒测试.白盒测试.灰盒测试 按测试对象是否运 ...

  6. 工厂模式(整理自李建忠<C++设计模式>视频)

    整理自李建忠<C++设计模式>视频 一.导入:"对象创建"模式和工厂模式 工厂模式只是该模式下的一种. 二.举例说明 有这样一个场景:需要在MainForm中设计一个按 ...

  7. JVM 调优 - jmap

    Java命令学习系列(三)——Jmap 2015-05-16 分类:Java 阅读(17065) 评论(9) 阿里大牛珍藏架构资料,点击链接免费获取 Jmap jmap是JDK自带的工具软件,主要用于 ...

  8. VMware CentOS7 安装

    一.软硬件准备 作者:小啊博 QQ:762641008 转载请声明:https://www.cnblogs.com/-bobo 1.准备Centos7镜像 软件:推荐使用VMwear,我用的是VMwe ...

  9. JQuery入门学习笔记(全)

    jQuery 语法 $(this).hide() - 隐藏当前元素 $("p").hide() - 隐藏所有 元素 $("p.test").hide() - 隐 ...

  10. Scala 多继承顺序

    Trait多继承顺序: 准则: 如果有超类,则先调用超类的函数. 如果混入的trait有父trait,它会按照继承层次先调用父trait的构造函数. 如果有多个父trait,则按顺序从左到右执行. 所 ...