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

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

作为测试需要上传了一些图片,但七牛的控制台却无法将内容按照上传时间排序或者是按照日期查询,由于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. Python—字符串和常用数据结构

    目录 1. 字符串 2. 列表 2.1 列表的增删改查 2.2 列表的切片和排序 2.3 生成式语法 3. 元组 4.集合 5. 字典 5.1 字典的增删改查 5.2 字典的常见操作 序言:这一章我们 ...

  2. 右键没有新建word选项

    两类解决办法 一. 1. 新建一个txt文本,并插入如下内容: Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.doc] @=&quo ...

  3. C++解决最基本的迷宫问题

    问题描述:给定一个最基本的迷宫图,用一个数组表示,值0表示有路,1表示有障碍物,找一条,从矩阵的左上角,到右下角的最短路.求最短路,大家最先想到的可能是用BFS求,本文也是BFS求最短路的. 源代码如 ...

  4. sql字段为逗号分开的字符串值的关联查询

    1.TREE表: [strID] [int] IDENTITY(1,1) NOT NULL,[strName] [nvarchar](50) NOT NULL, 2.SubInfo CREATE TA ...

  5. 使用 Eslint & standard 规范前端代码

    前言 JavaScript的动态语言类型,给它带来了独特的魅力,产生了风格多样的开发范式,同时也带来了一些问题,从运行时常见的 undefined .null 报错,到代码随意的加减分号.换行.空格, ...

  6. 遗传编程(GA,genetic programming)算法初探,以及用遗传编程自动生成符合题解的正则表达式的实践

    1. 遗传编程简介 0x1:什么是遗传编程算法,和传统机器学习算法有什么区别 传统上,我们接触的机器学习算法,都是被设计为解决某一个某一类问题的确定性算法.对于这些机器学习算法来说,唯一的灵活性体现在 ...

  7. Linux入门基础之 下

    八.Linux 管道.重定向及文本处理 8.1.Linux 多命令协作:管道及重定向 8.1.1 开源文化 开源文化的核心理念之一就是不要重复发明轮子,很多的开源软件都是现有软件.代码.功能的重新组合 ...

  8. 将maven项目导入到eclipse中

    一,前言 本文来演示一下如何将一个新的maven项目到入到eclipse中. 在文章使用命令行创建maven web项目中我们使用maven命令行,创建了web工程,接下来为了开发方便我要将新建的工程 ...

  9. Centos安装PhantomJS

    1.下载PhantomJS [root@liuge ~]# wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-l ...

  10. Git项目分支分配

    主要分支包含master分支与develop分支,临时分支可以分为: release: 从develop分出 ,是最终要发布的版本. feature: 实现某功能时推荐新建分支,从develop分出. ...