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

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

作为测试需要上传了一些图片,但七牛的控制台却无法将内容按照上传时间排序或者是按照日期查询,由于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. response中文乱码问题

    1.要确定I代码的编码格式为UTF-8 2.乱码原因:浏览器和服务器的编码格式不同: 服务器的默认编码为:ISO-8859-1,如果浏览器的编码不是ISO-8859-1,就会出现乱码: public ...

  2. Android 使用URLConnection下载音频文件

    本文链接: Android 使用URLConnection下载音频文件 使用MediaPlayer播放在线音频,请参考Android MediaPlayer 播放音频 有时候我们会需要下载音频文件.这 ...

  3. MySQL中常用到的关于时间的SQL

    -- 今天 SELECT DATE_FORMAT(NOW(),'%Y-%m-%d 00:00:00') AS dayStart;SELECT DATE_FORMAT(NOW(),'%Y-%m-%d 2 ...

  4. 谁是狸猫谁是太子?--戏说java构造器

    故事背景 <狸猫换太子>在我国民间文学中很出名,故事剧情大致如下:北宋第三位皇帝宋真宗赵恒年长无子,他的两个妃子刘妃与李妃同时怀了身孕.真宗召见二人,各赐信物,并声明哪个生了儿子就立谁为皇 ...

  5. linux系统下开发环境安装与配置

    安装系统环境 CentOS 6.8 64位 jdk版本 7u80 64位 Tomcat版本 Tomcat7 maven版本 Apache Maven 3.6.0 vsftpd版本 vsftpd-2.2 ...

  6. .net 更新access数据库 影响的行数为0

    在更新Access数据库的时候,明明传入的数据及参数类型都正确,但是一直更新不了,查看影响的行数一直为0 此原因为 C#操作Access数据库的时候更新的参数和条件参数要按照更新语句中的顺序进行设置, ...

  7. linux服务器创建虚拟路径解决文件上传路径隔离问题

    需求环境 图片上传最简单的就是上传web项目下,这样图片与项目不可分离会产生很多不必要的影响.例如:重新部署项目需要把所有上传的图片再copy一份等. 图片与项目分离有好几种方式: 方式一.在linu ...

  8. mysql5.7初始密码及设置问题

    为了加强安全性,MySQL5.7为root用户随机生成了一个密码,如果安装的是RPM包,则默认是在/var/log/mysqld.log中. 可通过# grep "password" ...

  9. 机器学习回顾篇(6):KNN算法

    1 引言 本文将从算法原理出发,展开介绍KNN算法,并结合机器学习中常用的Iris数据集通过代码实例演示KNN算法用法和实现. 2 算法原理 KNN(kNN,k-NearestNeighbor)算法, ...

  10. 搭建Nodejs环境 创建Express应用

    1. Nodejs Nodejs是一种服务器端js脚本运行环境: Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎 2. Express开发框架 极简的web框架,完全是由路 ...