Java 历史及特性

总结自:深入理解Java虚拟机:JVM高级特性与最佳实践 第2版

Java 历史

年份 纪事
1991年4月 James Gosling 的 Green Project 开始执行,该“绿色项目”的结果是 Oak(Java 前身)。
1995年5月23日 Oak 改名为 Java 并在 SunWorld 发布 Java 1.0 提出 “Write Once, Run Anywhere(一次编写到处执行) ”的口号
1996年1月 Sun Classic VM 发布
1996年4月 10个主要操作系统供应商嵌入 Java 技术,大约 8.3 万网站使用了 Java, 首次举行 JavaOne 这个后来的 Java 技术大会
1997年2月19日 JDK1.1发布,添加了新技术和Java语法
1997年2月19日 ~ 1999年4月8日 JDK1.1.0 ~ JDK 1.1.8发布: 1.1.4-Sparkler, 1.1.5-Pumpkin, 1.1.6-Abigai, 1.1.7-Brutus, 1.1.8-Chelsea
1998年12月4日 里程碑式版本 JDK 1.2-Playground 发布,分为三个版本:J2MEJ2SEJ2EE
1999年3月 JDK1.2.1
1999年7月 JDK 1.2.2
1999年4月27日 HotPot VM 发布,JDK 1.2 可选 VM, JDK 1.3 后默认的 VM 。
2000年5月8日 JDK 1.3-Kstrel, 对数学运算作出了改进,JNDI 作为平台服务,基于 CORBA IIOP 实现 RMI 通讯协议, Java 2D API,Timer API改进以及添加了 JavaSound 库
2001年5月17日 JDK-1.3.1-Ladybird
2002年2月13日 JDK-1.4-Merlin 发布,这是第一个走向成熟的版本。
2002年9月16日 JDK-1.4.1-Grasshopper
2003年6月26日 JDK-1.4.2-Mantis
2004年9月30日 JDK-1.5-Tiger 语法易用性上的改进,以及改进内存模型,提供了 java.util.concurrent 并发包。最后一个支持 Windows 9.x 平台的 Java。
2006年12月11日 JDK-1.6-Mustang 结束 J2SE、J2EE、J2ME 的命名, 启用 Java SE 6、 Java EE 6、Java ME 6 命名方式。
2006年11月13日 OpenJDK 初现。
2009年2月19日 JDK-1.7-Dolphin 第一个JDK 1.7规划的里程碑版本发布。于 2010年9月9日 所有的JDK 1.7 里程碑才完成。没有按计划完成
2012年10月16日 在 JDK 1.6发布后,Sun 公司,由于代码复杂性、JDK 开源、开发 JavaFX、经济危机、Sun 公司收购案等原因,Sun 公司被拖累。无法再进行两年一主版本。 JDK 1.6 一共发布了 37个更新

Java 特性

JDK 1.0

  1. JVM
  2. Applet (网页小程序)
  3. AWT

JDK 1.1

  1. *.jar 文件格式
  2. JDBC
  3. JavaBeans
  4. RMI
  5. 内部类 (Inner Class)
  6. 反射(Reflection)

JDK 1.2

  1. EJB
  2. Java Plug-in
  3. Java IDL
  4. Swing
  5. JIT
  6. strictfp 关键字
  7. Collections 集合类

JDK 1.3

  1. Timer API
  2. 平台级 JNDI
  3. 基于 CORBA IIOP 实现的 RMI
  4. 改进的 Java 2D
  5. JavaSound

JDK 1.4

  1. 正则表达式
  2. 异常链
  3. NIO
  4. 日志类
  5. XML 解释器
  6. XSLT 转换器

JDK 1.5

  1. 自动装箱
  2. 泛型
  3. 动态注解
  4. 枚举
  5. 可变长参数
  6. 遍历循环(foreach 循环)

JDK 1.6

  1. 启用动态语言支持(Mozilla JavaScript Rhino)
  2. 提供编译API
  3. 微型HTTP服务器 API
  4. 锁与同步改进
  5. 垃圾收集算法改进
  6. 类加载算法改进

JDK 1.7

  1. G1收集器
  2. 非Java语言调用支持(JSR-292)
  3. 升级类加载架构

