JDK源码阅读(一)

前言

       看JDK的源码是非常有效的学习方法,对深入学习和理解起着关键作用,要保持阅读源码的习惯,之后我们会经常对一些重要的源码进行整理,之前已经看了集合类,今天从基本类型开始,关键是多看,每次看都有新发现,这里主要列出别人整理过的深层次理解,方便自己经常结合源码看。

       我们运行的demo的时候,肯定想看自己的结果,所以首先的基础内容就是java的格式化输出,包括保留几位小数啦、进制之间的转换,不同类型之间的转化啦。这里就给几个整理的非常好的总结博客:String.format的用法Formatter的用法Java基础类型和字符串之间的转化。而且我们看源码,不是看了就懂的,作为准备得有一定的基础知识的补充才行,补充之后在进行一定拓展我这里就按照这种方式,整理出一个系统完全的学习笔记。每个类的测试demo,我放在了Github上,传送门:wustzoujing/Java_Learning.

Object类

       Java中所有的类都有一个共同的祖先,它就是Object类,我们首先就学习它。他有12个成员方法。按照用途如下:构造函数 ;hashCode和equals函数用来判断对象是否相同;wait(), wait(long), wait(long,int), notify(), notifyAll() ;toString()和getClass; clone() 用途是用来另存一个当前存在的对象。;finalize() 用于在垃圾回收;

                                                 

这里是整理的博客,和应该关注的重点!!!

全方法注释解析。源码上英文注释,我们试着翻译一下。注意native方法。

equal和==、hashcode String和hashmap等重写了这两个方法,必须一起重写,理由和怎么写?看博客。

clone。浅拷贝和深拷贝 这是C++里面重要的概念,因为C++中要delete,自己回收,而java不用。

wait notify notifyall实例 理解这三个函数的作用。

Integer

       我们这里拿Integer类来学习Java中的基本数据类型,在JDK源码中有大量的位运算和空间换时间的设计来优化速度。下面是整理的重点知识。

Java中参数传递。这个是在运行自己写的交换函数的时候发现的问题。Java中其实都是值传递,都是栈空间中的,要么是基本类型,要么是引用类型,就是一个地址。

位运算总结。位运算有判断奇偶、交换两数、变换符号及求绝对值等上的小技巧。源码在项目上。

Java中的数据类型。基本分类和引用类型及详细介绍。

Integer类源码解读(一)

Integer类源码解读(二)

String\StringBuffer\StringBuiler

       String被final修饰的,不可变的,重写了hashcode和equal方法,compareTo方法。首先来看一下字符串常见的几个问题:

(1)String s = new String(“xyz”);创建了几个String 对象?
       两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓冲区中的那一个,类似与缓存Byte数值的-128~127数值。New String每写一遍,就创建一个新的对象,那个常量”xyz”对象的内容来创建出一个新String对象。如果以前就用过’xyz’,这句代表就不会创建”xyz”自己了,直接从缓冲区拿。

       所以,凡是通过构造器创建的对象都会进行内存分配,所以他就不会指向缓存池中已有的对象而指向新的对象,这样就会造成缓存池中存在多个值相同的字符串对象,浪费资源。所以一般要直接为字符串指定值即可。

       这里需要介绍一下缓存池:为了节省内存,提高资源的复用,jvm引入了常量池这个概念,它属于方法区的一部分,作用之一就是存放编译期间生产的各种字面量和符号引用。方法区的垃圾回收行为是比较少出现的,该区中的对象基本不会被回收,可以理解成是永久存在的。

(2)String s=”a”+”b”+”c”+”d”;创建了几个String对象?
       一个,因为Javac在做编译时已经对这些字符串进行了合并操作,预先做了优化处理。

(3)String name = “ab”; name = name + “c”;两条语句总共创建了多少个字符串对象?
       创建了两个对象,这两个对象都会放到缓存池中,只是name的引用由”ab”改变为”abc”了。我们在这样用的时候,还需要考虑其他问题,如这个程序会造成内在泄漏,因为缓存池中的在缓存池中的字符串是不会被垃圾回收机制回收的,基本都是常驻内存,所以过多使用String类,可能会出现内存溢出。

(4)字符串比较

1
2
3
4
String s1 = "a";
String s2 = s1 + "b";
String s3 = "ab";
System.out.println(s2 == s3);//false

       可以看到s2与s3的引用并不相同。由于s2字符串在编译时并不能进行确定,所以首先进入缓存池中的有s1和s3,随后会创建一个新的s2字符串对象,两者当然不一样了。如果程序的字符串连接表达式中没有使用变量或者调用方法,那么该字符串变量的值就能够在编译期间确定下来,并且将该字符换缓存在缓冲区中,同时让该变量指向该字符串;否则将无法利用缓冲区,因为使用了变量和调用了方法之后的字符串变量的值只能在运行期间才能确定连接式的值,也就无法在编译期间确定字符串变量的值,从而无法将字符串变量增加到缓冲区并加以利用。如果要对s1与s2加上final关键字后,结果就为true了。因为会在编译期进行优化处理。所以如果有字符串拼接之类的操作,建议使用StringBuilder类型或StringBuffer类。而StringBuffer在方法加上了同步关键字,多线程情况下使用。

       还可以参考如下博客:

String 源码浅析

String\StringBuffer\StringBuiler比较

说明

       文中出现的图片,文字描述有些来自互联网,但是出处无法考究,如果侵犯您的相关权益,请联系我,核实后我会马上加上转载说明。谢谢!