程序世界中这些神秘数字你知道吗

记得大学时看过一本书,上边写到一个撩妹的小技巧:提出和对方玩一个意识游戏,让她心中想一个1到10、对她而言比较有意义的一个数字,然后自己在另一个地方写下一个数字,往往能猜中。这个小技巧利用了人的心理,同时,「程序」其本身本质上就是数字,本文将收集一些有趣的数字,主要以Java语言中的数字为主。给枯燥的生活一些调剂。

待会儿要登场的 Kim Polese

1. 神奇的数字 7142857

上边的那个问题的答案是7。我们平时生活中总是会在各种各样的地方遇到7这个数字,当你让别人去想一个1到10的数字时,它就欢呼雀跃地跳了出来。最广为人知的就是「一周有7天」这个事情了,同时,7还可以延伸出来另外一个很有趣的数字142857,看下边的算式:

1 / 7   =   0.142857, 142857, 142857...
2 / 7    =  0.285714, 285714...
3 / 7    =    0.428571...
4 / 7    =  0.571428...
5 / 7    =  0.714285...
6 / 7   =   0.857142...

当我看到这个结果时已经很震惊了,但是还有更多的:

着了魔的数字
142857 x 1 = 142857
142857 x 2 = 258714
142857 x 3 = 428571
142857 x 4 = 571428
142857 x 5 = 714285
148257 x 6 = 857142

2. 美剧「迷失」中的 4 8 15 16 23 42

这个太玄,就不多说了。

「迷失」中的神秘数字

3. 藏在Java随机数中的hello world

这算是一个广为人知的现象,在Java的Random类中实现的随机数生成算法并不是真正的随机数,只是概率上大致的随机,而其随机性取决于种子的选取,如果选取了特定的种子,那么产生的随机数也就确定了。

色子才是真随机

根据以上的事实,把-229985452当做种子传入Random类,就可以得到hello,相应的-147909649则能得到world。在Java中执行如下程序,它最终会打印输出hello world

public static String randomString(int i) {
    Random ran = new Random(i);
    StringBuilder sb = new StringBuilder();
    while (true) {
        int k = ran.nextInt(27);
        System.out.println("char:" + k + ",number:" +  k);
        if (k == 0)
            break;
        k += 96;
        sb.append((char) k);
    }

    return sb.toString();
}
System.out.println(randomString(-229985452) + " " + randomString(-147909649));

根据这个原理,你可以找到很多字符串的种子。原来除了简单的编码,字符串还可以使用随机数的形式隐藏起来。

4. JDK的版本号

我们知道的JDK版本号往往是1.61.8,或者Java8这种,但是在编译后的class文件中并不是这么记录的,偶尔在运行程序时会碰到这个错误

java.lang.UnsupportedClassVersionError: Bad version number in .class file [at java.lang.ClassLoader.defineClass1(Native Method)]

在class文件中版本号有[主版本号(major version number)].[次版本号(minor version number)],其中「主版本号」和「JDK版本号」的对应关系如下所示:

  • Java SE 9 = 53 (0x35 hex),
  • Java SE 8 = 52 (0x34 hex),
  • Java SE 7 = 51 (0x33 hex),
  • Java SE 6.0 = 50 (0x32 hex),
  • Java SE 5.0 = 49 (0x31 hex),
  • JDK 1.4 = 48 (0x30 hex),
  • JDK 1.3 = 47 (0x2F hex),
  • JDK 1.2 = 46 (0x2E hex),
  • JDK 1.1 = 45 (0x2D hex).

5. class文件中的 0xcafebabe,或者说是3405691582

如果你用任何一个文本文档编辑器打开一个Java的class文件或者Mac平台上的可执行文件,它的第一行一般如下所示:

//Java编译后的class文件
cafe babe 0000 0034 0117 0700 0201 0012

//iOS平台Objective-C编译后的可执行文件
cafe babe 0000 0005 0000 000c 0000 0009

其中第5、6个字节代表这个class文件的minor version number,这里全为0,第7、8个字节代表major version number的值,52,代表我的版本是1.8。而前4个字节从最开始一直就是「CAFE BABE」,这个词本来是 James Gosling对他经常去的一个咖啡馆,里的一个咖啡师的昵称,后来阴差阳错的一致被沿用至今。

6. Mach-o文件中也有0xcafebabe

Mach-o是一种在某些平台上(现在主要是Mac OS X和iOS)的可执行文件类型,在上一节中的代码中看到Objective-C编译后的文件中也出现了0xcafebabe这个词,这个词的历史其实可以追回到NeXT时期。

哈哈,对,就是我的那个NeXT

在Unix/Linux中使用/etc/magic中定义的值来判定读取到的文件类型(现在的Mac OS X中可以在/usr/share/file/magic目录下找到),就是说在程序读取文件时,会根据读到的前几个字节进行文件类型的判断(而不是扩展名),在Unix/Linux的系统中有个命令file可以判断一个二进制文件的类型。

NeXTSTEP是Mac OS X的前身,是一个基于BSD Unix的系统,自然也遵循了这个方法,当年NeXT获取了Objective-C的使用权,同时开发了一整套的开发套件,那么就需要找一个值来指代其文件类型,于是就使用了0xcafebabe,通常认为是一位叫Mike DeMoney的哥们做的这个决定。

7. 怎么Mach-o和Java还有这层关系

