前言

  • 为什么阅读源码?

学习设计模式和思维。总之,知道自己有多菜,在不断学习的过程中发现自身不足并弥补,才能进步。

  • 如何阅读

阅读顺序参考:https://blog.csdn.net/qq_21033663/article/details/79571506

结合aip:https://docs.oracle.com/javase/8/docs/api/


1.Object类

类 Object 是类层次结构的根类,每个类都使用 Object 作为超类,所有对象、包括数组都实现了Object类的方法。简而言之,所有类都有Object类中的方法。

//构造函数
Object() 
    private static native void registerNatives();static {registerNatives();}

Object类中一开始的4行代码,关于registerNatives():

  • native:本地方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。native方法在JVM中运行时数据区也和其它方法不一样,它有专门的本地方法栈。native方法主要用于加载文件和动态链接库。由此可知,本地方法的实现是由其他语言编写并保存在动态连接库中,因而在java类中不需要方法实现。
  • 静态代码块:用于初始化类,为类的属性初始化。每个静态代码块只会执行一次。
  • 代码功能:先定义了registerNatives()方法,然后当该类被加载的时候,调用该方法完成对该类中本地方法的注册。

当包含registerNatives()方法的类被加载的时候,注册的方法就是该类所包含的除了registerNatives()方法以外的所有本地方法

一个Java程序要想调用一个本地方法,需要执行两个步骤:第一,通过System.loadLibrary()将包含本地方法实现的动态文件加载进内存;第二,当Java程序需要调用本地方法时,虚拟机在加载的动态文件中定位并链接该本地方法,从而得以执行本地方法。registerNatives()方法的作用就是取代第二步,让程序主动将本地方法链接到调用方,当Java程序需要调用本地方法时就可以直接调用,而不需要虚拟机再去定位并链接。

  • 使用registerNatives()方法的三点好处:
  1. 通过registerNatives方法在类被加载的时候就主动将本地方法链接到调用方,比当方法被使用时再由虚拟机来定位和链接更方便有效;
  2. 如果本地方法在程序运行中更新了,可以通过调用registerNative方法进行更新;
  3. Java程序需要调用一个本地应用提供的方法时,因为虚拟机只会检索本地动态库,因而虚拟机是无法定位到本地方法实现的,这个时候就只能使用registerNatives()方法进行主动链接。
  4. 通过registerNatives()方法,在定义本地方法实现的时候,可以不遵守JNI命名规范。JNI命名规范要求本地方法名由“包名”+“方法名”构成。

Object类中的native方法: 

//Returns the runtime class of this Object.
public final native Class<?> getClass();//Returns a hash code value for the object.
public native int hashCode();//Creates and returns a copy of this object.
protected native Object clone() throws CloneNotSupportedException;//Wakes up a single thread that is waiting on this object's monitor.
public final native void notify();//Wakes up all threads that are waiting on this object's monitor.
public final native void notifyAll();//Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
public final native void wait(long timeout) throws InterruptedException;

其他方法:

public boolean equals(Object obj) {return (this == obj);}
  • equals()在实际开发中一般都要重写,因为obj1 == obj2只判断了两个对象的地址值,如果该对象的成员变量中包含了引用类型的变量,则需要进一步判断。
public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());}

toString() demo:

  • toString()返回全路径名称+哈希值;一般也需要重写;
public final void wait(long timeout, int nanos) throws InterruptedException {if (timeout < 0) {throw new IllegalArgumentException("timeout value is negative");}if (nanos < 0 || nanos > 999999) {throw new IllegalArgumentException("nanosecond timeout value out of range");}if (nanos > 0) {timeout++;}wait(timeout);}public final void wait() throws InterruptedException {wait(0);}
  • Object类中wait有三个重载方法,同时必须捕获非运行时异常InterruptedException。
  1. wait() :需要notify ,notifyAll才能唤醒;
  2. wait(long timeout) :经过timeout 超时后,若未被唤醒,则自动唤醒;
  3. wait(timeout, nanos) :经过timeout 超时后,若未被唤醒,则自动唤醒。相对wait(long timeout) 更加精确时间。
  • 方法都必须在synchronized 同步关键字所限定的作用域中调用,否则会报错java.lang.IllegalMonitorStateException ,意思是因为没有同步,所以线程对对象锁的状态是不确定的,不能调用这些方法。

