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

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

作为测试需要上传了一些图片,但七牛的控制台却无法将内容按照上传时间排序或者是按照日期查询,由于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. 判断是手机端还是PC短访问

    第一种:判断是手机访问还是PC访问 <script> function browserRedirect() { var sUserAgent = navigator.userAgent.t ...

  2. Python机器学习笔记:卷积神经网络最终笔记

    这已经是我的第四篇博客学习卷积神经网络了.之前的文章分别是: 1,Keras深度学习之卷积神经网络(CNN),这是开始学习Keras,了解到CNN,其实不懂的还是有点多,当然第一次笔记主要是给自己心中 ...

  3. 松软科技课堂:Winform之TextBox

    松软科技文(www.sysoft.net.cn): 文本框的几种模式:Multiline(多行).PasswordChar(密码)将文本框的PasswordChar设为*就是密码框效果,将MultiL ...

  4. 如何更规范化使用MySQL

    如何更规范化使用MySQL 背景:一个平台或系统随着时间的推移和用户量的增多,数据库操作往往会变慢:而在Java应用开发中数据库更是尤为重要,绝大多数情况下数据库的性能决定了程序的性能,如若前期埋下的 ...

  5. 混合事务分析处理“HTAP”的技术要点分析

    HTAP是近些年来比较火的一个概念,本文将聊聊HTAP的前世今生及技术特点. 一.数据应用类别 根据数据的使用特征,可简单做如下划分.在选择技术平台之前,我们需要做好这样的定位. 1.1 OLTP 联 ...

  6. Widget 基础

    一切皆Widget Widget 渲染过程 Flutter把视图数据的组织和渲染抽象为三部分,即 Widget.Element 和 RenderObject. Widget Widget 是空间实现的 ...

  7. java中String常见问题

    java中String常见问题 1.字符串比较==和equals ==:比较的是对象,判断两个引用的是否为同一内存地址(物理对象) equals:比较的是值 2.通过空白字符拆封字符串 str.spi ...

  8. Linux 文件/目录操作详解

    目录 Linux 文件/目录操作详解 初识Linux 一.文件/目录显示命令 ls 二.目录创建命令 mkdir 三.目录转移命令 cd 四.当前目录显示命令 pwd 五.文件处理命令 rmdir 六 ...

  9. Asteroids POJ - 3041 二分图最小点覆盖

       Asteroids POJ - 3041 Bessie wants to navigate her spaceship through a dangerous asteroid field in ...

  10. Fork/Join 框架框架使用

    1.介绍 Fork/Join 框架是 Java7 提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架.在多核计算机中正确使用可以很好的 ...