我给自己写的名言

我们总是无法避免未知。重要的是如何对待未知。(2018/5/2)
事情已经发生现实已不可逆转,所能做的就只不过是让自己未来不再糊涂不再后悔。(2018/9/9)
班级干部是一种用于负责任并用于出气的吸血蚂蚱。(2018/9/16)
优秀的潜质在于对自己所处的环境以及周围变化的了解。(2018/9/17)
活着不是为了谁,也不是为了什么,仅仅是为了解脱自己。(2018/10/18)
历史总是惊人地相似,未来总是频繁地改变。不再重蹈覆辙,取决于你的努力程度!(2018/11/3)
节约时间的唯一方法是专注,计划只能帮助你专注。(2018/11/3)
什么都会什么都不会,什么都会是无能的特征。(2018/11/11)
只要察觉了问题,一切都将解决。(2018/11/30)
拖延意味着任务还没有完成,甚至还没有开始。(2018/12/4)
期限会在最后一天给你亲切的恶意,你有机会改变局面,但又让你感觉到无力。(2018/12/5)
一切事物都会朝着熵增的方向,失去控制?还是全力管制?(2018/12/9)
对事物开始的期望,对事物结束的失望。(2018/12/10)
所有到来的一切都是有原因的,但最终都归结于自身的失败。(2018/12/25)
结束是另外一个开始,永无止境的开始,永无止境的结束。(2018/12/25)
琐碎的事情是一切时间不够的根源,小麻烦滚成大麻烦偷走你的时间。(2018/12/26)
相信客观证据告诉你的话语,而不是一时的不合预期的全盘否定。(2019/7/10)
因为坚信着可能性,所以没有放弃自身的可能性。(2019/8/9)
努力的力量来源于身边重要的人由衷相信的期望。(2019/8/9)
纠结之人莫纠结。无意义的纠结不会给你带来任何有意义的结果。(2019/9/17) 宣誓向正确的方向而努力,痛苦而坚持,疲倦而不敢忘。(2019/10/13)

页码数字计数的秘密

问题描述


一本书的页码从自然数 1 开始顺序编码直到自然数 n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如,第 6 页用数字 6 表示,而不是 06 或 006 等。数字计数问题要求对给定书的总页码 n ,计算出书的全部页码中分别用到多少次数字0,1, 2,…,9。

问题要点


1.页码的数字不含前导的零
2.对每页的数字包含的数字进行计数

问题分析


问题的处理对象其实就只有个位的数字,也就是说我们把数字用 10 求余就可以取得个位的数字,接着除以 10 就可以取下一位的数字。

基于这样的分析我们用 C++ 语言写出了以下代码:

#include <iostream>
typedef unsigned long long ull;
using namespace std;

int n;
//用于统计数字出现次数
ull count[10];

//用于统计一个数字 n 中的数字出现次数
//并添加到 count 数组中
void count_num(int n);

int main()
{
    while (cin >> n) {
        for (int i = 0; i < 10; i++) {
            count[i] = 0;
        }
        for (int i = 1; i <= n; i++) {
            count_num(i);
        }
        for (int i = 0; i < 10; i++)
            cout << i << ":" << count[i] << " ";
        cout << endl;
    }
    return 0;
}

void count_num(int n) {
    int low;
    while (n != 0) { // n 总是大于 0
        low = n % 10;
        count[low]++;
        n /= 10;
    }
}

复杂度如下:

项目 复杂度
n × m O(nm)
input O(n)
output O(n)
合计 O(nm)

但这样做如果我们需要计算 n = 109 的话,O(n2)=1018一台普通的计算机大约需要 2 分钟才算完。我们还有办法吗?问题伊始就说道不需要前导的零,这个是不是暗示呢?不管怎样,让我们试着往这方面思考。

行是知之始,知是行之成。——陶行知

补零会有什么结果呢,或者说为什么要这样做呢?会不会是补零后,我们会有另外的发现呢?带着疑问,我们对数字加了零:

01 02 03 04 05 06 07 08 09 10

0:10 1:2 2~9:1