protected void finalize() throws Throwable { }
  • finalize()方法是Java中Object类的一个空实现方法。 作用:GC准备回收该对象的内存时,会先调用finalize()。关键字protected是防止在该类之外定义的代码访问finalize()标识符。

2.String类

String类用final关键字修饰,类不能被继承,不能被覆盖,以及final类在执行速度方面比一般类快。

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/*** 成员属性  ***/// 底层利用字符数组实现,final修饰private final char value[];// String对象的hashcode缓存,考虑String不可变特性,hash码频繁使用,因此直接记录下该值也是一种优化。默认值为 0.private int hash;// serialVersionUID 支持序列化和反序列化支持private static final long serialVersionUID = -6849794470754667710L;private static final ObjectStreamField[] serialPersistentFields =new ObjectStreamField[0];// native方法 intern()public native String intern();
}

String类实现三个接口:

  1. Serializable:可序列化;
  2. Comparable:类的实例化对象之间可比较;
  3. CharSequence:此接口对多种不同的对char访问的统一接口;String定义的字符串只能读,CharSequence定义的字符串是可读可写的;

String类的intern()方法:

在用new时,String都是在堆上创建字符串对象。当调用 intern() 方法时,编译器会将字符串添加到常量池中(stringTable维护),并返回指向该常量的引用。

String构造函数:

public static void main(String[] args) throws UnsupportedEncodingException {/**String类构造函数demo */// 无参构造String s1 = new String();System.out.println(s1.hashCode()=="".hashCode());  //hash值默认为0; 0==0 trueString s = "123";String s2 = new String(s);System.out.println(s2 == s);   // false   == 比较的是对象内存地址值,s和s2是堆中的不同对象,所有false;
//      System.out.println(s2 == "123");  false 地址值不同,hash值相同
//      System.out.println(s == "123");   trueSystem.out.println(s2.hashCode() == s.hashCode());   // true; 比较的是String中的成员对象hash的值 String s3 = "123";System.out.println(s == s3); // true//用字符数组构造String s4 = new String(new char[] {'a', 'b'});String s5 = new String(new char[] {'a', 'b','c'}, 1, 2); //s5 = bc;String s6 = new String(new int[] {65,97,100},0,2); // int数组 用ASCII码构造  AaString s7 = new String(new byte[]{65,2,3}, "GBK"); //指定编码集// StringBuffer、StringBuilder构造String s8 = new String(new StringBuffer());String s9 = new String(new StringBuilder());}

贴几个源码:

    public String() {this.value = "".value;}public String(String original) {this.value = original.value;this.hash = original.hash;}public String(char value[]) {this.value = Arrays.copyOf(value, value.length);}public String(StringBuffer buffer) {synchronized(buffer) {this.value = Arrays.copyOf(buffer.getValue(), buffer.length());}}public String(StringBuilder builder) {this.value = Arrays.copyOf(builder.getValue(), builder.length());}
  • StringBuffer不是线程安全,要用synchronized关键字;StringBuilder线程安全。
 @Overridepublic int length() {return value.length;}@Overridepublic char charAt(int index) {if ((index < 0) || (index >= value.length)) {throw new StringIndexOutOfBoundsException(index);}return value[index];}@Overridepublic CharSequence subSequence(int start, int end) {return this.substring(start, end);}
  • 实现CharSequence接口的3个方法;
public int compareTo(String anotherString) {int len1 = value.length;int len2 = anotherString.value.length;int lim = Math.min(len1, len2);char v1[] = value;char v2[] = anotherString.value;int k = 0;while (k < lim) {char c1 = v1[k];char c2 = v2[k];if (c1 != c2) {return c1 - c2;}k++;}return len1 - len2;}
  • 实现 Comparable接口的compareTo():比较两个字符串的字典顺序。用字符串1跟字符串2作比较,如果字符串1的字典顺序在字符串2前面,则返回一个负数。若在后面,则返回一个正数。若两个字符串的字典顺序相同,则返回0。
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {if (srcBegin < 0) {throw new StringIndexOutOfBoundsException(srcBegin);}if (srcEnd > value.length) {throw new StringIndexOutOfBoundsException(srcEnd);}if (srcBegin > srcEnd) {throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);}System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);}
  • 将当前字符串从start到end-1位置上的字符复制到字符数组c中,并从c的offset处开始存放。

