java.lang包的一些学习心得

3月 1st, 2012 3,159 留下评论 阅读评论

寒假很闲,就打算写代码之余看看JDK源码。别觉得JDK源码是什么很难看不懂的代码,都是Java代码而且以逻辑为主算法很少,觉得体验Class、OOP和API的设计远远比掌握某个Class、API的复杂算法有意义(meaningful)也有意思(interesting)的多。

当然因为精力和时间有限,挑选常用和比较重要的包和类去看一下来的实在一些,然后你就会发现java.*下面其实就真没有多少包和类了,10来个包几百个类吧,这些类中有一半是没有或者基本可忽略代码的Annotation、Interface、Exception、Error等,更别看随便一个什么类的代码就上千行,其中3/4是注释有木有!好了,所以这也算是给自己的一个动力吧。果断地拿java.lang开咬…

看了不少jdk代码下来几个感受:

  1. Java最强调的代码规范到哪里去了…代码的括号、缩进真是乱成一团啊,由于是源码在Ecilpse中不能修改不能被Ctrl-Shift-F,这是很不爽的
  2. 注释长的很,看英文的注释也提升不了多少英文水平,还是看中文的效率高多了,觉得有不太理解地再去看英文注释(毕竟翻译有差)
  3. 大部分关键核心的代码都被native了,所以读源码更没难度了
  4. 大部分的代码其实真的很普通,既没有很高深也没有很美观
  5. 有些个别的代码写的真是XXX…(貌似程序猿都有强烈重构他人不完美的代码的冲动…)

然后介绍几个java.lang中一些自我感觉有趣的地方和值得学习的地方。

装箱机制中的int和Integer

先做道题,判断下面3个布尔值分别是什么:

Integer a1 = new Integer(1);
Integer b1 = new Integer(1);
System.out.println(a1 == b1);
 
Integer a2 = 1;
Integer b2 = 1;
System.out.println(a2 == b2);
 
Integer a3 = 200;
Integer b3 = 200;
System.out.println(a3 == b3);

答案是false、true、false。第一次见也许会感觉比较奇怪,这里涉及到int的装箱机制变成Integer,LZ第一次在某个视频中看到这个奇怪的问题然后听主讲人说在-128到127这个范围内装箱机制的结果就是这样的,也没讲具体啥原因。int装箱成Integer是个Java普通对象了,得new出来才行,为什么-128到127之间的装箱产生的Integer地址是一样的呢?

看Integer.java源码即知原因,其实java.lang.xxx(xxx for {Byte, Short, Integer, Long})都一样。Integer中有一个静态内部类IntegerCache,缓存了从-128到127这256个最常用数的Integer对象,Integer类被加载的时候这些缓存对象就初始化好了。然后只有唯一通过Integer.valueOf(int i)这个API用到了这个IntegerCache,当i在-128到127范围内时,便返回相应的缓存对象,否则就立即new一个。LZ的推理就是,int的装箱调用了Integer.valueOf(int i)这个方法(通过Eclipse的单步跟踪debug可以证明这一点),然后使用了IntegerCache的缓存,就是这样。事实证明,可以利用反射去查看IntegerCache中的为1的那个Integer的对象的地址,和题中的a2和b2的地址都是一样的。

Integer中的位算法

Integer类中有许多涉及到位操作的API,如bitCount(int i), numberOfLeadingZeros(int i), lowestOneBit(int i)等,它们的源代码都很难理解显然用到了位操作的某些算法,很好的是注释中提到了这一点:“bit twiddling”方法的实现基于 Henry S. Warren, Jr.撰写的 Hacker’s Delight(Addison Wesley, 2002)中的一些有关材料。然后Google一下你会发现这是一本好书啊,值得一读(虽然LZ还木有看过)。

String类的字符串匹配算法

看到String类的indexOf方法时可紧张了,想想可能是碰到的第一个实现了经典算法的源码API。怕看不懂源码先老老实实去自学字符串匹配的kmp算法,Matrix67的博客上的关于kmp的解说的确浅显易懂(原来这个算法又叫看毛片算法,哈哈哈)。研究半天终于懂了之后,兴奋地去再去读String.indexOf源码了,然后失望地发现其居然只是简单地用了复杂度为M*N的暴力匹配…这不是坑爹么!

某些非public的类

在javadoc中是看不到非public的类的,而某些这些非public的类还是比较重要的。比如java.lang.StringCoding,这是java根据不同的编码解析和生成字节流字符串的类,虽然不太看的懂但很重要的说总要让人知道存在吧,连注释都很简略。

大家都知道StringBuilder和StringBuffer功能一样但后者是线程安全的而前者则不是,而原理是所有的方法实现都在java.lang.AbstractStringBuilder中,二者都继承于这个类,然后对每个API再封装一层,区别就是StringBuilder直接调用super的API,StringBuffer的API则用了synchronized关键字再调用super的API。但是因为同样道理文档木有收录AbstractStringBuilder类,所以在文档中显示前2个类都直接继承自Object,好假…

Categories: Java 标签:
  1. 4月 24th, 2012 17:57

    Java最强调的代码规范到哪里去了…代码的括号、缩进真是乱成一团啊,由于是源码在Ecilpse中不能修改不能被Ctrl-Shift-F,这是很不爽的

    怎么会呢,莫非你是看的反编译的?

  2. 还是要努力啊

  3. zhangyoufu | #4
    3月 1st, 2012 21:42

    我是最近google 0x92492493遇到Hacker’s Delight这本书的。。存档作为工具书查阅。。

    • 不过还是得熟读一下知道有哪些算法值得到时候去借鉴