差不多与此同时,Sun公司也在半秘密地开发著名的Oak项目,这个项目也选择了0xcafebabe来作为魔术数。有一个有趣的故事是——这个有趣的故事好像是来源于Java项目的第一位工程师Patrick Naughton——cafe babe代表的是一个Sun公司的漂亮的市场经理(就是开篇的那张照片,Kim Polese),她当时在一个C++编译器的项目中工作,那个项目叫做cafe(C++, A Front End),于是她就被叫做cafe baby——在都是程序员的环境里大约就是会这样——后来她调到了Oak项目。话说后来Kim在硅谷也是风生水起,现在是某公司CEO。下面来感受一下当年的Kim。

高中时期
1996年创业时

当然,一个好八卦必须要有很多版本。另一个说法是,NeXT的很多人后来不想跟乔帮主混了,去了FirstPerson公司,这些人在那里一手创立了Java——呃,当然Java创始人公认是James Gosling——但这些人确实对Java产生了很大的影响。不得不承认,Java的设计理念和Objective-C有太多的相似之处(Interface属于完全的抄……呃……借鉴),而且很多地方Java和Objective-C的设计理念相同,只是由于抛掉了c语言的枷锁,得以走得更远。总之,他们来了,然后这群人里有一个人(Mike DeMoney)使用了和Mach-o相同的魔术数。

然而,八卦止于无聊的人(逃……),公认的Java创始人James Gosling出来说:很抱歉打扰大家谈论八卦的雅兴,不过小可我才是那个选择了在class文件中使用0xcafebabe的人,这跟上边那几位一点关系都没有。

As far as I know, I'm the guilty party on this one. I was totally unaware of the NeXT connection. The small number of interesting HEX words is probably the source of the match. As for the derivation of the use of CAFEBABE in Java, it's somewhat circuitous:

James大神

当然,由这个magic number背后也可以看出Objective-C和Java一脉相承的关系。

8. 更多的魔术数

话说NeXT的这群工程师都好调皮。

0xbaaaaaad iOS错误日志代码,表示一个日志是全局日志快照,very bad
0xbad22222 iOS错误日志代码
0x8badf00d (Ate Bad Food) iOS错误日志代码,表示代码吃坏了肚子,被杀掉了
0xdeadfa11 (Dead Fall) iOS错误日志代码,用户强制退出
0xDEAD10CC (Dead Lock) iOS错误日志代码,这个很清晰,哎呀,死锁了
0xBAADF00D (Bad Food) Windows中的错误代码
0xCAFED00D (Cafe dude) Java中使用
0xCAFEBABE (Cafe babe) Java和Mach-o文件类型
0x0D15EA5E (Disease) 
0x1BADB002 (1 bad boot) 启动失败
0xDEADDEAD Windows的蓝屏???

9. Integer类型中的-128和127

很多书、文章或者各种编程指南中都建议在Java中不要使用基本数据类型(intlongcharbyte等),Java也提供了自动装箱来尽可能的保证在JVM中奔跑的数据尽可能都是「对象」。然而,有时候这种习惯也会带来一些副作用。

for (int i = 0; i < 10; i++) {
    System.out.println((Integer) i);
}
//正常情况下,此代码会循环输出0到9等十个数字

但是,我们可以通过一些小手段,使这个代码输出其他的数字。利用到Java的两个特性,反射和Integer类的缓存。

大家都知道,当你在Java中获取-128到127的Integer类型时,其实是不会新建对象的,很多面试题都喜欢考这个特性,其实没什么高深的,只是想给人挖陷阱而已。Integer类有一个内部类叫IntegerCache,在这个类中创建了256个数字的缓存,在JDK的源码中是这样写的:

public static Integer valueOf(int i) {
    //这里的low和high就是-128和127,也就是一个字节的长度
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

针对上边这块代码,我只要把这个静态内部类IntegerCache中的cache数组的内容改掉,别人再调用valueOf()就拿不到正确的数据了,代码如下:

Class<?> clazz = Class.forName("java.lang.Integer$IntegerCache");
Field field = clazz.getDeclaredField("cache");
field.setAccessible(true);
Integer[] cache = (Integer[]) field.get(clazz);

// 写入错误的值
for (int i = 0; i < cache.length; i++) {
  cache[i] = new Integer(128 - i);
}

10. ArrayList的默认大小

使用Java集合时,有时候因为不希望碰到null的情况,所以一些List会像这样赋值

List<String> list = new ArrayList<>();

这条语句的意思是建立一个默认为空的ArrayList,但是Java的ArrayList的空间是自增的,且ArrayList底层是用数组实现的,所以就会有一个默认大小,作为第一次需要自增时初始化的大小,这个数字在ArrayList而言是10。所以如果你使用上边的语句建立List,那么在第一次插入元素时,它就会生成一个空间为10的数组。如果你这个List最多只会插入4个元素,那么就浪费了空间。所以如果要建立的这个List大小大约已知的话,在性能需求较紧张时,最好把你预测的空间填进去。

当然,不要过早去优化,但一个好习惯总是好的。

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 姓名:周君会 学号:17011210526 转载自: http://www.jianshu.com/p/...
    lotus儿阅读 1,934评论 1 9
  • 少用挑剔眼光看待孩子成长,相比较,国外家长则习惯用欣赏的眼光看待自己、孩子和世界。 有位教育专家曾经谈到这样一个奇...
    书宇YY阅读 297评论 0 0
  • 我热爱的少女 爱幻想的少女 幻想把铁轨还给海子 幻想把斧头还给顾城 为这诗与远方 我痛饮般若汤 酒醉带出铁轨和斧头...
    鸿清风阅读 231评论 0 0
  • 我们常常把“来日方长”挂在嘴边,以为日子还很长。 很遗憾,时光总在一句没有定数的承诺中溜走。 而我们,也这样错过了...
    YanwayLin阅读 713评论 0 1