Arrays.copyOf()和System.arrayCopy()的区别:

Arrays.copyOf()不仅仅只是拷贝数组中的元素,在拷贝元素时,会创建一个新的数组对象。而System.arrayCopy只拷贝已经存在数组元素。

public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}// 忽略大小写
public boolean equalsIgnoreCase(String anotherString) {return (this == anotherString) ? true: (anotherString != null)&& (anotherString.value.length == value.length)&& regionMatches(true, 0, anotherString, 0, value.length);}
  • instanceof:Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
  • 首先,判断引用值是否相等,相等即true;否则,判断类型是否匹配,类型相同,长度相等,逐个比较字符是否一样,完全符合,则返回ture。(如果两个对象判断相等,判断类型)
public static final Comparator<String> CASE_INSENSITIVE_ORDER= new CaseInsensitiveComparator();private static class CaseInsensitiveComparatorimplements Comparator<String>, java.io.Serializable {// use serialVersionUID from JDK 1.2.2 for interoperabilityprivate static final long serialVersionUID = 8575799808933029326L;public int compare(String s1, String s2) {int n1 = s1.length();int n2 = s2.length();int min = Math.min(n1, n2);for (int i = 0; i < min; i++) {char c1 = s1.charAt(i);char c2 = s2.charAt(i);if (c1 != c2) {c1 = Character.toUpperCase(c1);c2 = Character.toUpperCase(c2);if (c1 != c2) {c1 = Character.toLowerCase(c1);c2 = Character.toLowerCase(c2);if (c1 != c2) {// No overflow because of numeric promotionreturn c1 - c2;}}}}return n1 - n2;}/** Replaces the de-serialized object. */private Object readResolve() { return CASE_INSENSITIVE_ORDER; }}
  • CaseInsensitiveComparator静态内部类:compare方法实现String对象的大小写不敏感比较。

  • 存疑:为什么设计成静态内部类?
public boolean startsWith(String prefix, int toffset) {char ta[] = value;int to = toffset;char pa[] = prefix.value;int po = 0;int pc = prefix.value.length;// Note: toffset might be near -1>>>1.if ((toffset < 0) || (toffset > value.length - pc)) {return false;}while (--pc >= 0) {if (ta[to++] != pa[po++]) {return false;}}return true;}public boolean endsWith(String suffix) {return startsWith(suffix, value.length - suffix.value.length);}
  • 子串截取
public String substring(int beginIndex, int endIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}if (endIndex > value.length) {throw new StringIndexOutOfBoundsException(endIndex);}int subLen = endIndex - beginIndex;if (subLen < 0) {throw new StringIndexOutOfBoundsException(subLen);}return ((beginIndex == 0) && (endIndex == value.length)) ? this: new String(value, beginIndex, subLen);}
  • 字符替换

    • 哪怕多做些循环判断,也要尽量避免new新的对象;
public String replace(char oldChar, char newChar) {if (oldChar != newChar) {int len = value.length;int i = -1;char[] val = value; /* avoid getfield opcode */while (++i < len) {if (val[i] == oldChar) {break;}}if (i < len) {char buf[] = new char[len];for (int j = 0; j < i; j++) {buf[j] = val[j];}while (i < len) {char c = val[i];buf[i] = (c == oldChar) ? newChar : c;i++;}return new String(buf, true);}}return this;}
  • 分割字符
public String[] split(String regex, int limit) {/* fastpath if the regex is a(1)one-char String and this character is not one of theRegEx's meta characters ".$|()[{^?*+\\", or(2)two-char String and the first char is the backslash andthe second is not the ascii digit or ascii letter.*/char ch = 0;if (((regex.value.length == 1 &&".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||(regex.length() == 2 &&regex.charAt(0) == '\\' &&(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&((ch-'a')|('z'-ch)) < 0 &&((ch-'A')|('Z'-ch)) < 0)) &&(ch < Character.MIN_HIGH_SURROGATE ||ch > Character.MAX_LOW_SURROGATE)){int off = 0;int next = 0;boolean limited = limit > 0;ArrayList<String> list = new ArrayList<>();while ((next = indexOf(ch, off)) != -1) {if (!limited || list.size() < limit - 1) {list.add(substring(off, next));off = next + 1;} else {    // last one//assert (list.size() == limit - 1);list.add(substring(off, value.length));off = value.length;break;}}// If no match was found, return thisif (off == 0)return new String[]{this};// Add remaining segmentif (!limited || list.size() < limit)list.add(substring(off, value.length));// Construct resultint resultSize = list.size();if (limit == 0) {while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {resultSize--;}}String[] result = new String[resultSize];return list.subList(0, resultSize).toArray(result);}return Pattern.compile(regex).split(this, limit);}
public String trim() {int len = value.length;int st = 0;char[] val = value;    /* avoid getfield opcode */while ((st < len) && (val[st] <= ' ')) {st++;}while ((st < len) && (val[len - 1] <= ' ')) {len--;}return ((st > 0) || (len < value.length)) ? substring(st, len) : this;}

3.AbstractStringBuilder

这个抽象类是StringBuilder和StringBuffer的直接父类。可以认为AbstractStringBuilder 就是对于可变字符序列的这一概念的描述。

他提供了可变字符序列的一个基本协议约定,也就是基本的功能方法作为一个抽象类, 并且也提供了一部分默认的实现;StringBuffer和StringBuilder都是可变的字符序列,所以他们都实现了AbstractStringBuilder。

类声明:

abstract class AbstractStringBuilder implements Appendable, CharSequence{}

实现了两个接口,其中CharSequence这个字符序列的接口已经很熟悉了:

  • 该接口规定了需要实现该字符序列的长度:length();
  • 可以取得下标为index的的字符:charAt(int index);
  • 可以得到该字符序列的一个子字符序列: subSequence(int start, int end);
  • 规定了该字符序列的String版本(重写了父类Object的toString()):toString();

Appendable接口顾名思义,定义添加的’规则’:

  • append(CharSequence csq) throws IOException:如何添加一个字符序列
  • append(CharSequence csq, int start, int end) throws IOException:如何添加一个字符序列的一部分
  • append(char c) throws IOException:如何添加一个字符

成员变量:

/*** The value is used for character storage.*/char[] value;/*** The count is the number of characters used.*/int count;

构造函数:

 AbstractStringBuilder() {}/*** Creates an AbstractStringBuilder of the specified capacity.*/AbstractStringBuilder(int capacity) {value = new char[capacity];}

方法:


4.StringBuffer

类声明:

成员变量:

构造函数:

方法:


5.StringBuilder

类声明:

成员变量:

构造函数:

方法:


6.HashMap

public static void main(String[] args) {HashMap map1 = new HashMap<String,String>(8,(float) (0.8));HashMap map2 = new HashMap<String,String>();map1.put("1", "aaa");map1.put("3", "ccc");map2.put("a", "jony");map2.put("1", "kiki");map1.put(null, null);System.out.println(map1.size()); //size=3-HashMap允许存放null键值对System.out.println(map1.put("1", "s")); // put方法-如果key已存在,替换,并返回原value;map2.putAll(map1); //putAll方法-将map1中所有mappings复制到map2中,对于map2之前已有key对应的value将被map1对应的value覆盖,其余map2的键值对不受影响;System.out.println(map2.size());System.out.println(map2.get("1"));System.out.println(map1.get("3"));System.out.println(map1.containsKey("2")); // 是否包含某个keySystem.out.println(map1.containsValue("ccc")); // 是否包含某个valueSet<String> set = map1.keySet(); // 返回所有key构成的集合Collection set2 = map1.values(); //返回所有value构成的集合Set<String> set3 = map1.entrySet(); //返回所有Entry构成的集合System.out.println(map1.replace("1", "ee"));System.out.println(map2.remove("a")); //移除指定key值对应的mapping,如果指定key不存在,返回null}

JDK源码阅读之路【不断更新】相关推荐

  1. jdk源码阅读-HashMap

    前置阅读: jdk源码阅读-Map : http://www.cnblogs.com/ccode/p/4645683.html 在前置阅读的文章里,已经提到HashMap是基于Hash表实现的,所以在 ...

  2. Hive源码阅读之路

    Hive源码阅读(1)阅读环境搭建 前言:让学习成为一种习惯 环境准备 Hive源码下载 Hive源码目录 hive三个最重要的组件: 其他组件 hive辅助组件 编译源码 配置Hive本地调试 配置 ...

  3. jdk javac运行不了_Intellij IDEA搭建jdk源码阅读环境

    一.找到源码位置 直接找到jdk安装的目录,会看到src.zip的压缩包,这里面就是jdk的源码,例如下图: 在这里解压. 第一次尝试建议使用9或更早版本jdk的源码,否则易造成卡死. 二.Intel ...

  4. 走过的路-java源码阅读之路

    源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 一.人生三种境界: 1.昨夜西风凋碧树,独上高楼望尽天涯路.           2.衣带渐宽终不悔,为伊消得人憔悴.           ...

  5. Mac搭建JDK源码阅读环境

    点赞再看,养成习惯,微信公众号搜索[虚竹讲程序经],获取更多技术干货! 想要读懂JDK源码,需要在自己电脑上搭建JDK的源码阅读环境,正所谓,工欲善其事,必先利其器.下面演示如何在Mac上结合Idea ...

  6. jdk源码(jdk源码阅读顺序)

    如何在myEclipse中查看JDK源码 myeclipse中查看jdk类库的源码步骤如下: 1.点 "window"-> "Preferences" - ...

  7. JDK源码阅读环境搭建

    内容来源 B站Up主: CodeSheep 视频: https://www.bilibili.com/video/BV1V7411U78L 感谢大佬分享学习心得 Thanks♪(・ω・)ノ~~~ 1. ...

  8. JDK源码阅读-搭建阅读环境

    1.找到源码位置 其实我们安装jdk的时候源码就已经存在,只要找到jdk的安装位置,就能找到源码,如果不知道jdk具体安装位置的话,可以在idea中查看. 打开目录,找到路径下的src.zip,这就是 ...

  9. JDK源码阅读 String

      1.String是如何做到不可变?为什么要将它设计为不可变类?     答:首先String类是被final修饰,不能被继承:它把数据存放在一个数组value中,value同样被final修饰:所 ...

最新文章

  1. 前端中的this,指的是什么?
  2. python和R对dataframe的拼接、采样、链式操作:dplyr、tidyr、concat、rbind、cbind、sample、sample_n、set.seed、mutate、filter
  3. Android开发:关于WebView
  4. kotlin调用类中的方法_一种轻松的方法来测试Kotlin中令人沮丧的静态方法调用
  5. Jmeter接口测试使用beanshell断言json返回
  6. 康轩职教计算机应用基础课件,《Excel中IF函数的应用-机器人任务》计算机应用基础职教课件.ppt...
  7. 3.空域图像处理的洪荒之力
  8. Eclipse启动提示“subversive connector discovery”
  9. 多个安卓设备投屏到电脑_手机投屏软件哪个好,如何将手机屏幕投屏到电脑?...
  10. java面试英语自我介绍_程序员面试英文自我介绍
  11. 校园导航系统课程设计,#校园管理系统
  12. 我们来了!多云架构时代,欢迎加入中国开源网络新势力
  13. Spring的bean定义 2 : 通用bean定义逻辑 -- AbstractBeanDefinition
  14. 传图取字:微信小程序自动把图片上的文字提取出来
  15. mysqladmin命令简介
  16. js实现粘贴板js插件clipboard.js实现一键复制粘贴功能
  17. 历时7天,四名学生将《水浒传》搬到线上!
  18. 获取文件名下载并兼容IE(文件流)
  19. 那位把每天当做试用期的女孩,升职为总裁助理了
  20. 乐视android版本怎么升级,乐视手机EUI系统升级教程 乐视手机EUI系统怎么升级

热门文章

  1. mysql使用注意事项
  2. 如何精准引流?教你适合各个行业精准引流的方法
  3. unable to dequeue a cell with identifier xxx - must register a nib or a class fo
  4. linux——管道详解
  5. SCOUT 薄膜分析软件
  6. 吐槽微软,远离微软!
  7. 关于神经网络中梯度概念的浅显易懂解释
  8. C++学习(一一七)pdb文件
  9. 《Effective C++》-第一章-让自己习惯C++
  10. 《解忧杂货店》阅读后感