这样做似乎没什么规律,如果把零去掉,并把 10 去掉

1 2 3 4 5 6 7 8 9

0:0 1~9:1

这样看来好像也没什么规律,如果前面加一个零呢?

0 1 2 3 4 5 6 7 8 9

0~9: 1

这样每个数字都加一就可以了!在细心一点看一看会发现,这都是一位数,如果是两位呢?

00 01 02 03 04 05 06 07 08 09
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
………………………..
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

0~9: 20

这样的话,再由此推到三位数呢?

000 001 002 003 004 005 006 007 008 009
010 011 012 013 014 015 016 017 018 019
…………………………………
100 101 102 103 104 105 106 107 108 109
110 111 112 113 114 115 116 117 118 119
…………………………………
580 581 582 583 584 585 586 587 588 589
590 591 592 593 594 595 596 597 598 599
…………………………………
980 981 982 983 984 985 986 987 988 989
990 991 992 993 994 995 996 997 998 999

0~9:300

如果继续推到四位数,五位数呢?把位数和上面的结果联系起来,我们可以得出这个式子:

出现次数 = 位数 × 10(位数 – 1)

这是巧合吗?实际上,我们可以以递归的形式来解释这个式子

f(1)=1
f(n)=f(n-1) * 10 + 10(n – 1)

这说明两位数是一位数的 10 倍加上十位数上每个数字出现了10次,三位数如此类推。
关于详细的证明过程,这里不累赘了。

我们为什么要推出数字出现次数与所有相关位数的关系呢?我们企图从直观上毫无规律之中找出规律。这些规律必然会带有各种条件,既然我们有了一个所有相关位数都的出现次数是一样的规律,那么我们如何使用这个规律呢?

如果我们把求到了的所有相关位数的数字出现次数减去额外补的零的个数那么我们就得到了准确的每个数字出现的次数。我们在处理问题的时候,可以一步一步地接近我们想得到的。我们按照上面推出所有相关位数的数字出现次数的思路可以得出第 n 位的补零次数为:

f(1) = 1
f(n) = 10 * f(n – 1)

接下来便是如何根据特定的自然数 n 来计算 0~9 各个数字出现的次数。我们来考察一个随意的数字 156 :

000 001 002 003 004 005 006 007 008 009
010 011 012 013 014 015 016 017 018 019
…………………………………
100 101 102 103 104 105 106 107 108 109
110 111 112 113 114 115 116 117 118 119
…………………………………
150 151 152 153 154 155 156

我们不能直接通过位数来得到正确的答案,但发现 156 大于 100,意味着我们可以当作两位数 (00~99) 来计算一遍,结果为 0~9:20 ,那么我们就只剩下:

000 001 002 003 004 005 006 007 008 009
010 011 012 013 014 015 016 017 018 019
…………………………………
100 101 102 103 104 105 106 107 108 109
110 111 112 113 114 115 116 117 118 119
…………………………………
150 151 152 153 154 155 156

可以知道,我们少算 100 个零。另外,我们可以知道总共多出的零的个数为 111 (100 + 10 + 1) 个。接下来就需要计算 100~156 的部分,接下来会表示得详细一点。

100 101 102 103 104 105 106 107 108 109
110 121 112 113 114 115 116 117 118 119
120 121 122 123 124 125 126 127 128 129
130 131 132 133 134 135 136 137 138 139
140 141 142 143 144 145 146 147 148 149
150 151 152 153 154 155 156

我们稍微观察一下便可以发现如果去了最高位,那么就会得到 5 个一位的情况。
(待续)

文章约定

0b0001内容
0b0010格式
0b0011注意
0b0100著作

0b0001 内容

每个分类都会有相应的 “目录” 通过目录你可以看到你感兴趣的内容。每一篇文章都会尽可能地遵循 top-down 思路。

top-down:先讲述 Why 再讲述 How。

0b0010 格式

留意本篇文章的格式。

0b0011 注意

本人无意侵犯你的权利,如果在某些情形下没有注明作者请联系我。

0b0100 著作

在一般情况下,我没有在文章顶头以引用形式显示作者信息时即认为
是本人著作。引用通常不是作者著作。

2018-03-20