JDK源码阅读之路【不断更新】

 

前言

  • 为什么阅读源码?

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

  • 如何阅读

阅读顺序参考: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 String
    implements 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 true

		String 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");	  true
		System.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码构造  Aa
		String 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线程安全。
	@Override
	public int length() {
		return value.length;
	}

	@Override
	public char charAt(int index) {
		if ((index < 0) || (index >= value.length)) {
			throw new StringIndexOutOfBoundsException(index);
		}
		return value[index];
	}

	@Override
	public 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 CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private 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 promotion
                            return 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 the
            RegEx's meta characters ".$|()[{^?*+\\", or
         (2)two-char String and the first char is the backslash and
            the 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 this
            if (off == 0)
                return new String[]{this};

            // Add remaining segment
            if (!limited || list.size() < limit)
                list.add(substring(off, value.length));

            // Construct result
            int 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")); // 是否包含某个key
		System.out.println(map1.containsValue("ccc")); // 是否包含某个value
		
		Set<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
		
		
	}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值